mirror of
git://projects.qi-hardware.com/nn-usb-fpga.git
synced 2025-01-10 08:30:17 +02:00
2874 lines
194 KiB
Plaintext
2874 lines
194 KiB
Plaintext
|
\chapter{PLATAFORMA DE DESARROLLO ECBOT}
|
|||
|
|
|||
|
|
|||
|
\section{Introducci<63>n}
|
|||
|
En esta secci<63>n se realizar<61> una explicaci<63>n detallada del proceso de adaptaci<63>n de Linux a la familia de plataformas ECB\_AT91, este proceso es aplicable a otros dispositivos que trabajen con procesadores soportados por la distribuci<63>n de Linux. Adicionalmente, se explicar<61> de forma detallada el funcionamiento de este sistema operativo, el proceso de arranque y su puesta en marcha, as<61> como las principales distribuciones, aplicaciones y librer<65>as disponibles para el desarrollo de aplicaciones. Esta y otra informaci<63>n recolectada durante m<>s de tres a<>os permite que la industria y la academia desarrollen aplicaciones comerciales utilizando herramientas de dise<73>o modernas.
|
|||
|
|
|||
|
\subsection{Contribuciones al desarrollo tecnol<6F>gico en Colombia}
|
|||
|
|
|||
|
Durante la realizaci<63>n de esta investigaci<63>n se llevaron a cabo varias actividades, cuyo objetivo principal es contribuir al desarrollo tecnol<6F>gico en Colombia, como se expuso anteriormente el pa<70>s presenta serias dificultades en este campo y es deber de la comunidad acad<61>mica nacional atacar los problemas locales. Por esta raz<61>n unoa de las matas del presente trabajo fu<66> la creaci<63>n de una plataforma hardware que permita implementar las diferentes modelos bio-inspirados. En la mayor<6F>a de estudios similares no se contempla la creaci<63>n de estas plataformas ya que en los pa<70>ses donde se desarrollan la investigaci<63>n existe una industria electr<74>nica competitiva y que esta al tanto de los desarrollos tecnol<6F>gicos a nivel mundial. Como se mencion<6F> anteriormente este no es el caso de nuestro pais, en la mayor<6F>a de las industrias nacionales y en las facultades relacionadas con la electr<74>nica se trabaja con tecnolog<6F>as de hace 30 a<>os (Familias 74 TTL y 40 CMOS) y se utilizan herramientas de programaci<63>n de bajo nivel como el lenguaje ensamblador.
|
|||
|
|
|||
|
A continuaci<63>n se mestran una lista del trabajo realizado sobre algunas de las recomendaciones dadas por los estudios acerca del desarrollo tecnol<6F>gico en Colombia; vale la pena anotar que no todas est<73>n dentro del alcance de este trabajo, se eligieron en las que se pod<6F>a hacer un aporte significativo.
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
|
|||
|
\item Realizaci<63>n de proyectos de aplicaci<63>n: La primera decisi<73>n que se tom<6F> en cuanto a la naturaleza de esta investigaci<63>n fu<66> la de generar una aplicaci<63>n f<>sica real que validara los modelos propuestos, este trabajo no se limitar<61> a realizar simulaciones, sino que se construir<69> una plataforma que sea tecnol<6F>gicamente ``moderna'' y que est<73> al nivel de las plataformas utilizadas en estudios similares. Para esto se dise<73><65> la primer \textit{Computadora en una sola placa} (SBC \footnote{Single Board Computer}) que utiliza un procesador de 32 Bits y utiliza Linux como sistema operativo. Adicionalmente, se crearon plataformas de desa
|
|||
|
|
|||
|
\item Infraestructura institucional que impulse la actualizaci<63>n tecnol<6F>gica en el sector mediante desarrollo de proyectos de tecnolog<6F>a de punta con una posible transferencia de tecnolog<6F>a: En las condiciones actuales no es posible que la industria electr<74>nica del pa<70>s se modernice por s<> sola, es necesario que las Universidades doten al sistema productivo con profesionales que tengan habilidades especiales, siendo la m<>s importante la capacidad de dise<73>ar y construir dispositivos que puedan ser explotados comercialmente. En la actualidad, nuestros estudiantes se limitan a analizar y a simular la mayor<6F>a de los procesos, lo que es necesario pero no suficiente, el nivel de las implementaciones f<>sicas que realizan en los <20>ltimos semestres de sus carreras es muy baja y un m<>nimo porcentaje llegan a un dise<73>o de circuito Impreso. En la Secci<63>n \ref{academic} mostraremos los cambios introducidos en las asignaturas de la l<>nea de Electr<74>nica Digital y como estos generan las habilidades mencionadas anteriormente.
|
|||
|
|
|||
|
\item El contacto con las empresas no debe ser encargada <20>nicamente a los estudiantes, la Universidad debe desarrollar las competencias que la empresa requiere: Se realiz<69> una investigaci<63>n del estado actual de las empresas involucradas en el proceso de manufactura de dispositivos relacionados con la electr<74>nica digital, se identificaron las empresas proveedoras de servicios con el f<>n de determinar que procesos se pueden realizar en el pa<70>s, as<61> mismo se identificaron algunas de las necesidades del sector productivo. En la secci<63>n \ref{industry} se muestra un ejemplo de creaci<63>n de empresa con soporte de la Universidad, espec<65>ficamente del presente trabajo.
|
|||
|
|
|||
|
\item Interacci<63>n entre Universidades, Conviene que buena parte de los trabajos realizados en doctorado sean de investigaci<63>n aplicada, orientadas a mejorar la productividad del sector empresarial: Es importante el dialogo continuo entre todas las Universidades del pa<70>s y la divulgaci<63>n de sus investigaciones, en muchas ocasiones los escasos recursos econ<6F>micos son utilizados para repetir temas de investigaci<63>n, o sus resultados no son dados a conocer. Adicionalmente, los programas acad<61>micos de programas curriculares equivalentes presentan diferentes enfoques y diferentes niveles de excelencia, lo que impide el conocimiento de los trabajos realizados.
|
|||
|
|
|||
|
\item Innovaci<63>n curricular, actualizaci<63>n continua de profesionales: Durante el <20>ltimo a<>o se introdujeron cambios en los contenidos de las asignaturas del <20>rea de sistemas digitales, estos cambios tienen como objetivo crear una metodolog<6F>a de dise<73>o unificada que pueda ser utilizada en los tres cursos, del mismo modo se realiz<69> una actualizaci<63>n tecnol<6F>gica en cuanto al software y al hardware utilizado en estos cursos, se elimin<69> el uso de tecnolog<6F>as viejas y se abri<72> el paso a tecnolog<6F>as y metodolog<6F>a de dise<73>o que se utilizan en cursos similares en Universidades de paises desarrollados.
|
|||
|
|
|||
|
|
|||
|
\item Necesidad de mejorar las competencias y habilidades generales de los ingenieros, (continuo aprendizaje) habilidad para innovar, investigar, desarrollar nueva tecnolog<6F>a: Se crearon alianzas con diferentes profesiones con el f<>n de crear condiciones de trabajo cercanas a las que se puedan encontrar en la industria, es importante para la situaci<63>n del pa<70>s que nuestros egresados sean cap<61>ces de crear nuevos productos que puedan satisfacer las necesidades de la industria local. Por esta raz<61>n durante este trabajo se di<64> un especial <20>nfasis en el proceso de fabricaci<63>n de dispositivos electr<74>nicos.
|
|||
|
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Contribuciones a Nivel Tecnol<6F>gico y Acad<61>mico}
|
|||
|
|
|||
|
En este cap<61>tulo se realiza la presentaci<63>n de la plataforma Hardware y Software utilizada en el desarrollo de esta investigaci<63>n. Uno de los objetivos de este trabajo, es la creaci<63>n de una plataforma Embebida que permita la apropiaci<63>n de nuevas herramientas y metodolog<6F>as de dise<73>o. El mercado de los sistemas embebidos contin<69>a en aumento y su campo de acci<63>n se ha extendido en casi todas las actividades humanas. Seg<65>n BBC, inc. \footnote{http://www.bccresearch.com/} el mercado para el software embebido puede crecer de \$1.6 billones a \$3.5 billones en 2009, con una tasa de crecimiemto anual (AAGR) del 16\%, mientras la tasa de crecimiento para las tarjetas embebidas es del 10\%. (Favor ver Figura \ref{GESM}).
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/embedded_system_market} \end{center}
|
|||
|
% \includegraphics[scale=.6]{./images/glob-emb-software-rev-regio} \end{center}
|
|||
|
\caption{Mercado Global de Sistemas Embebidos 2003-2009. Fuente: BCC Inc.} \label{GESM}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Esto unido a: el gran nivel de integraci<63>n obtenido por la industria de los semiconductores en los \textit{SOC}, la disponibilidad de herramientas software de desarrollo gratuitas (compiladores, simuladores, librer<65>as, Sistemas Operativos) abre grandes posibilidades comerciales para paises en v<>a de desarrollo ya que no son necesarias grandes inversiones de capital para la implementaci<63>n de estos sistemas.
|
|||
|
|
|||
|
M<EFBFBD>s de un bill<6C>n de dispositivos embebidos fueron vendidos en el 2004, seg<65>n \textit{Venture Development Corporation (VDC)}. De acuerdo con VDC el porcentaje de dispositivos basados en Sistemas Operativos comerciales tiende a disminuir callendo del 43.1\% en 2001 a 37.1\% en 2004, esta tendencia se debe al aumento de complejidad de los dispositivos y a las necesidades de conexi<78>n (tales como Ethernet, bluetooth, WiFi, etc); adem<65>s, la caida de precios del hardware, elimina la necesidad de eficiencia en el manejo de recursos proporcionada por muchos productos comerciales. Otro factor es el deseo de utilizar el mismo Sistema Operativo para varios proyectos.
|
|||
|
|
|||
|
Recientes investigaciones de VDC sugieren que entre el 13 y el 15\% de los desarrolladores utilizan linux como su sistema operativo principal, y se espera que esta cifra aumente al madurar la tecnolog<6F>a y el soporte de los recursos de la comunidad aumenten. La figura \ref{os_trends} muestra una encuenta realizada a 932 desarrolladores de todo el mundo por \textit{linuxdevices} \footnote{http://www.linuxdevices.com}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/embedded_OS_sourcing_trends} \end{center}
|
|||
|
\caption{Preferencia de Sistema Operativo para Sistemas Embebidos 2003-2007. Fuente: linuxdevices.} \label{os_trends}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
La elecci<63>n de Linux como herramienta de desarrollo esta fuertemente influenciada por su caracter libre, la gran disponibilidad de herramientas de desarrollo, aplicaciones, librer<65>as y la posibilidad de modificar o adaptar c<>digo ya existente.
|
|||
|
|
|||
|
El coraz<61>n de todo sistema embebido es su procesador, en la actualidad existen diversos fabricantes que ponen a disposici<63>n de los desarrolladores \textit{System On Chip} (SOC) que incluyen una gran variedad de perif<69>ricos que incluyen dispositivos de comunicaci<63>n (UARTs, USB, Ethernet), interface con el humano (Controladores de: LCD, tarjetas de sonido, dispositivos touch screen), almacenamiento (memorias: RAM, SDRAM, SD, MMC). Al incluir la mayor<6F>a de los perif<69>ricos en el mismo Chip se reduce el espacio de la placa de circuito impreso (PCB) y se reduce la posibilidad de errores debido a interconexi<78>n y contrario a lo que se podr<64>a esperar, el costo de este SOC es muy bajo (en comparaci<63>n con el costo de cada perif<69>rico por separado). La figura \ref{cpu_trends} muestra la preferencia de los desarrolladores encuestados por \textit{linuxdevices}.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/embedded_processor_preference_history} \end{center}
|
|||
|
\caption{Preferencia de CPU para Sistemas Embebidos 2004-2007. Fuente: linuxdevices.} \label{cpu_trends}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Como puede verse en la Figura \ref{cpu_trends} existe una clara preferencia entre los procesadores x86 y los procesadores ARM, siendo estos <20>ltimos los m<>s populares en dispositivos de consumo como PDAs, Routers, tel<65>fonos celulares, consolas de juego port<72>tiles.\ref{cpu_trends}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
\section{Sistemas Embebidos}
|
|||
|
Un Sistema Embebidos es un sistema de prop<6F>sito espec<65>fico en el cual, el computador es encapsulado completamente por el dispositivo que el controla. A diferencia de los computadores de prop<6F>sito general, un Sistema Embebido realiza tareas pre-definidas, lo cual permite su optimizaci<63>n, reduciendo el tama<6D>o y costo del producto \cite{Wik}
|
|||
|
|
|||
|
\subsection{Caracter<65>sticas}
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Los sistemas embebidos son dise<73>ados para una aplicaci<63>n
|
|||
|
espec\'{\i}fica, es decir, estos sistemas realizan un grupo de funciones
|
|||
|
previamente definidasm y una vez el sistema es dise<73>ado, no se puede cambiar
|
|||
|
su funcionalidad. Por ejemplo, el control de un asensor siempre realizar\'a
|
|||
|
las mismas acciones durante su vida \'util.
|
|||
|
\item Debido a su interacci<63>n con el entorno los ES deben cumplir
|
|||
|
esctr<74>ctamente restricciones temporales. El t\'ermino {\textit{Sistemas
|
|||
|
de Tiempo Real}} es utilizado para enfatizar este aspecto.
|
|||
|
\item Los Sistemas Embebidos son heterog\'eneos, es decir, est\'an
|
|||
|
compuestos por componentes Hardware y Software. Los componentes Hardware,
|
|||
|
como ASICs y Dispositivos L\'ogicos Programables (PLD) proporcionan la
|
|||
|
velocidad de ejecuci\'on y el cosumo de potencia necesarios en algunas
|
|||
|
aplicaciones.
|
|||
|
\item Los Sitemas Embebidos tienen grandes requerimientos en t\'erminos de
|
|||
|
confiabilidad. Errores en aplicaciones como la aviaci\'on y el
|
|||
|
automovilismo, pueden tener consecuencias desastrosas.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsection{Arquitectura}
|
|||
|
|
|||
|
En la Figura \ref{es_arch} se muestra la arquitectura t<>pica de un Sistema Embebido. La cual integra un componente hardware, implementado ya sea en un PLD (CPLD, FPGA) o en un ASIC, conocido con el nombre de perif<69>ricos y un componente software (procesador o DSP) cap<61>z de ejecutar software, la parte del procesador est<73> dividida en la CPU (En algunos casos posee una cach<63>) y las unidades de Memoria.
|
|||
|
|
|||
|
|
|||
|
\begin{figure}
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/ES_Architecture} \end{center}
|
|||
|
\caption{Arquitectura de un Sistema Embebido}\label{es_arch}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Al momento de dise<73>ar un Sistema Embebido encontramos las siguientes opciones:
|
|||
|
\begin{itemize}
|
|||
|
\item Componente HW y SW Integrado en un dispositivo semiconductor (SoC): En la actualidad existen muchas compa<70><61>as que fabrican procesadores de 32 bits integrados a una gran variedad de perif<69>ricos, lo cual simplifica el dise<73>o y reduce costos. \footnote{http://www.sharpsma.com, http://www.atmel.com, http://www.cirrus.com, http://www.samsung.com, http://www.freescale.com, etc}. Este tipo de implementaci<63>n es muy popular en los dispositivos de consumo masivo (Reproductores de MP3, consolas de juego, etc), debido a los grandes niveles de producci<63>n (del orden de millones de unidades) resulta m<>s econ<6F>mico contar con un dispositivo que integre el mayor n<>mero de funcionalidades, esto disminuye el costo de componentes y reduce el <20>rea de circuito impreso.
|
|||
|
|
|||
|
\item Componente SW en un SoC y componente HW en una FPGA: Cuando no existen en el mercado un SoC con la cantidad de perif<69>ricos requerida para una determinada aplicaci<63>n, o con una funcionalidad espec<65>fica, es necesario recurrir a la utilizaci<63>n de dispositivos comerciales que implementen dicha operaci<63>n, en algunas ocaciones el perif<69>rico puede relizar funciones poco com<6F>nes y no se proporciona comercialmente, la soluci<63>n es entonces, implementar estas funcionalidades en una FPGA; tambi<62>n se recomienda la utilizaci<63>n de FPGAs en sistemas que requieren la utilizaci<63>n de la misma funcionalidad un gran n<>mero de veces (Puertos seriales, Pines de Entrada/Salida). Esta decisi<73>n esta atada al nivel de producci<63>n, ya que al incluir una FPGA aumenta el costo global del proyecto.
|
|||
|
|
|||
|
\item Componente SW y HW en una FPGA: Esta es tal vez la opci<63>n m<>s flexible, pero la de menor desempe<70>o, ya que al utilizar los recursos l<>gicos de la FPGA para la implementaci<63>n del procesador (softcore) la longitud de los caminos de interconexi<78>n entre los bloques l<>gicos aumentan el retardo de las se<73>ales, lo cual disminuye la m<>xima velocidad de funcionamiento. Los procesadores \textit{softcore} m<>s populares en la actualidad son:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Microblaze y Picoblaze de Xilinx\footnote{http://www.xilinx.com}
|
|||
|
\item Leon de Gaisler Research \footnote{http://www.gaisler.com/}
|
|||
|
\item LatticeMico32 de Lattice Semiconductors\footnote{http://www.latticesemi.com}
|
|||
|
\item OpenRisc \footnote{http://www.opencores.com}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsection{Metodolog<6F>a de Dise<73>o}
|
|||
|
|
|||
|
El proceso de dise<73>o de un Sistema Embebido comienza con la {\textit{especificaci\'on del sistema}}, (ver Figura \ref{des_flow}), en este
|
|||
|
punto se describe la funcionalidad y se definen las restricciones
|
|||
|
f\'{\i}sicas, el\'ectricas y econ\'omicas. Esta especificaci\'on debe ser muy
|
|||
|
general y no deben existir dependencias (tecnol\'ogicas, metodol\'ogicas) de
|
|||
|
ning\'un tipo, se suele utilizar lenguajes de alto nivel, como UML, C++. La
|
|||
|
especificaci\'on puede ser verificada a trav\'es de una serie de pasos de
|
|||
|
an\'alisis cuyo objetivo es determinar la validez de los algor\'{\i}tmos
|
|||
|
seleccionados, por ejemplo, determinar si el algoritmo siempre termina, los
|
|||
|
resultados satisfacen las especificaciones. Desde el punto de vista de la
|
|||
|
re-utilizaci\'on, algunas partes del funcionamiento global deben tomarse de
|
|||
|
una librer\'{\i}a de algor\'{\i}tmos existentes.
|
|||
|
|
|||
|
\begin{figure}
|
|||
|
\begin{center} \includegraphics[scale=.55]{./images/design_flow} \end{center}
|
|||
|
\caption{Flujo de Dise<73>o de un Sistema Embebido \cite{Cor05}}\label{des_flow}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
|
|||
|
Una vez definidas las especificaciones del sistema se debe realizar un
|
|||
|
modelamiento que permita extraer de estas la funcionalidad. El modelamiento es
|
|||
|
crucial en el dise<73>o ya que de \'el depende el paso existoso de la
|
|||
|
especificaci\'on a la implementaci\'on. Es importante definir que modelo
|
|||
|
matem\'atico debe soportar el entorno de dise<73>o. Los modelos m\'as utilizados
|
|||
|
son: M\'aquinas de estados finitos, diagramas de flujos de datos, Sistemad de
|
|||
|
Eventos Discretos y Redes de Petri. Cada modelo posee propiedades
|
|||
|
matem\'aticas que pueden explotarse de forma eficiente para responder
|
|||
|
preguntas sobre la funcionalidad del sistema sin llevar a cabo dispendiosas
|
|||
|
tareas de verificaci\'on. \ Todo modelo obtenido debe ser verificado para
|
|||
|
comprobar que cumple con las restricciones del sistema.
|
|||
|
|
|||
|
Una vez se ha obtenido el modelo del sistema se procede a determinar su
|
|||
|
{\textit{arquitectura}}, esto es, el n\'umero y tipo de componentes y su
|
|||
|
inter-conexi\'on. Este paso no es m\'as que una exploraci\'on del espacio de
|
|||
|
dise<EFBFBD>o en b\'usqueda de soluciones que permitan la implementaci\'on de una
|
|||
|
funcionalidad dada, y puede realizarse con varios criterios en mente: Costos,
|
|||
|
confiabilidad, viabilidad comercial.
|
|||
|
|
|||
|
Utilizando como base la arquitectura obtenida en el paso anterior las tareas
|
|||
|
del modelo del sistemas son mapeadas dentro de los componentes. Esto es,
|
|||
|
asignaci\'on de funciones a los componentes de la arquitectura. Existen dos
|
|||
|
opciones a la hora de implementar las tareas o procesos:
|
|||
|
\begin{enumerate}
|
|||
|
\item Implementaci\'on Software: La tarea se va a ejecutar en un procesador.
|
|||
|
\item Implementaci\'on Hardware: La tarea se va a ejecutar en un sistema
|
|||
|
digital dedicado.
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
Para cumplir las especificaciones del sistema algunas tareas deben ser
|
|||
|
implementadas en Hardware, esto con el f\'{\i}n de no ocupar al procesador en
|
|||
|
tareas c\'{\i}clicas, un ejemplo t\'{\i}pico de estas tareas es la
|
|||
|
generaci\'on de bases de tiempos. La decisi\'on de que tareas se implementan
|
|||
|
en SW y que tareas se implementan en HW recibe el nombre de
|
|||
|
{\textit{particionamiento}}, esta selecci\'on es fuertemente dependiente de
|
|||
|
restricciones econ\'omicas y temporales.
|
|||
|
|
|||
|
|
|||
|
Las tareas Software deben compartir los recursos que existan en el sistema
|
|||
|
(procesador y memoria), por lo tanto se deben hacer decisiones sobre el orden
|
|||
|
de ejecuci\'on y la prioridad de estas. Este proceso recibe el nombre de
|
|||
|
{\textit{planificaci\'on}}. En este punto del dise<73>o el modelo debe incluir
|
|||
|
informaci\'on sobre el mapeo, el particionamiento y la planificaci\'on del
|
|||
|
sistema.
|
|||
|
|
|||
|
|
|||
|
Las siguientes fases corresponden a la implementaci\'on del modelo, para esto
|
|||
|
las tareas hardware deben ser llevadas al dispositivo elegido (ASIC o FPGA) y
|
|||
|
se debe obtener el $''$ejecutable$''$ de las tareas software, este proceso
|
|||
|
recibe el nombre de {\textit{s\'{\i}ntesis}} HW y SW respectivamente, as\'{\i}
|
|||
|
mismo se deben sintetizar los mecanismos de comunicaci\'on.
|
|||
|
|
|||
|
|
|||
|
El proceso de prototipado consiste en la realizaci\'on f\'{\i}sica del
|
|||
|
sistema, finalmente el sistema f\'{\i}sico debe someterse a pruebas para
|
|||
|
verificar que se cumplen con las especificaciones iniciales.
|
|||
|
|
|||
|
Como puede verse en el flujo de dise<73>o existen realimentaciones, estas
|
|||
|
realimentaciones permiten depurar el resultado de pasos anteriores en el caso
|
|||
|
de no cumplirse con las especificaciones iniciales.
|
|||
|
|
|||
|
|
|||
|
\subsection{Herramientas Software de libre distribuci<63>n \textit{GNU toolchain}}
|
|||
|
En el mercado existe una gran variedad de herramientas de desarrollo para Sistemas Embebidos,
|
|||
|
sin embargo, en este estudio nos centraremos en el uso de las herramientas de libre distribuci<63>n;
|
|||
|
esta elecci<63>n se debe a que la mayor<6F>a de los productos comerciales utilizan el toolchain de GNU\footnote{http://www.gnu.org} internamente y proporcionan un entorno gr<67>fico para su f<>cil manejo. Otro factor considerado a la hora de realizar nuestra elecci<63>n es el econ<6F>mico, ya que la mayor<6F>a de los productos comerciales son costosos y poseen soporte limitado. Por otro lado, el toolchain de GNU es utilizado ampliamente en el medio de los dise<73>adores de sistemas embebidos y se encuentra un gran soporte en m<>ltiples foros de discusi<73>n (ver Figura \ref{tools}).
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/embedded-linux-tool-trends-sm} \end{center}
|
|||
|
\caption{Tendencia de utilizaci<63>n de herramientas de desarrollo}\label{tools}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
\subsubsection{GNU binutils\cite{A1}}
|
|||
|
Son una colecci<63>n de utilidades para archivos binarios y estan compuestas por:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{addr2line} Convierte direcciones de un programa en nombres de archivos y n<>meros de l<>nea. Dada una direcci<63>n y un ejecutable, usa la informaci<63>n de depuraci<63>n en el ejecutabe para determinar que nombre de atchivo y n<>mero de lpinea est<73> asociado con la direcci<63>n dada.
|
|||
|
\item \textbf{ar} Esta utilidad crea, modifica y extrae desde ficheros. Un fichero es una colecci<63>n de otros archivos en una estructura que hace posible obtener los archivos individuales miembros del archivo.
|
|||
|
\item \textbf{as} Utilidad que compila la salida del compilador de C (GCC).
|
|||
|
\item \textbf{c++filt} Este program realiza un mapeo inverso: Decodifica nombres de bajo-nivel en nombres a nivel de usuario, de tal forma que el linker pueda mantener estas funciones sobrecargadas (overloaded) ``from clashing''.
|
|||
|
\item \textbf{gasp} GNU Assembler Macro Preprocessor
|
|||
|
\item \textbf{ld} El \textit{linker} GNU combina un n<>mero de objetos y ficheros, re-localiza sus datos y los relaciona con referencias. Normalmente el <20>ltimo paso en la construcci<63>n de un nuevo programa compilado es el llamado a ld.
|
|||
|
\item \textbf{nm} Realiza un listado de s<>mbolos de archivos tipo objeto.
|
|||
|
\item \textbf{objcopy} Copia los contenidos de un archivo tipo objeto a otro. \textit{objcopy} utiliza la librer<65>a GNU BFD para leer y escribir el archivo tipo objeto. Permite esccribibr el archivo destino en un formato diferente al del archivo fuente.
|
|||
|
\item \textbf{objdump} Despliega informaci<63>n sobre archivos tipo objeto.
|
|||
|
\item \textbf{ranlib} Genera un <20>ndice de contenidos de un fichero, y lo almacena en <20>l.
|
|||
|
\item \textbf{readelf} Interpreta encabezados de un archivo ELF.
|
|||
|
\item \textbf{size} Lista el tama<6D>o de las secciones y el tama<6D>o total de un archivo tipo objeto.
|
|||
|
\item \textbf{strings} Imprime las secuencias de caracteres imprimibles de almenos 4 caracteres de longitud.
|
|||
|
\item \textbf{strip} Elimina todos los s<>mbolos de un archivo tipo objeto.
|
|||
|
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsubsection{GNU Compiler Collection}
|
|||
|
El \textit{GNU Compiler Collection} normalmente llamado GCC, es un grupo de compiladores de lenguajes de programaci<63>n producido por el proyecto GNU. Es el compilador standard para el software libre de los sistemas operativos basados en Unix y algunos propietarios como Mac OS de Apple. Soporta los siguientes lenguajes: ADA, C, C++, Fortran, Java, Objective-C, Objective-C++ para las arquitecturas: Alpha, ARM, Atmel AVR, Blackfin, H8/300, System/370, System/390, IA-32 (x86) and x86-64, IA-64 i.e. the "Itanium", Motorola 68000, Motorola 88000, MIPS, PA-RISC, PDP-11, PowerPC, SuperH, SPARC, VAX, Renesas R8C/M16C/M32C, MorphoSys.
|
|||
|
|
|||
|
Como puede verse GCC soporta una gran cantidad de lenguajes de programaci<63>n, sin embargo, en el presente estudio solo lo utilizaremos como herramienta de compilaci<63>n para C y C++. Una caracter<65>stica de resaltar de GCC es la gran cantidad de plataformas que soporta, esto lo hace una herramienta Universal para el desarrollo de sistemas embebidos, el c<>digo escrito en una plataforma (en un lenguaje de alto nivel) puede ser implementado en otra sin mayores cambios, esto elimina la dependencia entre el c<>digo fuente y el HW\footnote{Esto recibe el nombre de re-utilizaci<63>n de c<>digo}, lo cual no ocurre al utilizar lenguaje ensamblador.
|
|||
|
|
|||
|
Por otro lado, el tiempo requerido para realizar aplicaciones utilizando C o C++ disminuye, ya que no es necesario aprender las instrucciones en assembler de una plataforma determinada; adem<65>s, la disponibilidad de librer<65>as de m<>ltiples prop<6F>sitos reduce a<>n m<>s los tiempos de desarrollo, permitiendo de esta forma tener bajos tiempos \textit{time to market} y reducir de forma considerable el costo del desarrollo.
|
|||
|
|
|||
|
\subsubsection{GNU Debugger}
|
|||
|
El depurador oficial de GNU (GDB), es un depurador que al igual que GCC tiene soporte para m<>ltiples lenguajes y plataformas. GDB permite al usuario monitorear y modificar las variables internas del programa y hacer llamado a funciones de forma independiente a la ejecuci<63>n normal del mismo. Adem<65>s, permite establecer sesiones remotas utilizando el puerto serie o TCP/IP. Aunque GDB no posee una interfaz gr<67>fica, se han desarrollado varios front-ends como DDD o GDB/Insight.
|
|||
|
|
|||
|
\subsubsection{Librer<65>as C}
|
|||
|
Adicionalmente es necesario contar con una librer<65>a que proporcione las librer<65>as standard de C: stdio, stdlib, math; las m<>s utilizadas en sistemas embebidos son:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{glibc\footnote{http://www.gnu.org/software/libc/}} Es la librer<65>a C oficial del proyecto GNU. Uno de los inconvenientes al trabajar con esta librer<65>a en sistemas embebidos es que genera ejecutables de mayor tama<6D>o que los generados a partir de otras librer<65>as, lo cual no la hace muy atractiva para este tipo de aplicaciones.
|
|||
|
\item \textbf{uClibc\footnote{http://uclibc.org/}} Es una librer<65>a dise<73>ada especialmente para sistemas embebidos, es mucho m<>s peque<75>a que \textbf{glibc}.
|
|||
|
\item \textbf{newlib\footnote{http://sources.redhat.com/newlib/}} Al igual que \textbf{uClibc}, est<73> dise<73>ada para sistemas embebidos. El t<>pico ``Hello, world!'' ocupa menos de 30k en un entorno basado en newlib, mientras que en uno basado en glibc, puede ocupar 380k \cite{BG}.
|
|||
|
\item \textbf{diet libc\footnote{http://www.fefe.de/dietlibc/}} Es una versi<73>n de \textit{libc} optimizada en tama<6D>o, puede ser utilizada para crear ejecutables est<73>ticamente enlazados para linux en plataformas alpha, arm, hppa, ia64, i386, mips, s390, sparc, sparc64, ppc y x86\_64.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Flujo de dise<73>o software}
|
|||
|
|
|||
|
En la figura \ref{toolchain_flow} se ilustra la secuencia de pasos que se realizan desde la creaci<63>n de un archivo de texto que posee el c<>digo fuente de una aplicaci<63>n hasta su implementaci<63>n en la tarjeta de desarrollo.
|
|||
|
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/SW_design_flow} \end{center}
|
|||
|
\caption{Flujo de dise<73>o SW utilizando la cadena de herramientas GNU}\label{toolchain_flow}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
A continuaci<63>n se realiza una breve descripci<63>n de los pasos necesarios para generar un ejecutable para un sistema embebido:
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
\item \textbf{Escritura del c<>digo fuente:} Creaci<63>n del c<>digo fuente en cualquier editor de archivos de texto.
|
|||
|
\item \textbf{Compilaci<63>n:} Utilizando el compilador gcc se compila el c<>digo fuente; vala la pena mencionar que en este punto el compilador solo busca en los encabezados (\textit{headers}) de las librer<65>as la definici<63>n de una determinada funci<63>n, como por ejemplo el \textit{printf} en el archivo \textit{stdio.h}. Como resultado de este paso se obtiene un archivo tipo objeto.
|
|||
|
\item \textbf{Enlazado:} En esta etapa se realizan dos tareas:
|
|||
|
\begin{enumerate}
|
|||
|
\item Se enlazan los archivos tipo objeto del proyecto, junto con las librer<65>as, si una determinada funci<63>n no es edfinida por ninguna de las librer<65>as pasadas como par<61>metro al linker, este generar<61> un error y no se generar<61> el ejecutable.
|
|||
|
\item Se define la posici<63>nes f<>sicas de las secciones del ejecutable tipo ELF, esto se realiza a trav<61>s de un link de enlazado el cual define de forma expl<70>cita su localizaci<63>n.
|
|||
|
\end{enumerate}
|
|||
|
\item \textbf{Extracci<63>n del archivo de programaci<63>n} En algunas aplicaciones es necesario extraer <20>nicamente las secciones que residen en los medios de almacenamiento no vol<6F>til y eliminar las dem<65>s secciones del ejecutable. Esto se realiza con la herramiento \textit{objcopy}, la cual, permite generar archivos en la mayor<6F>a de los formatos soportados por los programadores de memorias y procesadores, como por ejemplo S19 e Intel Hex.
|
|||
|
\item \textbf{Descarga del programa a la plataforma}. Dependiendo de la plataforma existen varios m<>todos para descargar el archivo de programaci<63>n a la memoria de la plataforma de desarrollo:
|
|||
|
\begin{enumerate}
|
|||
|
\item Utilizando un \textit{loader}: El \textit{loader} es una aplicaci<63>n que reside en un medio de almacenamiento no vol<6F>til y permite la descarga de archivos utilizando el puerto serie o una interfaz de red.
|
|||
|
\item Utilizando el puerto JTAG: El puerto JTAG (Joint Test Action Group) proporciona una interfaz capaz de controlar los registros internos del procesador, y de esta forma, acceder a las memorias de la plataforma y ejecutar un programa residente en una determinada posici<63>n de memoria.
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
\item \textbf{Depuraci<63>n} Una vez se descarga la aplicaci<63>n a la plataforma es necesario someterla a una serie de pruebas con el f<>n de probar su correcto funcionamiento. Esto se puede realizar con el depurador GNU (GDB) y una interfaz de comunicaci<63>n que puede ser un puerto serie o un adaptador de red.
|
|||
|
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Make}
|
|||
|
Como vimoas anteriormente es necesario realizar una serie de pasos para poder descargar una aplicaci<63>n a una plataforma embebida. Debido a que las herramientas GNU solo poseen entrada por consola de comandos, es necesario escribir una serie de comandos cada vez que se realiza un cambio en el c<>digo fuente, lo cual resulta poco pr<70>ctico durante la etapa de desarrollo. Para realizar este proceso de forma autom<6F>tica, se cre<72> la herramienta make, la cual recibe como entrada un archivo que normalmente recibe el nombre de \textit{Makefile} o \textit{makefile}. La herramienta make ejecuta los comandos necesarios para realizar la compilaci<63>n, depuraci<63>n, o programaci<63>n, indicados en el archivo \textit{Makefile} o \textit{makefile}. Un ejemplo de este tipo de archivo se muestra a continuaci<63>n:
|
|||
|
|
|||
|
\begin{lstlisting}[numbers=left]
|
|||
|
SHELL = /bin/sh
|
|||
|
|
|||
|
basetoolsdir = /home/at91/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu
|
|||
|
bindir = ${basetoolsdir}/bin
|
|||
|
libdir = ${basetoolsdir}/lib/gcc/arm-softfloat-linux-gnu/3.4.5
|
|||
|
|
|||
|
CC = arm-softfloat-linux-gnu-gcc
|
|||
|
AS = arm-softfloat-linux-gnu-as
|
|||
|
LD = arm-softfloat-linux-gnu-ld
|
|||
|
OBJCOPY = arm-softfloat-linux-gnu-objcopy
|
|||
|
|
|||
|
CFLAGS =-mcpu=arm920t -I. -Wall
|
|||
|
LDFLAGS =-L${libdir} -l gcc
|
|||
|
|
|||
|
OBJS = \
|
|||
|
main.o \
|
|||
|
debug_io.o \
|
|||
|
at91rm9200_lowlevel.o \
|
|||
|
p_string.o
|
|||
|
|
|||
|
ASFILES = arm_init.o
|
|||
|
|
|||
|
LIBS=${libdir}/
|
|||
|
|
|||
|
all: hello_world
|
|||
|
|
|||
|
hello_world: ${OBJS} ${ASFILES} ${LIBS}
|
|||
|
${LD} -e 0 -o hello_world.elf -T linker.cfg ${ASFILES} ${OBJS} ${LDFLAGS}
|
|||
|
${OBJCOPY} -O binary hello_world.elf hello_world.bin
|
|||
|
|
|||
|
clean:
|
|||
|
rm -f *.o *~ hello_world.*
|
|||
|
|
|||
|
PREPROCESS.c = $(CC) $(CPPFLAGS) $(TARGET_ARCH) -E -Wp,-C,-dD,-dI
|
|||
|
|
|||
|
%.pp : %.c FORCE
|
|||
|
$(PREPROCESS.c) $< > $@
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En las l<>neas 3-5 se definen algunas variables globales que ser<65>n utilizadas a lo largo del archivo; en las l<>neas 7 - 10 se definen las herramientas de compilaci<63>n a utilizar, espec<65>ficamente los compiladores de C (CC), de assembler (AS), el linker (LD) y la utilidad objcopy. A partir de la l<>nea 15 se definen los objetos que forman parte del proyecto, en este caso: \textit{main.o, debug\_io.o, at91rm9200\_lowlevel.o y p\_string.o}; en la l<>nea 21 se definen los archivos en assembler que contiene el proyecto, para este caso \textit{arm\_init.o}. Las l<>neas 12 y 13 definen dos variables especiales que se pasan directamente al compilador de C (CFLAGS) y al liniker (LDFLAGS)
|
|||
|
|
|||
|
|
|||
|
En las l<>neas 25, 27 y 31 aparecen unas etiquetas de la forma: \textit{nombre:} esta es la forma de definir reglas y permiten ejecutar de forma independiente el conjunto de instrucciones asociadas a ellas, por ejemplo, si se ejecuta el comando:
|
|||
|
\\ \bigskip
|
|||
|
\textit{make clean}\\ \bigskip
|
|||
|
make ejecutar<61>:\\ \bigskip
|
|||
|
\textit{rm -f *.o *~ hello\_world.*}
|
|||
|
|
|||
|
Observemos los comandos asociados a la etiqueta \textit{hello\_world:} En la misma l<>nea aparecen \textit{\${OBJS} \${ASFILES} \${LIBS}}, estos reciben el nombre de dependencias y le indican a la herramienta \textit{make} que antes de ejecutar los comandos asociados a este label, debe realizar las acciones necesarias para generar \textit{\${OBJS} \${ASFILES} \${LIBS}}, esto es: \textit{main.o, debug\_io.o, at91rm9200\_lowlevel.o, p\_string.o, arm\_init.o y libgcc.a}. \textit{make} tiene predefinidas una serie de reglas para compilar los archivos .c la regla es de la forma:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
.c.o:
|
|||
|
$(CC) $(CFLAGS) -c $<
|
|||
|
.c:
|
|||
|
$(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Lo cual le indica a la herramienta make que para generar un archivo \textit{.o} a partir de uno \textit{.c} es necesario ejecutar \textit{\$(CC) \$(CFLAGS) -c \$<}; de aqui la importancia de definir bien la variable de entorno \textit{CC} cuando trabajamos con compiladores cruzados\footnote{Un compilador cruzado genera c<>digo para una plataforma diferente en la que se est<73> ejecutando, por ejemplo, genera ejecutables para ARM pero se ejecuta en un x86}. Hasta este punto al ejecutar el comando: \textit{make hello\_world}, \textit{make} realizar<61>a las siguientes operaciones: \\
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
arm-softfloat-linux-gnu-gcc -mcpu=arm920t -I. -Wall -c -o main.o main.c
|
|||
|
arm-softfloat-linux-gnu-gcc -mcpu=arm920t -I. -Wall -c -o debug_io.o debug_io.c
|
|||
|
arm-softfloat-linux-gnu-gcc -mcpu=arm920t -I. -Wall -c -o at91rm9200_lowlevel.o
|
|||
|
at91rm9200_lowlevel.c
|
|||
|
arm-softfloat-linux-gnu-gcc -mcpu=arm920t -I. -Wall -c -o p_string.o p_string.c
|
|||
|
arm-softfloat-linux-gnu-as -o arm_init.o arm_init.s
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En las l<>neas 28 se realiza el proceso de enlazado; al \textit{linker} se le pasan los par<61>metros:
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{-e 0}: Punto de entrada , utilice 0 como s<>mbolo para el inicio de ejecuci<63>n.
|
|||
|
\item \textbf{-o hello\_world.elf}: Nombre del archivo de salida \textit{hello\_world}
|
|||
|
\item \textbf{-T linker.cfg}: Utilice el archivo de enlace \textit{linker.cfg}
|
|||
|
\item \textbf{\${ASFILES} \${OBJS} \${LDFLAGS}}: Lista de objetos y librer<65>as para crear el ejecutable.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
En la l<>nea 29 se utiliza la herramienta \textit{objcopy} para generar un archivo binario (\textit{-O binary}) con la informaci<63>n necesaria para cargar en una memoria no vol<6F>til. Esto se explicar<61> con mayor detalle m<>s adelante.
|
|||
|
|
|||
|
\subsubsection{El formato \textbf{ELF}}
|
|||
|
|
|||
|
El formato ELF (\textit{Executable and Linkable Format}) Es un st<73>ndard para objetos, librer<65>as y ejecutables y es el formato que genera las herramientas GNU. Como puede verse en la figura \ref{elf1} est<73> compuesto por varias secciones (\textit{link view}) o segmentos (\textit{execution view}). Si un programador est<73> interesado en obtener informaci<63>n de secciones sobre tablas de s<>mbolos, c<>digo ejecutable espec<65>fico o informaci<63>n de enlazado din<69>mico debe utilizar \textit{link view}. Pero si busca informaci<63>n sobre segmentos, como por ejemplo, la localizaci<63>n de los segmentos \textit{text} o \textit{data} debe utilizar \textit{execution view}. El encabezado describe el layout del archivo, proporcionando informaci<63>n de la forma de acceder a las secciones \cite{MLH98}.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.4]{./images/ELF_Link_exec1} \end{center}
|
|||
|
\caption{Formato ELF}\label{elf1}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Las secciones pueden almacenar c<>digo ejecutable, datos, informaci<63>n de enlazado din<69>mico, datos de depuraci<63>n, tablas de s<>mbolos,comentarios, tablas de strings, y notas. Las secciones m<>s importantes son las siguientes:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{.bss} Datos no inicializados. (RAM)
|
|||
|
\item \textbf{.comment} Informaci<63>n de la versi<73>n.
|
|||
|
\item \textbf{.data y .data1} Datos inicializados. (RAM)
|
|||
|
\item \textbf{.debug} Informaci<63>n para depuraci<63>n simb<6D>lica.
|
|||
|
\item \textbf{.dynamic} Informaci<63>n sobre enlace din<69>mico
|
|||
|
\item \textbf{.dynstr} Strings necesarios para el enlacedin<69>mico
|
|||
|
\item \textbf{.dynsym} Tabla de s<>mbolos utilizada para enlace din<69>mico.
|
|||
|
\item \textbf{.fini} C<>digo de terminaci<63>n de proceso.
|
|||
|
\item \textbf{.init} C<>digo de inicializaci<63>n de proceso.
|
|||
|
\item \textbf{.line} Informaci<63>n de n<>mero de l<>nea para depuraci<63>n simb<6D>lica.
|
|||
|
\item \textbf{.rodata y .rodta1} Datos de solo-lectura (ROM)
|
|||
|
\item \textbf{.shstrtab} Nombres de secciones.
|
|||
|
\item \textbf{.symtab} Tabla de s<>mbolos.
|
|||
|
\item \textbf{.text} Instrucciones ejecutables (ROM)
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
Para aclarar un poco este concepto, escribamos una aplicaci<63>n sencilla:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#include <stdio.h>
|
|||
|
|
|||
|
int global;
|
|||
|
int global_1 = 1;
|
|||
|
|
|||
|
int main(void)
|
|||
|
{
|
|||
|
int i; // Variable no inicializada
|
|||
|
int j = 2; // Variable inicializada
|
|||
|
for(i=0; i<10; i++){
|
|||
|
printf("Printing %d\n", i*j); // Caracteres constantes
|
|||
|
j = j + 1;
|
|||
|
global = i;
|
|||
|
global_1 = i+j;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Generemos el objeto compil<69>ndolo con el siguiente comando:
|
|||
|
\textit{arm-none-eabi-gcc -c hello.c}
|
|||
|
|
|||
|
Examinemos que tipo de secciones tiene este ejecutable
|
|||
|
\textit{arm-none-eabi-readelf -S hello.o}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
Section Headers:
|
|||
|
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
|
|||
|
[ 0] NULL 00000000 000000 000000 00 0 0 0
|
|||
|
[ 1] .text PROGBITS 00000000 000034 00009c 00 AX 0 0 4
|
|||
|
[ 2] .rel.text REL 00000000 000484 000020 08 9 1 4
|
|||
|
[ 3] .data PROGBITS 00000000 0000d0 000004 00 WA 0 0 4
|
|||
|
[ 4] .bss NOBITS 00000000 0000d4 000000 00 WA 0 0 1
|
|||
|
[ 5] .rodata PROGBITS 00000000 0000d4 000010 00 A 0 0 4
|
|||
|
[ 6] .comment PROGBITS 00000000 0000e4 00004d 00 0 0 1
|
|||
|
[ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 000131 00002e 00 0 0 1
|
|||
|
[ 8] .shstrtab STRTAB 00000000 00015f 000051 00 0 0 1
|
|||
|
[ 9] .symtab SYMTAB 00000000 000368 0000f0 10 10 11 4
|
|||
|
[10] .strtab STRTAB 00000000 000458 00002b 00 0 0 1
|
|||
|
Key to Flags:
|
|||
|
W (write), A (alloc), X (execute), M (merge), S (strings)
|
|||
|
I (info), L (link order), G (group), x (unknown)
|
|||
|
O (extra OS processing required) o (OS specific), p (processor specific)
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La secci<63>n \textit{.text}, como se dijo anteriormente contiene las instrucciones ejecutables, por esta raz<61>n se marca como ejecutable \textit{``X''} en la columna \textit{Flg}. Es posible ver las instrucciones que se ejecutan en esta secci<63>n:
|
|||
|
|
|||
|
\textit{arm-none-eabi-objdump -d -j .text hello.o}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
00000000 <main>:
|
|||
|
0: e92d4800 stmdb sp!, {fp, lr}
|
|||
|
4: e28db004 add fp, sp, #4 ; 0x4
|
|||
|
8: e24dd008 sub sp, sp, #8 ; 0x8
|
|||
|
c: e3a03002 mov r3, #2 ; 0x2
|
|||
|
10: e50b3008 str r3, [fp, #-8]
|
|||
|
14: e3a03000 mov r3, #0 ; 0x0
|
|||
|
18: e50b300c str r3, [fp, #-12]
|
|||
|
1c: ea000013 b 70 <main+0x70>
|
|||
|
20: e51b200c ldr r2, [fp, #-12]
|
|||
|
24: e51b3008 ldr r3, [fp, #-8]
|
|||
|
28: e0030392 mul r3, r2, r3
|
|||
|
2c: e59f005c ldr r0, [pc, #92] ; 90 <.text+0x90>
|
|||
|
30: e1a01003 mov r1, r3
|
|||
|
34: ebfffffe bl 0 <printf>
|
|||
|
38: e51b3008 ldr r3, [fp, #-8]
|
|||
|
3c: e2833001 add r3, r3, #1 ; 0x1
|
|||
|
40: e50b3008 str r3, [fp, #-8]
|
|||
|
44: e59f2048 ldr r2, [pc, #72] ; 94 <.text+0x94>
|
|||
|
48: e51b300c ldr r3, [fp, #-12]
|
|||
|
4c: e5823000 str r3, [r2]
|
|||
|
50: e51b200c ldr r2, [fp, #-12]
|
|||
|
54: e51b3008 ldr r3, [fp, #-8]
|
|||
|
58: e0822003 add r2, r2, r3
|
|||
|
5c: e59f3034 ldr r3, [pc, #52] ; 98 <.text+0x98>
|
|||
|
60: e5832000 str r2, [r3]
|
|||
|
64: e51b300c ldr r3, [fp, #-12]
|
|||
|
68: e2833001 add r3, r3, #1 ; 0x1
|
|||
|
6c: e50b300c str r3, [fp, #-12]
|
|||
|
70: e51b300c ldr r3, [fp, #-12]
|
|||
|
74: e3530009 cmp r3, #9 ; 0x9
|
|||
|
78: daffffe8 ble 20 <main+0x20>
|
|||
|
7c: e3a03000 mov r3, #0 ; 0x0
|
|||
|
80: e1a00003 mov r0, r3
|
|||
|
84: e24bd004 sub sp, fp, #4 ; 0x4
|
|||
|
88: e8bd4800 ldmia sp!, {fp, lr}
|
|||
|
8c: e12fff1e bx lr
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La secci<63>n \textit{.data} mantiene las variables inicializadas, y contiene:
|
|||
|
|
|||
|
\textit{arm-none-eabi-objdump -d -j .data hello.o}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
00000000 <global_1>:
|
|||
|
0: 01 00 00 00
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como vemos, la secci<63>n \textit{.data} contiene \'unicamente el valor de inicializaci\'on de la variable \textit{global\_1} (1) y no muestra informaci<63>\'on acerca de la variable \textit{j}, esto se debe a que la informaci\'on est\'a en el \textit{stack} del proceso. Si observamos el contenido de la secci<63>n \textit{.text} observamos que esta variable es asignada en tiempo de ejecuci<63>n, en la l<>nea \textit{0c:}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
0c: e3a03002 mov r3, #2 ; 0x2
|
|||
|
10: e50b3008 str r3, [fp, #-8]
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
se ve la asignaci<63>n de esta variable.
|
|||
|
|
|||
|
|
|||
|
La secci<63>n \textit{.bss} mantiene la informaci\'on de las variables no incializadas:
|
|||
|
\textit{arm-none-eabi-objdump -d -j .bss hello}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
000145c4 <global>:
|
|||
|
145c4: 00000000
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En Linux todas las variables no inicializadas, se inicializadan en cero.
|
|||
|
|
|||
|
La secci<63>n \textit{.rodata} mantiene los datos que no cambian durante la ejecuci<63>n del programa, es decir, de solo lectura, si examinamos esta secci<63>n obtenemos:
|
|||
|
|
|||
|
\textit{hexdump -C hello.o | grep -i 000000d0} (la secci<63>n \textit{.rodata} comienza en la posici<63>n de memoria 0xd4)
|
|||
|
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
000000d0 01 00 00 00 50 72 69 6e 74 69 6e 67 20 25 64 0a |....Printing %d.|
|
|||
|
000000e0 00 00 00 00 00 47 43 43 3a 20 28 43 6f 64 65 53 |.....GCC: (CodeS|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Observamos que en el archivo se almacena la cadena de caracteres \textit{Printing \%d\\n} la cual no se modifica durante la ejecuci<63>n del programa.
|
|||
|
|
|||
|
\subsubsection{Linker Script}
|
|||
|
Como vimos anteriormente, el \textit{linker} es el encargado de agrupar todos los archivos objeto \textit{.o}, y las librer<65>as necesarias para crear el ejecutable, este \textit{linker} permite definir donde ser<65>n ubicados los diferentes segmentos del archivo ELF, por medio de un archivo de enlace \textit{linker script}. De esta forma podemos ajustar el ejecutable a plataformas con diferentes configuraciones de memoria.Esto brinda un grado mayor de flexibilidaad de la cadena de herramientas GNU. Cuando se dispone de un sistema operativo como Linux no es necesario definir este archivo, ya que el sistema operativo se encarga de guardar las secciones en el lugar indicado, sin embargo, es necesario tenerlo presente ya que como veremos m<>s adelante existe un momento en el que el sistema operativo no ha sido cargado en la plataforma y las aplicaciones que se ejecuten deben proporcionar esta informaci<63>n. A continuaci<63>n se muestra un ejemplo de este archivo:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
/* identify the Entry Point (_vec_reset is defined in file crt.s) */
|
|||
|
ENTRY(_vec_reset)
|
|||
|
|
|||
|
/* specify the memory areas */
|
|||
|
MEMORY
|
|||
|
{
|
|||
|
flash : ORIGIN = 0, LENGTH = 256K /* FLASH EPROM */
|
|||
|
ram : ORIGIN = 0x00200000, LENGTH = 64K /* static RAM area */
|
|||
|
}
|
|||
|
|
|||
|
/* define a global symbol _stack_end */
|
|||
|
_stack_end = 0x20FFFC;
|
|||
|
|
|||
|
/* now define the output sections */
|
|||
|
SECTIONS
|
|||
|
{
|
|||
|
. = 0; /* set location counter to address zero */
|
|||
|
.text : /* collect all sections that should go into FLASH after startup */
|
|||
|
{
|
|||
|
*(.text) /* all .text sections (code) */
|
|||
|
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
|
|||
|
*(.rodata*) /* all .rodata* sections (constants, strings, etc.) */
|
|||
|
*(.glue_7) /* all .glue_7 sections (no idea what these are) */
|
|||
|
*(.glue_7t) /* all .glue_7t sections (no idea what these are) */
|
|||
|
_etext = .; /* define a global symbol _etext just after the last code byte */
|
|||
|
} >flash /* put all the above into FLASH */
|
|||
|
|
|||
|
.data : /* collect all initialized .data sections that go into RAM */
|
|||
|
{
|
|||
|
_data = .; /* create a global symbol marking the start of the .data section */
|
|||
|
*(.data) /* all .data sections */
|
|||
|
_edata = .; /* define a global symbol marking the end of the .data section */
|
|||
|
} >ram AT >flash /* put all the above into RAM (but load the LMA initializer copy into FLASH) */
|
|||
|
|
|||
|
.bss : /* collect all uninitialized .bss sections that go into RAM */
|
|||
|
{
|
|||
|
_bss_start = .; /* define a global symbol marking the start of the .bss section */
|
|||
|
*(.bss) /* all .bss sections */
|
|||
|
} >ram /* put all the above in RAM (it will be cleared in the startup code */
|
|||
|
. = ALIGN(4); /* advance location counter to the next 32-bit boundary */
|
|||
|
_bss_end = . ; /* define a global symbol marking the end of the .bss section */
|
|||
|
}
|
|||
|
_end = .; /* define a global symbol marking the end of application RAM */
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En las primeras l<>neas del archivo aparece la declaraci<63>n de las memorias de la plataforma, en este ejemplo tenemos una memoria RAM de 64kB que comienza en la posici<63>n de memoria 0x00200000 y una memoria flash de 256k que comienza en la posici<63>n 0x0. A continuacion se definen las secciones y el lugar donde ser<65>n almacenadas; En este caso, las secciones \textit{.text} (c<>digo ejecutable) y \textit{.rodata} (datos de solo lectura) se almacenan en una memoria no vol<6F>til la flash. Cuando el sistema sea energizado el procesador ejecutar<61> el c<>digo almacenado en su memoria no vol<6F>til. Las secciones \textit{.data} (variables inicializadas) y \textit{.bss} (variables no inicializadas) se almacenar<61>n en la memoria vol<6F>til RAM, ya que el acceso a las memorias no vol<6F>tiles son m<>s lentas y tienen ciclos de lectura/escritura finitos.
|
|||
|
|
|||
|
En algunos procesadores (como el AT91RM9200) no se dispone de una memoria no vol<6F>til, por lo que es necesario que la aplicaci<63>n sea cargada por completo en la RAM. Algunos desarrolladores prefieren almacenar y ejecutar sus aplicaciones en las memorias vol<6F>tiles durante la etapa de desarrollo, debido a que la programaci<63>n de las memorias no vol<6F>tiles toman mucho m<>s tiempo. Obviamente una vez finalizada la etapa de desarrollo las aplicaciones deben ser almacenadas en memorias no vol<6F>tiles.
|
|||
|
|
|||
|
\subsection{Herramientas hardware}
|
|||
|
Como se mencion<6F> anteriormente existen varias alternativas al momento de implementar un Sistema Embebido (ver Figura \ref{es_arch}). En este trabajo se utiliza una arquitectura compuesta por el SoC de Atmel el AT91RM9200 y una FPGA, teniendo en cuenta que esta pataforma tiene fines acad<61>micos es muy importante tener la posibilidad de crear tareas HW en un Dispositivo L<>gico Programable (PLD).
|
|||
|
|
|||
|
\subsubsection{SoC}
|
|||
|
La Figura \ref{at91rm} muestra la arquitectura de un SoC actual, espec<65>ficamente del AT91RM920 de Atmel. En este diagrama podemos observar el n<>cleo central un procesador ARM920T de 180MHz y los perif<69>ricos asociados a <20>l. En la actualidad podemos encontrar una gran variedad de SoC dise<73>ados para diferentes aplicaciones: Multimedia, Comunicaciones, Asistentes Digitales; los perif<69>ricos incluidos en cada SoC buscan minimizar el n<>mero de componentes externos, y de esta forma reducir los costos. Este SoC en particular fu<66> uno de los primeros que dise<73>o ATMEL y est<73> enfocado a tareas en las que se requiere una conexi<78>n de red. Dentro de los perif<69>ricos encontramos:
|
|||
|
\begin{itemize}
|
|||
|
\item Controlador para memorias: NAND flash, DataFlash, SDRAM, SD/MMC
|
|||
|
\item Puerto USB 2.0 host.
|
|||
|
\item Puerto I2C
|
|||
|
\item Interfaz Ethernet 10/100.
|
|||
|
\item Interfaz high speed USB 2.0
|
|||
|
\item 4 Puertos SPI.
|
|||
|
\item 2 puertos seriales (RS232).
|
|||
|
\item Soporte JTAG.
|
|||
|
\item Interf<72>z de Bus externo (EBI).
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/at91rm9200} \end{center}
|
|||
|
\caption{SoC AT91RM9200 fuente: Hoja de Especificaciones AT91RM9200, ATMEL} \label{at91rm}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Existen una serie de perif<69>ricos que son indispensables en todo Sistema Embebido, los cuales facilitan la programaci<63>n de aplicaciones y la depuraci<63>n de las mismas. A continuaci<63>n se realizar<61> una descripci<63>n de los diferentes perif<69>ricos que se encuentran disponibles en este SoC, indicando los que fueron utilizados en la plataforma de desarrollo.
|
|||
|
|
|||
|
\subsubsection{Memorias Vol<6F>tiles}
|
|||
|
|
|||
|
Como se estudi<64> anteriormente existen secciones del ejecutable que deben ser almacenadas en memorias vol<6F>tiles o en memorias no vol<6F>tiles. Debido a esto la mayor<6F>a de los SoC incluyen perif<69>ricos dedicados a controlar diferentes tipos de memoria, las memorias vol<6F>tiles son utilizadas como memoria de acceso aleatorio (RAM) gracias a su bajo tiempo de accesso y al ilimitado n<>mero de ciclos de lectura/escritura.
|
|||
|
|
|||
|
El tipo de memoria m<>s utilizado en los sistemas embebidos actuales es la memoria SDRAM; la cual est<73> organizada como una matriz de celdas, con un n<>mero de bits dedicados al direccionamiento de las filas y un n<>mero dedicado a direccionar columnas (ver Figura \ref{sdram_basics}).
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/sdram_basics} \end{center}
|
|||
|
\caption{Diagrama de Bloques de una memoria SDRAM fuente: Hoja de Especificaciones MT48LC16M16, Micron Technology} \label{sdram_basics}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Un ejemplo simplificado de una operaci<63>n de lectura es el siguiente: Una posici<63>n de memoria se determina colocando la direcci<63>n de la fila y la de la columna en las l<>neas de direcci<63>n de fila y columna respectivamente, un tiempo despu<70>s el dato almacenado aparecer<65> en el bus de datos. El procesador coloca la direcci<63>n de la fila en el bus de direcciones y despu<70>s activa la se<73>al \textit{RAS} (Row Access Strobe). Despu<70>s de un retardo de tiempo predeterminado para permitir que el circuito de la SDRAM capture la direcci<63>n de la fila, el procesador coloca la direcci<63>n de la columna en el bus de direcciones y activa la se<73>al \textit{CAS} (Column Access Strobe). Una celda de memoria SDRAM esta compuesta por un transistor y un condensador; el transistor suministra la carga y el condensador almacena el estado de cada celda, esta carga en el condensador desaparece con el tiempo, raz<61>n por la cual es necesario recargar estos condensadores peri<72>dicamente, este proceso recibe el nombre de \textit{Refresco}. Un ciclo de refresco es un ciclo especial en el que no se escribe ni se lee informaci<63>n, solo se recargan los condensadores para mantener la informaci<63>n. El perif<69>rico que controla la SDRAM est<73> encargado de garantizar los ciclos de refresco de acuerdo con los requerimientos de la SDRAM \cite{CH06}. La figura \ref{sdram_ecbot} muestra el diagrama de conexiones de una memoria de 32MB utilizada en la plataforma ECBOT.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/sdram_ecbot} \end{center}
|
|||
|
\caption{Diagrama de conexiones de la memoria SDRAM de la plataforma ECBOT} \label{sdram_ecbot}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
El SoC AT91RM9200 posee un perif<69>rico que es cap<61>z de controlar la memoria SDRAM sin necesidad de l<>gica adicional.
|
|||
|
|
|||
|
\subsubsection{Memorias No Vol<6F>tiles}
|
|||
|
La memorias no vol<6F>tiles almacenan por largos per<65>odos de tiempo informaci<63>n necesaria para la operaci<63>n de un Sistema Embebido, pueden ser vistos como discos duros de estado s<>lido; existen dos tipos de memoria las memorias NOR y las NAND; las dos poseen la capacidad de ser escritas y borradas utilizando control de software, con lo que no es necesario utilizar programadores externos y puedens er modificadas una vez instaladas en el circuito integrado. Una desventaja de estas memorias es que los tiempos de escritura y borrado son muy largos en comparaci<63>n con los requeridos por las memorias RAM.
|
|||
|
|
|||
|
Las memorias NOR poseen buses de datos y direcci<63>n, con lo que es posible acceder de forma f<>cil a cada byte almacenado en ella. Los bits datos pueden ser cambiados de 0 a 1 utilizando el control de software un byte a la vez, sin embargo, para cambiar un bit de 1 a 0 es necesario borrar una serie de unidades de borrado que reciben el nombre de bloques, lo que permite reducir el tiempo de borrado de la memoria. Debido a que el borrado y escritura de una memoria ROM se puede realizar utilizando el control software (ver Figura \ref{nor_prog}) no es necesario contar con un perif<69>rico especializado para su manejo.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/nor_prog} \end{center}
|
|||
|
\caption{Ciclos de escritura y borrado de una memoria flash NOR} \label{nor_prog}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Las memorias NOR son utilizadas en aplicaciones donde se necesiten altas velocidades de lectura y baja densidad, debido a que los tiempos de escritura y lectura son muy grandes se utilizan como memorias ROM. Las memorias NAND disminuyen los tiempos de escritura y aumentan la capacidad de almacenamiento, ideales para aplicaciones donde se requiera almacenamiento de informaci<63>n. Adicionalmente las memorias NAND consumen menos potencia que las memorias NAND, por esta raz<61>n este tipo de memorias son utilizadas en casi todos los dispositivos de almacenamiento modernos como las memorias SD y las memorias USB, los cuales integran una memoria NAND con un circuito encargado de controlarlas e implementar el protocolo de comunicaci<63>n. A diferencia de las flash tipo NOR, los dispositivos NAND se acceden de forma serial utilizando interfaces complejas; su operaci<63>n se asemeja a un disco duro tradicional. Se accede a la informaci<63>n utilizando bloques (m<>s peque<75>os que los bloques NOR). Los ciclos de escritura de las flash NAND son mayores en un orden de magnitud que los de las memorias NOR.
|
|||
|
|
|||
|
Un problema al momento de trabajar con las memorias tipo NAND es que requieren el uso de un \textit{manejo de bloques defectuosos}, esto es necesario ya que las celdas de memoria pueden da<64>arse de forma espont<6E>nea durante la operaci<63>n normal. Debido a esto se debe tener un determinado n<>mero de bloques que se encargen de almacenar tablas de mapeo para manejar los bloques defectuosos; o puede hacerse un chequeo en cada inicializaci<63>n del sistema de toda la RAM para actualizar esta lista de sectores defectuosos. El algoritmo de ECC (Error-Correcting Code) debe ser cap<61>z de corregir errores tan peque<75>os como un bit de cada 2048 bits, hasta 22 bits de cada 2048. Este algor<6F>tmo es capaz de detectar bloques defectuosos en la fase de programac<61><63>n comparando la informaci<63>n almacenada con la que debe ser almacenada (verificaci<63>n), si encuentra un error marca el bloque como defectuoso y utiliza un bloque sin defactos para almacenar la informaci<63>n.
|
|||
|
|
|||
|
La tabla \ref{flash_comp} resume las principales caracter<65>sticas de los diferentes tipos de memoria flash.
|
|||
|
|
|||
|
\begin{center}
|
|||
|
\begin{table}[ht]
|
|||
|
\begin{tabular}{|l|c|c|c|}
|
|||
|
\hline
|
|||
|
& \textbf{SLC NAND} & \textbf{MLC NAND} & MLC NOR \\ \hline
|
|||
|
Densidad & 512Mbits - 4GBits & 1Gbits - 16GBits & 16MBits - 1GBit \\ \hline
|
|||
|
Velocidad de Lectura & 24MB/s & 18.6MB/s & 103MB/s \\ \hline
|
|||
|
Velocidad de escritura& 8 MB/s & 2.4MB/s & 0,47MB/s \\ \hline
|
|||
|
Tiempo de borrado & 2ms & 2ms & 900ms \\ \hline
|
|||
|
Interfaz & Acceso Indirecto & Acceso Indirecto & Acceso Aleatorio\\ \hline
|
|||
|
Aplicaci<63>n & Almacenamiento & Almacenamiento & Solo lectura \\ \hline
|
|||
|
\end{tabular}
|
|||
|
\caption{Cuadro de comparaci<63>n de las memorias flash NAND y NOR} \label{flash_comp}
|
|||
|
\end{table}
|
|||
|
\end{center}
|
|||
|
|
|||
|
El AT91RM9200 tiene un perif<69>rico que puede manejar una memoria flash NAND, sin embargo, no se utiliz<69> en esta aplicaci<63>n. En su lugar se utiliz<69> una memoria \textit{DataFlash} de Atmel, este dispositivo b<>sicamente es una memoria flash tipo NOR con una interfaz SPI, permite una velocidad de lectura de hasta 66MHz utilizando solamente 4 pines para la comunicaci<63>n con el procesador. La figura \ref{dataflash_ecbot} muestra el diagrama de conexiones de esta memoria.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/dataflash_ecbot} \end{center}
|
|||
|
\caption{Conexiones de la memoria DataFlash de la plataforma ECBOT} \label{dataflash_ecbot}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{M<>todos de arranque}
|
|||
|
|
|||
|
Como es obvio todo SoC debe ser programado para que pueda ejecutar una determinada tarea; este programa debe estar almacenado en una memoria no vol<6F>til y debe estar en el formato requerido por el procesador. Normalmente los SoCs proporcionan varios caminos (habilitando diferentes perif<69>ricos) para hacer esto. Un programa de inicializaci<63>n \textit{(boot program)} contenido en una peque<75>a ROM del SoC se encarga de configurar, y revisar ciertos perif<69>ricos en b<>squeda de un ejecutable, una vez lo encuentra, lo copia a la memoria RAM interna y lo ejecuta desde all<6C>. No sobra mencionar que este ejecutable debe estar enlazado de tal forma que todas las secciones se encuentren en el espacio de la memoria RAM interna (0x0 despu<70>s del REMAP \footnote{Los procesadores ARM pueden intercambiar el sitio de la memoria RAM interna y la memoria no vol<6F>til}). El AT91RM9200 posee una memoria interna SRAM de 16 kbytes. Despu<70>s del reset esta memoria esta disponible en la posici<63>n 0x200000, despu<70>s del remap esta memoria se puede acceder en la posici<63>n 0x0. Algunos fabricantes, en la etapa de producci<63>n graban en las memorias no vol<6F>tiles las apliacaciones definitivas, y soldan en la placa de circuito impreso los dispoditivos programados, esto es muy conveniente cuando se trabaja con grandes cantidades ya que ahorra tiempo en el montaje de los dispositivos.
|
|||
|
|
|||
|
El programa de inicializaci<63>n del AT91RM9200 (se ejecuta si el pin BMS se encuentra en un valor l<>gico alto) busca una secuencia de 8 vectores de excepci<63>n ARM v<>lidos en la DataFlash conectada al puerto SPI, en una EEPROM conectada a la interfaz I2C o en una memoria de 8 bits conectada a la interfaz de bus externo (EBI), estos vectores deben ser instrucciones LDR o Bbranch, menos la sexta instrucci<63>n (posici<63>n 14 a 17) que contiene informaci<63>n sobre el tama<6D>o de la im<69>gen (en bytes) a descargar y el tipo de dispositivo DataFlash. Si la secuencia es encontrada, el c<>digo es almacenado en la memoria SRAM interna y se realiza un remap (con lo que la memoria interna SRAM es accesible en la posici<63>n 0x0 ver Figura \ref{soc_boot_remap}).
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/soc_boot_remap} \end{center}
|
|||
|
\caption{Diagrama de flujo del programa de inicializaci<63>n del SoC AT91RM9200} \label{soc_boot_remap}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Si no se encuentra la secuencia de vectores ARM, se inicializa un programa que configura el puerto serial de depuraci<63>n (DBGU) y el puerto USB Device. Quedando en espera de la descarga de una aplicaci<63>n a trav<61>s del protocolo DFU (Digital Firmware Upgrade) por el puerto USB o con el protocolo XMODEM en el puerto DBGU. La figura \ref{soc_boot_proc} muestra el diagrama de flujo del programa de inicializaci<63>n del SoC AT91RM9200
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/soc_boot_proc} \end{center}
|
|||
|
\caption{Diagrama de flujo del programa de inicializaci<63>n del SoC AT91RM9200} \label{soc_boot_proc}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
El programa descargado a la memoria SRAM interna debe ser capaz de programar una memoria no vol<6F>til (La Flash DataFlash SPI para el ECBOT), debe proporcionar un canal de comunicaci<63>n que permita descargar ejecutables m<>s grandes, y debe inicializar el controlador de memoria SDRAM para que almacene temporalmente el ejecutable a grabar, esto es necesario ya que la memoria interna del AT91RM9200 solo es de 16kBytes. M<>s adelante hablaremos detalladamente de la aplicaci<63>n que realiza estas funciones.
|
|||
|
|
|||
|
|
|||
|
\subsection{Interfaz JTAG}
|
|||
|
A mediados de los 1970s, la estructura de pruebas para tarjetas de circuito impreso (PCB, Printed Circuit Boards) se basaba en el uso de la t<>cnica ``bed-of-nails''. Este m<>todo hacia uso de un dispositivo que conten<65>a una serie de puntos de prueba, que permit<69>an el acceso a dispositivos en la tarjeta a trav<61>s de puntos de prueba colocados en la capa de cobre, o en otros puntos de contacto convenientes. Las pruebas se realizaban en dos fases: La prueba del circuito apagado y la prueba del circuito funcionando. Con la aparici<63>n de los dispositivos de montaje superficial se empez<65> a colocar dispositivos en las dos caras de la tarjeta, debido a que las dimensiones de los dispositivos de montaje superficial son muy peque<75>as, se disminuy<75> la distancia f<>sica entre las interconexiones, dificultando el proceso de pruebas.
|
|||
|
|
|||
|
A mediados de los 1980s un grupo de ingenieros de pruebas miembros de compa<70><61>as electr<74>nicas Europeas se reunieron para examinar el problema y buscar posibles soluciones. Este grupo se autodenomin<69> JETAG (Joint European Test Action Group). El m<>todo de soluci<63>n propuesto por ellos estaba basado en el concepto de un registro de corrimiento serial colocado alrededor de la frontera dispositivo, de aqu<71> el nombre ?Boundary Scan?. Despu<70>s el grupo se asoci<63> a compa<70><61>as norteamericanas y la ``E'' de ``European'' desapareci<63> del nombre de la organizaci<63>n convirti<74>ndose en JTAG (Join Test Action Group).
|
|||
|
|
|||
|
\subsubsection{Arquitectura BOUNDARY SCAN}
|
|||
|
A cada se<73>al de entrada o salida se le adiciona un elemento de memoria multi-prop<6F>sito llamado ``Boundary Scan Cell'' (BSC). Las celdas conectadas a los pines de entrada reciben el nombre de ``Celdas de entrada'', y las que est<73>n conectadas a los pines de salida ``Celdas de salida''. En la Figura \ref{jtag_basics} se muestra esta arquitectura.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/jtag_basics} \end{center}
|
|||
|
\caption{Arquitectura Boundary Scan} \label{jtag_basics}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Las BSC se configuran en un registro de corrimiento de entrada y salida paralela. Una carga paralela de los registros (captura) ocasiona que los valores de las se<73>ales aplicadas a los pines del dispositivo pasen a las celdas de entrada y que opcionalmente los valores de las se<73>ales internas del dispositivo pasen a las celdas de salida. Una descarga paralela (Actualizaci<63>n) ocasiona que los valores presentes en las celdas de salida pasen a los pines del dispositivo, y opcionalmente los valores almacenados en las celdas de entrada pasen al interior del dispositivo.
|
|||
|
|
|||
|
Los datos pueden ser corridos a trav<61>s del registro de corrimiento, de forma serial, empezando por un pin dedicado TDI (Test Data In) y terminando en un pin de salida dedicado llamado TDO (Test Data Out). La se<73>al de reloj se proporciona por un pin externo TCLK (Test Clock) y el modo de operaci<63>n se controla por la se<73>al TMS (Test Mode Select). Los elementos del Boundary Scan no afectan el funcionamiento del dispositivo. Y son independientes del n<>cleo l<>gico del mismo.
|
|||
|
|
|||
|
\subsubsection{Instrucciones JTAG}
|
|||
|
El Standard IEEE 1149.1 describe tres instrucciones obligatorias: Bypass, Sample/Preload, y Extest \cite{TI96}.
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{BYPASS} Esta instrucci<63>n permite que el chip permanezca en un modo funcional, hace que el registro de Bypass se coloque entre TDI y TDO; permitiendo la transferencia serial de datos a trav<61>s del circuito integrado desde TDI hacia TDO sin afectar la operaci<63>n. La codificaci<63>n en binario para esta instrucci<63>n debe ser con todos los bits en uno.
|
|||
|
|
|||
|
\item \textbf{SAMPLE/PRELOAD} Esta instrucci<63>n selecciona el registro Boundary-Scan para colocarse entre los terminales TDI y TDO. Durante esta instrucci<63>n, el registro Boundary-Scan puede ser accesado a trav<61>s de la operaci<63>n Data Scan, para tomar una muestra de los datos de entrada y salida del chip. Esta instrucci<63>n tambi<62>n se utiliza para precargar los datos de prueba en el registro Boundary-Scan antes de ejecutar la instrucci<63>n EXTEST. La codificaci<63>n de esta instrucci<63>n la define el fabricante.
|
|||
|
|
|||
|
\item \textbf{EXTEST} Esta instrucci<63>n coloca al circuito integrado en modo de test externo (pruebas de la interconexi<78>n) y conecta el regsitro Boundary-Scan entre TDI y TDO. Las se<73>ales que salen del circuito son cargadas en el registro boundary-scan en el flanco de bajada de TCK en el estado Capture-DR; las se<73>ales de entrada al dispositivo son cargadas al registro boundary-scan durante el flanco de bajada de TCK en el estado Update-DR (ver Figura \ref{jtag_sm}) . La codificaci<63>n para esta instrucci<63>n est<73> definida con todos los bits en cero.
|
|||
|
|
|||
|
\item \textbf{INTEST} La instrucci<63>n opcional INTEST tambi<62>n selecciona el registro boundary-scan, pero es utilizado para capturar las se<73>ales que salen del n<>cleo l<>gico del dispositivo, y para aplicar valores connocidos a las se<73>ales de entrada del n<>cleo. La codificaci<63>n para esta se<73>al es asignada por el dise<73>ador.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.8]{./images/jtag_sm} \end{center}
|
|||
|
\caption{Arquitectura Boundary Scan} \label{jtag_sm}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Depuraci<63>n del core ARM \cite{DR05}}
|
|||
|
|
|||
|
Todos los nucleos ARM7 y ARM9 poseen soporte de depuraci<63>n en modo halt, lo que permite detener por competo el n<>cleo. Durante este estado es posible modificar y capturar las se<73>ales del n<>cleo, permitiendo cambiar y examinar el core y el estado del sistema. En este estado la fuente de reloj del core es el reloj de depuraci<63>n (DCLK) que es generado por la l<>gica de depuraci<63>n. Los n<>cleos ARM7 y ARM9 implementan un controlador compatible con JTAG, con dos cadena boundary-scan alrededor de las se<73>ales del core, una con las se<73>ales del core, para pruebas del dispositivo y la otra es un sub-set de la primera con se<73>ales importantes para la depuraci<63>n. La Figura \ref{arm_scan1} muestra el orden de las se<73>ales en las cadenas para los n<>cleos ARM7TDMI y ARM9TDMI. Para pop<6F>sitos de depuraci<63>n es suficiente la cadena 1. Esta cadena puede ser utilizada en modo INTEST, permitiendo capturar las se<73>ales del core y aplicar vectores al mismo, o en modo EXTEST, permitiendo la salida y entrada de informaci<63>n hacia y desde exterior del core respectivamente.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/arm_scan1} \end{center}
|
|||
|
\caption{Cadena Boundary Scan 1} \label{arm_scan1}
|
|||
|
\end{figure}
|
|||
|
Las se<73>ales D[0:31] del ARM7TDMI est<73>n conectadas al bus de datos del n<>cleo y se utiliza para capturar instrucciones o lectura/escritura de informaci<63>n; la se<73>al BREAKPT se utiliza para indicar que la instrucci<63>n debe ejecutarse a la velocidad del sistema, esto es, utilizando el reloj MCLK en lugar de DCLK.
|
|||
|
|
|||
|
Las se<73>ales ID[0:31] del ARM9TDMI est<73>n conectadas al bus de instrucciones y se utilizan para capturar instrucciones, las se<73>ales DD[31:0] est<73>n conectadas al bus de dtaos bi-direccional y se utilizan para leer o escribir informaci<63>n.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/arm_scan2} \end{center}
|
|||
|
\caption{Cadena Boundary Scan 2 (Embedded ICE)} \label{arm_scan2}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Los ARM7 y ARM9 poseen un m<>dulo ICE (In Circuit Emulator) que reemplaza el microcontrolador con una variaci<63>n que posee facilidades para la depuraci<63>n hardware. El emulador es conectado a un computador que ejecuta el software de depuraci<63>n. Esto permite realizar depuraci<63>n activa y pasiva, dando un punto de vista no intrusivo del flujo del programa. La Figura \ref{arm_scan2} muestra la cadena scan ICE, que es la misma para los n<>cleos ARM7 y ARM9, esta formada por 32 bits de datos, 5 bits de direcciones y un flag para diferenciar entre lectura (nRW bajo) y escritura. Se puede acceder a las caracter<65>sticas ICE a trav<61>s de registros, cuya direcci<63>n es colocada en el bus de direcciones.
|
|||
|
|
|||
|
El proyecto OPENOCD (Open On-Chip Debugger \footnote{http://openocd.berlios.de/web/}) permite la programaci<63>n de la memoria flash interna de algunos procesadores ARM7TDMI, y la depuraci<63>n de procesadores ARM7 y ARM9 utilizndo el m<>dulo ICE. Este proyecto se ha convertido en el m<>s popular dentro del grupo de desarrolladores de sistemas Embebidos. En \cite{DR05} se puede encontrar el funcionamiento interno de esta herramienta.
|
|||
|
|
|||
|
\subsubsection{Programaci<63>n de memorias Flash}
|
|||
|
Algunos SoC no poseen programas de inicializaci<63>n que permitan la descarga de aplicaciones ya sea a las memorias externas o a la interna, una soluci<63>n podr<64>a ser utilizar el protocolo JTAG para cargar las aplicaciones en la RAM interna, sin embargo, existen procesadore en los que no se conocen las espcificaciones del ICE y en en otros este m<>dulo no existe. En estos casos se utiliza la interfaz JTAG en modo EXTEST para controlar directamente las memorias conectadas a los SoCs. El proyecto UrJTAG, \footnote{http://urjtag.sourceforge.net/} permite la programaci<63>n de diversas memorias flash, utilizando los pines del dispositivo. UrJTAG permite la creaci<63>n de diferentes interfaces para conectarse con las memorias, estas interfaces reciben el nombre de buses y pueden ser creadas e incluidas en el c<>digo original de forma f<>cil.
|
|||
|
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION LINUX
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
|
|||
|
\section{El sistema Operativo Linux}
|
|||
|
\textit{Hello everybody out there using minix -
|
|||
|
I'm doing a (free) operating system (just a hobby, won't be big and
|
|||
|
professional like gnu) for 386(486) AT clones.
|
|||
|
}
|
|||
|
|
|||
|
Con este mail enviado al foro de discusi<73>n comp.os.minix, Linus Torvalds, un estudiante de la Universidad de Helsinki en Finlandia introduce Linux el 25 de Agosto de 1991. A principios de los 90, el sistema operativo Unix (desarrollado en \textit{The Bell Labs} a principios de los 60s), ten<65>a una solida posici<63>n en el mercado de servidores, y estaba muy bien posicionado en las Universidades, por lo tanto, un gran n<>mero de estudiantes trabajaban a diario con <20>l y muchos de ellos deseaban poder utilizarlo en sus computadores personales, sin embargo, Unix era un producto comercial muy costoso. La
|
|||
|
figura \ref{linuxhistory} muestra el desarrollo previo a la creaci<63>n de la primera versi<73>n de linux hasta el d<>a de hoy. Una de las caracter<65>sticas m<>s importantes de Linux es que desde su creaci<63>n, fue pensado como un sistema operativo gratuito y de libre distribuci<63>n. Esta caracter<65>stica ha permitido que programadores a lo largo del mundo puedan manipular el c<>digo fuente para eliminar errores y para aumentar sus capacidades.
|
|||
|
|
|||
|
Sin embargo, el cr<63>dito de las que conocemos hoy (Debian, Ubuntu, Suse, etc) no solo se debe a Torvalds, ya que linux es solo el kernel del sistema operativo. En 1983, Richard Stallman funda en proyecto GNU, el cual proporciona una parte esencial de los sistemas linux. A principios de los 90s, GNU hab<61>a producido una serie de herramientas como librer<65>as, compiladores, editores de texto, Shells, etc. Estas herramientas fueron utilizadas por Torvalds para escribir el elemento que le hac<61>a falta al proyecto GNU para completar su sistema operativo: el kernel.
|
|||
|
|
|||
|
Desde el lanzamiento de la primera versi<73>n de linux, cientos, miles, cientos de miles y millones de programadores se han puesto en la tarea de convertir a linux en un sistema operativo robusto, amigable y actualizado; tan pronto como se desarrolla una nueva pieza de hardware existen cientos de programadores trabajando en crear el soporte para linux.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.5]{./images/linuxhistory} \end{center}
|
|||
|
\caption{Linux: Historia Fuente.}\label{linuxhistory}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
\subsubsection{Porqu<71> Linux}
|
|||
|
Existen varias motivaciones para escoger Linux frente a un sistema oeprativo tradicional para sistemas embebidos \cite{KYJM+08}:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Calidad Y confiabilidad del c<>digo}: Aunque estas medidas son subjetivas, miden el nivel de confianza en el c<>digo, que compromete software como el kernel y las aplicacione proporcionadas por las distribuciones.
|
|||
|
\item \textbf{Disponibilidad de C<>digo:} Todo el c<>digo fuente de las aplicaciones, del sistema operativo y de las herramientas de compilaci<63>n se encuentran disponibles sin ninguna restricci<63>n. Existen varios tipos de licencias: la GNU General Public License (GPL). BSD (Berkeley Software Distribution), la cual permite la distribuci<63>n de binarios sin el c<>digo fuente.
|
|||
|
\item \textbf{Soporte de Hardware:} Linux soporta una gran variedad de dispositivos y plataformas, a pesar de que muchos fabricantes no proporcionan soporte para Linux, la comunidad trabaja arduamente en incluir el nuevo hardware en las nuevas distribuciones de Linux. Linux en la actualidad se puede ejecutar en docenas de diferentes arquitecturas hardware, lo cual lo convierte en el Sistema Operativo m<>s portable.
|
|||
|
\item \textbf{Protocolos de Comunicaci<63>n y est<73>ndares de Software:} Linux proporciona muchos protocolos de comunicaci<63>n, lo que permite su f<>cil integraci<63>n a marcos de trabajo ya existentes.
|
|||
|
\item \textbf{Disponibilidad de Herramientas:} La variedad de herramientas disponibles para Linux lo hacen muy vers<72>til. Existen grandes comunidades como SourceForge\footnote{http://www.sourceforge.net} o Freshmeat \footnote{http://www.freshmeat.net} que permiten a miles de desrroladores compartir sus trabajos y es posible que en ellas se encuentre una aplicaci<63>n que cumpla con sus necesidades.
|
|||
|
\item \textbf{Soporte de la Comunidad:} Esta es la principal fortaleza de Linux. Millones de usuarios alrededor del mundo pueden encontrar errores en alguna aplicaci<63>n y desarrolladores miembros de la cumonidad (en algunos casos los creadores de las aplicaciones) arreglar<61>n este problema y difundir<69>n su soluci<63>n. El mejor sitio para hacer esto son las listas de correo de soporte y desarroll.
|
|||
|
\item \textbf{Licencia:} Al crear una aplicaci<63>n bajo alguna de las licencias usuales en Linux, no implica perder la porpiedad intelectual ni los derechos de autor la misma.
|
|||
|
\item \textbf{Independencia del vendedor:} No existe solo un distribuidor del sistema operativo GNU-Linux, ya que las licencias de Linux garantizan igualdad a los distribuidores. Algunos vendedores poporcionan aplicaciones adicionales que no son libres y pro lo tanto no se encuentran disponibles con otros vendedores. Esto debe tenerse en cuenta en el momento de elegir la distribuci<63>n a utilizar.
|
|||
|
\item \textbf{Costo:} Muchas de las herramientas de deasrrollo y componentes de Linux son gratuitos, y no requieren el pago por ser incluidos en productos comerciales.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\subsection{Arquitectura de Linux \cite{IBSS98} \cite{IB98}}
|
|||
|
|
|||
|
Linux (Linus' Minix) es un clon del sistema operativo Unix para PC con procesador Intel 386. Linux toma dos caracter<65>sticas muy importantes de Unix: es un sistema multitarea y multiusuario, lo cual fue implementado posteriormente por los sistemas operativos Windows y MacOS. Con estas caracter<65>sticas es posible ejecutar tareas de forma independiente, y transparente para el/los usuarios.
|
|||
|
|
|||
|
Linux est<73> compuesto por cinco sub-m<>dulos \cite{IB98}: El programador (Scheduler), el manejador de memoria, el sistema de archivos virtual, la interfaz de red y la comunicaci<63>n entre procesos (IPC). Tal como se ilustra en la figura \ref{linux_kernel}.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.55]{./images/kernel} \end{center}
|
|||
|
\caption{Estructura del kernel de linux }\label{linux_kernel}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Como puede observarse en la figura \ref{linux_kernel} el kernel de linux posee sub-m<>dulos que son independientes de la arquitectura y otros que deben ser escritos para el procesador utilizado, esto hace que Linux sea un sistema operativo portable. En la actualidad existe una gran variedad de arquitecturas soportadas por linux, entre las que se encuentran:
|
|||
|
|
|||
|
alpha arm26 frv i386 m32r m68knommu parisc ppc64 sh sparc um x86\_64
|
|||
|
arm cris h8300 ia64 m68k mips ppc s390 sh64 sparc64 v850
|
|||
|
|
|||
|
Las funciones de estos componentes se describen a continuaci<63>n \cite{IBSS98}:
|
|||
|
|
|||
|
\subsubsection*{Programador de procesos (Scheduler)}
|
|||
|
|
|||
|
Es el coraz<61>n del sistema operativo linux. Esta encargado de realizar las siguientes tareas:
|
|||
|
\begin{itemize}
|
|||
|
\item Permitir a los procesos hacer copias de si mismos.
|
|||
|
\item Determinar que procesos pueden acceder a la CPU y efectuar la transferencia entre los procesos en ejecuci<63>n.
|
|||
|
\item Recibir interrupciones y llevarlas al subsistema del kernel adecuado.
|
|||
|
\item Enviar se<73>ales a los procesos de usuario.
|
|||
|
\item Manejar el timer f<>sico.
|
|||
|
\item Liberar los recursos de los procesos, cuando estos finalizan su ejecuci<63>n.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
El programador de procesos proporciona dos interfaces: Una limitada para los procesos de usuario y una interfaz amplia para el resto del kernel. El scheduler de Linux utiliza una interrupci<63>n del timer que se presenta cada 10 ms, por lo tanto, el cambio de estado del programador se realiza cada 10 ms. Esto debe ser tenido en cuenta a la hora de realizar procesos que manejen dispositivos hardware veloces. Un proceso puede estar en uno de los siguientes estados:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item En ejecuci<63>n.
|
|||
|
\item Retornando de un llamado de sistema.
|
|||
|
\item Procesando una rutina de interrupci<63>n.
|
|||
|
\item Procesando un llamado del sistema.
|
|||
|
\item Listo.
|
|||
|
\item En espera.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\subsubsection*{Manejador de Memoria}
|
|||
|
|
|||
|
|
|||
|
En el momento en que se energiza la CPU, esta solo ve 1-MB de memoria f<>sica (Incluyendo las ROMs). El c<>digo de inicializaci<63>n del Sistema Operativo debe activar el modo protegido del procesador, de tal forma que la memoria Extendida (incluyendo la memoria de los dispositivos) sea accesible. Finalmente el OS habilita la memoria virtual para permitir la ilusi<73>n de un espacio de memoria de 4 GB. El manejador de memoria proporciona los siguientes servicios (ver figuras \ref{kernel_mapping} y \ref{app_mapping}):
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Gran espacio de memoria}. Los procesos usuario, pueden referenciar m<>s memoria que la existente f<>sicamente.
|
|||
|
\item \textbf{Protecci<63>n} La memoria de un proceso es privada y no puede ser le<6C>da o modificada por
|
|||
|
otro proceso. Adicionalmente evita que los procesos sobreescriban datos de solo
|
|||
|
lectura.
|
|||
|
\item \textbf{Mapeo de memoria} Los usuarios pueden mapear un archivo en un <20>rea de memoria virtual
|
|||
|
y accesar el archivo como una memoria.
|
|||
|
\item \textbf{Acceso transparente a la memoria f<>sica} esto asegura un buen desempe<70>o del sistema.
|
|||
|
\item \textbf{Memoria compartida}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
Al igual que el programador el manejador de memoria proporciona dos diferentes niveles de acceso a memoria el nivel de usuario y el de kernel.
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Nivel de Usuario
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{malloc() / free()}. Asigna o libera memoria para que sea utilizada por un proceso.
|
|||
|
\item \textit{mmap() / munmap() / msync() /mremap()} Mapea archivos en regiones de memoria virtual.
|
|||
|
\item \textit{mprotect} Cambia la protecci<63>n sobre una regi<67>n de una memoria virtual.
|
|||
|
\item \textit{mlock() / mlockall() / munlock() / munlockall()} Rutinas que permiten al super
|
|||
|
usuario prevenir el intercambio de memoria.
|
|||
|
\item \textit{swapon() / swapoff()} Rutinas que le permiten al super-usuario agregar o eliminar
|
|||
|
archivos swap en el sistema.
|
|||
|
\end{itemize}
|
|||
|
\item Nivel de kernel
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{kmalloc() / kfree()} Asigna o libera memoria para que sea utilizada por estructuras de
|
|||
|
datos del kernel.
|
|||
|
\item \textit{verify\_area()} Verifica que una regi<67>n de la memoria de usuario ha sido mapeada con
|
|||
|
los permisos necesarios.
|
|||
|
|
|||
|
\item \textit{get\_free\_page() / free\_page()} Asigna y libera p<>ginas de memoria f<>sica.
|
|||
|
\end{itemize}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.45]{./images/kernel_memory_mapping} \end{center}
|
|||
|
\caption{Mapeo de memoria del Kernel.}\label{kernel_mapping}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.45]{./images/application_memory_mapping1} \end{center}
|
|||
|
\caption{Mapeo de memoria para una aplicaci<63>n}\label{app_mapping}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
|
|||
|
\subsubsection*{Comunicaci<63>n Entre Procesos (IPC)}
|
|||
|
|
|||
|
El mecanismo IPC de Linux posibilita la ejecuci<63>n \textit{concurrente} de procesos, permitiendo compartir recursos, la sincronizaci<63>n e intercambio de datos entre ellos. Linux proporciona los siguientes mecanismos:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Se<53>ales} Mensajes as<61>ncronos enviados a los procesos.
|
|||
|
\item \textbf{Listas de espera} Proporciona mecanismos para colocar a dormir a los procesos mientras
|
|||
|
esperan que una operaci<63>n se complete, o un recurso se libere.
|
|||
|
\item \textbf{Bloqueo de archivos} Permite a un proceso declarar una regi<67>n de un archivo como solo
|
|||
|
lectura para los dem<65>s procesos.
|
|||
|
\item \textbf{Conductos (pipe)} Permite transferencias bi-direccionales entre dos procesos.
|
|||
|
\item \textbf{System V}
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Sem<65>foros} Una implementaci<63>n del modelo cl<63>sico del sem<65>foro.
|
|||
|
\item \textbf{Lista de Mensajes} Secuencia de bytes, con un tipo asociado, los mensajes son
|
|||
|
escritos a una lista de mensajes y pueden obtenerse leyendo esta lista.
|
|||
|
\item \textbf{Memoria Compartida} Mecanismo por medio del cual varios procesos tienen acceso a la
|
|||
|
misma regi<67>n de memoria f<>sica.
|
|||
|
\end{itemize}
|
|||
|
\item \textbf{Sockets del dominio Unix} Mecanismo de transferencia de datos orientada a la conexi<78>n.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
\subsubsection*{Interfaces de Red}
|
|||
|
|
|||
|
Este sistema proporciona conectividad entre m<>quinas, y un modelo de comunicaci<63>n por sockets. Se proporcionan dos modelos de implementaci<63>n de sockets: BSD e INET. Adem<65>s, proporciona dos protocolos de transporte con diferentes modelos de comunicaci<63>n y calidad de servicio: El poco confiable protocolo UDP (\textit{User Datagram Protocol}) y el confiable TCP (\textit{Transmission Control Protocol}), este <20>ltimo garantiza el env<6E>o de los datos y que los paquetes ser<65>n entregados en el mismo orden en que fueron enviados. Se proporcionan tres tipos diferentes de conexi<78>n: SLIP (Serial), PLIP (paralela) y ethernet.
|
|||
|
|
|||
|
\subsubsection*{Sistema de archivo virtual}
|
|||
|
El sistema de archivos de linux cumple con las siguientes tareas:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Controlar m<>ltiples dispositivos hardware}
|
|||
|
\item \textbf{Manejar sistemas de archivos l<>gicos}
|
|||
|
\item \textbf{Soporta diferentes formatos ejecutables} Por ejemplo a.out, ELF, java)
|
|||
|
\item \textbf{Homogeneidad} Proporciona una interfaz com<6F>n a todos los dispositivos l<>gicos o f<>sicos.
|
|||
|
\item \textbf{Desempe<70>o}
|
|||
|
\item \textbf{Seguridad}
|
|||
|
\item \textbf{Confiabilidad}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsubsection{Drivers de Dispositivos}
|
|||
|
La capa manejador de dispositivos es responsable de presentar una interfaz com<6F>n a todos los dispositivos f<>sicos. El kernel de Linux tiene 3 tipos de controladores de dispositivo: Caracter (acceso secuencial), bloque (acceso en m<>ltiplos de tama<6D>o de bloque) y red. Ejemplos de controladores secuenciales son el modem, el mouse; ejemplos de controladores tipo bloque son los dispositivos de almacenamiento masivo como discos duros, memorias SD. Los manejadores de dispositivos soportan las operaciones de archivo, y pueden ser tratados como tal.
|
|||
|
|
|||
|
\subsubsection{Sistema de Archivos l<>gico}
|
|||
|
Aunque es posible acceder a dispositivos f<>sicos a trav<61>s de un archivo de dispositivo, es com<6F>n acceder a dispositivos tipo bloque utilizando un sistema de arcvhivos l<>gico, el que puede ser montado en un punto del sistema de archivos virtual.
|
|||
|
|
|||
|
Para dar soporte al sistema de archivos virtual, Linux utiliza el concepto de \textit{inodes}. Linux usa un inode para representar un archivo sobre un dispositivo tipo bloque. El inode es virtual en el sentido que contiene operaciones que son implementadas diferentemente dependiendo de el sistema l<>gico y del sistema f<>sico donde reside el archivo. La interfaz inode hace que todos los archivos se vean igual a otros subsistemas Linux. El inode se utiliza como una posici<63>n de almacenamiento para la informaci<63>n relacionada con un archivo abierto en el disco. El inode almacena los buffers asociados, la longitud total del archivo en bloques, y el mapeo entre el offset del archivo y los bloques del dispositivo.
|
|||
|
|
|||
|
\subsubsection{M<>dulos}
|
|||
|
|
|||
|
La mayor funcionalidad del sistema de archivos virtual se encuentra disponible en la forma de m<>dulos cargados din<69>micamente. Esta cconfiguraci<63>n din<69>mica permite a los usuarios de Linux compilar un kernel tan peque<75>o como sea posible, mientras permite cargar el manejador del dispositivo y m<>dulos del sistema de archivos si solo son necesarios durante una sesi<73>n. Esto es <20>til en el caso de los dispositivos que se pueden conectar en caliente, como por ejemplo un scanner, si tenemos el manejador del scanner cragado a<>n sin que este este conectado a nuestro equipo se esta desperdiciando la memoria asociada a dicho controlador.
|
|||
|
|
|||
|
|
|||
|
\subsubsection*{Interfaces de Red}
|
|||
|
|
|||
|
Este sistema proporciona conectividad entre m<>quinas, y un modelo de comunicaci<63>n por sockets. Se proporcionan dos modelos de implementaci<63>n de sockets: BSD e INET. Adem<65>s, proporciona dos protocolos de transporte con diferentes modelos de comunicaci<63>n y calidad de servicio: El poco confiable protocolo UDP (\textit{User Datagram Protocol}) y el confiable TCP (\textit{Transmission Control Protocol}), este <20>ltimo garantiza el env<6E>o de los datos y que los paquetes ser<65>n entregados en el mismo orden en que fueron enviados. Se proporcionan tres tipos diferentes de conexi<78>n: SLIP (Serial), PLIP (paralela) y ethernet.
|
|||
|
|
|||
|
|
|||
|
\section{Portando Linux a la plataforma ECBOT y ECB\_AT91}
|
|||
|
Como vimos anteriormente el kernel de Linux es el coraz<61>n del sistema operativo GNU/Linux y es el encargado de manejar directamente el Hardware asociado a una determinada plataforma, por lo tanto, es necesario que este sea cap<61>z de manejar todos los perif<69>ricos asociados a esta y proporcione caminos para controlarlos. En esta secci<63>n se describir<69> el proceso que debe realizarse para hacer que Linux se ejecute de forma correcta en una plataforma y que permita controlar sus diferentes componentes hardware (este proceso recibe el nombre de \textit{Porting}).
|
|||
|
|
|||
|
\subsection{El Kernel de Linux}
|
|||
|
El c<>digo fuente se encuentra dividido entre el c<>digo espec<65>fico a una arquitectura y el c<>digo com<6F>n. El c<>digo espec<65>fico de cada arquitectura lo encontramos en los subdirectorios \textit{arch} y \textit{include/asm-xxx}, en ellos podemos encuentrar los archivos para las arquitecturas: alpha, blackfin, h8300, m68k, parisc, s390, sparc, v850, arm, cris, ia64, m68knommu, powerpc, sh, sparc64, x86,
|
|||
|
avr32, frv, m32r, mips, ppc, sh64, um, xtensa. A continuaci<63>n se listan los directorios que hacen parte sdel c<>digo fuente de Linux.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
arch fs lib net block
|
|||
|
usr include crypto ipc scripts
|
|||
|
Documentation mm security drivers kernel
|
|||
|
sound
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Dentro de cada arquitectura soportada por Linux (\textit{arch/xxx/}) encontramos los siguientes directorios:
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{kernel} C<>digo del n<>cleo del kernel.
|
|||
|
\item \textbf{mm} C<>digo para el manejo de memoria.
|
|||
|
\item \textbf{lib} Librer<65>a de funciones internas, optimizadas para la arquitectura (backtrace, memcpy, funciones I/O, bit-twiddling etc);
|
|||
|
\item \textbf{nwfpe} Implementaciones de punto flotante.
|
|||
|
\item \textbf{boot} Sition donde reside la im<69>gen del kernel una vez compilado, este directorio contiene herramientas para generar im<69>genes comprimidas.
|
|||
|
\item \textbf{tools} Contiene scripts para la autogeneraci<63>n de archivos, tambi<62>n contiene el archivo \textit{mach-types} que contiene la lista de las m<>quinas (plataformas) registradas.
|
|||
|
\item \textbf{configs} Contiene el archivo de configuraci<63>n para cada plataforma.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
Si deseamos dar soporte a una determinada plataforma debemos trabajar en el directorio que contiene la arquitectura del procesador a utilizar, en nuestro caso trabajaremos con la arquitectura \textit{arm}. En el c<>digo fuente de Linux se encuentran muchas plataformas que utilizan las diferentes architecturas, los archivos de configuraci<63>n de estas pueden ser utilizados para crear una propia. En nuestro caso tomamos como referenica la plataforma \textit{Atmel AT91RM9200-EK} dise<73>ada por ATMEL. Los archivos de configuraci<63>n de esta plataforma se encuentra en: \textit{arch/arm/mach-at91/board-ek.c}; dentro de la arquitectura arm existen varias sub-arquitecturas que corresponden a las diferentes familias de SoC; El AT91RM9200 hace parte de la familia de SoCs AT91 de ATMEL.
|
|||
|
|
|||
|
Existen dos formas en las que podemos adaptar nuestra plataforma al kernel de Linux, la primera es utilizando un archivo de configuraci<63>n de una plataforma existente, y la otra es registrar la nuestra. Cada plataforma es identificada por un \textit{machine ID}, el primero paso en el proceso de \textit{port} es obter un ID, lo cu<63>l se puede hacer en l<>nea: \textit{http://www.arm.linux.org.uk/developer/machines/}, mientras que se asigna un nuevo n<>mero puede asignarse uno que no este utilizado en el archivo: \textit{arch/arm/tools/mach-types}. La entrada correspondiente a la familia de plataformas ECBACT91 es:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
ecbat91 MACH_ECBAT91 ECBAT91 1072
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Con este ID (o uno temporal) se debe crear la siguiente entrada en el archivo \textit{/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig}:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
config MACH_ECBAT91
|
|||
|
bool "emQbit ECB_AT91 SBC"
|
|||
|
depends on ARCH_AT91RM9200
|
|||
|
help
|
|||
|
Select this if you are using emQbit's ECB_AT91 board.
|
|||
|
<http://wiki.emqbit.com/free-ecb-at91>
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La que permite seleccionar nuestra plataforma desde el programa de configuraci<63>n de Linux\footnote{este programa se ejecuta con el comando: \textit{make ARCH=arm CROSS\_COMPILE=arm-none-eabi-}}(Ver Figura \ref{ecb_at91_linux_config})
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.45]{./images/ecb_at91_linux_config} \end{center}
|
|||
|
\caption{Herramienta de configuraci<63>n de Linux mostrando la plataforma ECB\_AT91}\label{ecb_at91_linux_config}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Al seleccionar nuestra plataforma el programa de configuraci<63>n crear<61> un archivo de configuraci<63>n \textit{.config \footnote{los archivos que comienzan con ``.'' est<73>n ocultos}} localizado en la ra<72>z del c<>digo fuente, este archivo refleja las selecciones realizadas para configurar la imagen del kernel; en este caso espec<65>fico se agragar<61> la l<>nea:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
CONFIG_MACH_ECBAT91=y
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como veremos m<>s adelante, la aplicaci<63>n encargada de cargar la im<69>gen del kernel de Linux le pasa a este el n<>mero de identificaci<63>n de la plataforma, si este n<>mero no es el mismo que el kernel tiene registrado se generar<61> un error, para evitar esto debemos incluir las siguientes l<>neas en el archivo \textit{arch/arm/boot/compressed/head-at91rm9200.S}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
@ emQbit ECB_AT91 : 1072
|
|||
|
mov r3, #(MACH_TYPE_ECBAT91 & 0xff)
|
|||
|
orr r3, r3, #(MACH_TYPE_ECBAT91 & 0xff00)
|
|||
|
cmp r7, r3
|
|||
|
beq 99f
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
El archivo \textit{/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile} contiene una relaci<63>n entre la plataforma seleccionada y el archivo de compilaci<63>n a utilizar, por lo que debemos incluir las siguientes l<>neas:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
obj-$(CONFIG_MACH_ECBAT91) += board-ecbat91.o
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Con esto asignamos el archivo de configuraci<63>n \textit{board-ecbat91.c} a la plataforma \textit{MACH\_ECBAT91}.
|
|||
|
|
|||
|
\subsubsection{Archivo de configuraci<63>n de la plataforma ECB\_AT91 }
|
|||
|
En esta secci<63>n realizaremos una descripci<63>n del archivo de configuraci<63>n de la familia de plataformas \textit{ECB\_AT91} (\textit{board-ecbat91.c}) y se har<61> una explicaci<63>n de cada uno de los par<61>metros de este archivo.
|
|||
|
|
|||
|
Como todo archivo escrito en C al comienzo se declaran los encabezados que contienen las funciones utilizadas, en nuestro caso:
|
|||
|
|
|||
|
\begin{lstlisting}[numbers=left]
|
|||
|
#include <linux/types.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/mm.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/dma-mapping.h>
|
|||
|
#include <linux/platform_device.h>
|
|||
|
#include <linux/spi/spi.h>
|
|||
|
#include <linux/spi/flash.h>
|
|||
|
#include <linux/leds.h>
|
|||
|
|
|||
|
#include <asm/hardware.h>
|
|||
|
#include <asm/setup.h>
|
|||
|
#include <asm/mach-types.h>
|
|||
|
#include <asm/irq.h>
|
|||
|
|
|||
|
#include <asm/mach/arch.h>
|
|||
|
#include <asm/mach/map.h>
|
|||
|
#include <asm/mach/irq.h>
|
|||
|
|
|||
|
#include <asm/arch/board.h>
|
|||
|
#include <asm/arch/at91rm9200_mc.h>
|
|||
|
#include <asm/arch/gpio.h>
|
|||
|
#include <linux/gpio_keys.h>
|
|||
|
#include <linux/input.h>
|
|||
|
|
|||
|
#include "generic.h"
|
|||
|
#include <asm/arch/at91_pio.h>
|
|||
|
|
|||
|
#include <linux/w1-gpio.h>
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Cada arquitectura (CPU) posee un archivo donde se declaran los diferentes perif<69>ricos que pueden ser utilizados: \textit{arch/arm/mach-at91/at91rm9200\_devices.c} en el caso del procesador AT91RM9200; En <20>l podemos encontrar soporte para: USB Host, USB Device, Ethernet, Compact Flash / PCMCIA, MMC / SD, NAND / SmartMedia, TWI (i2c), SPI, Timer/Counter blocks, RTC, Watchdog, SSC -- Synchronous Serial Controller, UART. Este archivo adem<65>s proporciona funciones que permiten incluir y configurar los diferentes controladores asociados al SoC, adicionalmente realiza las operaciones necesarias para poder utilizarlo, como por ejemplo, definir que el control de un determinado pin este a cargo del perif<69>rico.
|
|||
|
|
|||
|
El primer dispositivo declarado en el archivo de configuraci<63>n es el puerto serial (UART), este puerto es vital ya que es el <20>nico medio de comunicaci<63>n que tenemos con nuestra plataforma.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static struct at91_uart_config __initdata ecb_at91uart_config = {
|
|||
|
.console_tty = 0, /* ttyS0 */
|
|||
|
.nr_tty = 2,
|
|||
|
.tty_map = { 4, 0, -1, -1, -1 } /* ttyS0, ..., ttyS4 */
|
|||
|
};
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Los par<61>metros de configuraci<63>n de la \textit{UART} se declaran utilizando la estructura \textit{at91\_uart\_config} declarada en el archivo \textit{include/asm-arm/arch/board.h}, la variable \textit{console\_tty} define el n<>mero del dispositivo \textit{tty} asociado a la consola serial, \textit{ttyS0} en nuestro caso, la variable \textit{nr\_tty} define el n<>mero de interfaces seriales disponibles \footnote{El AT91RM9200 tiene 4 USARTS y una UART para depuraci<63>n}, \textit{ttyS0} y \textit{ttyS1} en nuestro caso; \textit{tty\_map} realiza la correspondencia entre los dispositivos \textit{tty} y las UART disponibles en el SoC, para este ejemplo asocia \textit{ttyS0} a la \textit{UART4} y \textit{ttyS1} a la \textit{UART0}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static void __init ecb_at91map_io(void)
|
|||
|
{
|
|||
|
/* Initialize processor: 18.432 MHz crystal */
|
|||
|
at91rm9200_initialize(18432000, AT91RM9200_PQFP);
|
|||
|
|
|||
|
/* Setup the LEDs */
|
|||
|
at91_init_leds(AT91_PIN_PB20, AT91_PIN_PB20);
|
|||
|
|
|||
|
/* Setup the serial ports and console */
|
|||
|
at91_init_serial(&ecb_at91uart_config);
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La funci<63>n \textit{at91rm9200\_initialize} declarada en \textit{arch/arm/mach-at91/at91rm9200.c} se encarga, como su nombre lo indica, de inicializar el procesador AT91RM9200, espec<65>ficamente se encarga de configurar, el reloj interno del procesador (con la funci<63>n \textit{at91\_clock\_init}), registra los Osciladores configurables PCK0 a PCK3 (utilizando la funci<63>n \textit{at91rm9200\_register\_clocks}) y finalmente habilita el soporte para los pines de entrada/salida de prop<6F>sito general \textit{GPIOs} (utilizando la funci<63>n \textit{at91\_gpio\_init}). Adicionalmente informa que se est<73> utilizando el empaquetado TQFP208 (Este chip viene en dos versiones TQFP y BGA).
|
|||
|
|
|||
|
Las plataforma que carecen de un dispositivo de visualizaci<63>n como una pantalla, reflejan la actividad de procesos importantes en el estado de diodos emisores de luz LEDs, Linux permite visualizar la actividad de la CPU y el estado de un timer interno (\textit{at91\_init\_leds( cpu\_led, timer\_led)}). Nuestra plataforma utiliza un LED conectado al pin PB20 para estas indicaciones.
|
|||
|
|
|||
|
La funci<63>n \textit{at91\_init\_serial(\&ecb\_at91uart\_config)}, como su nombre lo indica inicializa las interfaces seriales utilizando como configuraci<63>n la estructura \textit{at91\_init\_serial} explicada anteriormente.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static void __init ecb_at91init_irq(void)
|
|||
|
{
|
|||
|
at91rm9200_init_interrupts(NULL);
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La funci<63>n \textit{at91rm9200\_init\_interrupts} inicializa el Controlador de Interrupciones del AT91RM9200 y permite que estas sean atendidas.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static struct at91_usbh_data __initdata ecb_at91usbh_data = {
|
|||
|
.ports = 1,
|
|||
|
};
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La estructra \textit{at91\_usbh\_data} fija el n<>mero de puertos USB host a 1 (El encapsulado TQFP solo tiene un puerto USB host, la versi<73>n BGA tiene 2).
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static struct at91_mmc_data __initdata ecb_at91mmc_data = {
|
|||
|
.slot_b = 0,
|
|||
|
.wire4 = 1,
|
|||
|
};
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
El SoC AT91RM9200 puede manejar dos memorias SD, la variable \textit{slot\_b} determina cual se usa, el slot a en nuestro caso; la variable \textit{wire4} selecciona el n<>mero de l<>neas de datos entre 1 y 4 (\textit{wire4 = 1}).
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#if defined(CONFIG_MTD_DATAFLASH)
|
|||
|
static struct mtd_partition __initdata my_flash0_partitions[] =
|
|||
|
{
|
|||
|
{
|
|||
|
.name = "Darrel-loader", / 0x0
|
|||
|
.offset = 0,
|
|||
|
.size = 12* 1056, // 12672 bytes
|
|||
|
},
|
|||
|
{
|
|||
|
.name = "uboot", // 0x3180
|
|||
|
.offset = MTDPART_OFS_NXTBLK,
|
|||
|
.size = 118 * 1056,
|
|||
|
},
|
|||
|
{
|
|||
|
.name = "kernel", // 0x21840
|
|||
|
.offset = MTDPART_OFS_NXTBLK,
|
|||
|
.size = 1534 * 1056, /* 1619904 bytes */
|
|||
|
},
|
|||
|
{
|
|||
|
.name = "filesystem",
|
|||
|
.offset = MTDPART_OFS_NXTBLK,
|
|||
|
.size = MTDPART_SIZ_FULL,
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
static struct flash_platform_data __initdata my_flash0_platform = {
|
|||
|
.name = "Removable flash card",
|
|||
|
.parts = my_flash0_partitions,
|
|||
|
.nr_parts = ARRAY_SIZE(my_flash0_partitions)
|
|||
|
};
|
|||
|
#endif
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Muchos dispositivos flash est<73>n divididos en secciones que reciben el nombre de particiones, similares a las particiones encontradas en un disco duro. El subsistema MTD proporciona soporte para estas particiones Flash, si esta funci<63>n es seleccionada con la herramienta de configuraci<63>n del kernel (CONFIG\_MTD\_DATAFLASH = y). La familia de plataformas ECB\_AT91 tiene un dispositivo DataFlash serial de 16 Mbits (2Mbytes), en la que creamos 4 particiones, en las que se almacenar<61>n el loader, el u-boot, la imagen del kernel, y el sistema de archivos (En el dispositivo flash actual no hay suficiente espacio para este <20>ltimo). Cada partici<63>n se define con una estructura \textit{mtd\_partition} formada por 3 variables: \textit{name}, \textit{offset} (Direcci<63>n inicial de la partici<63>n) y .\textit{size}.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
|
|||
|
static struct spi_board_info __initdata ecb_at91spi_devices[] = {
|
|||
|
{ /* DataFlash chip */
|
|||
|
.modalias = "mtd_dataflash",
|
|||
|
.chip_select = 0,
|
|||
|
.max_speed_hz = 10 * 1000 * 1000,
|
|||
|
.bus_num = 0,
|
|||
|
.platform_data = &my_flash0_platform,
|
|||
|
},
|
|||
|
{ /* User accessable spi - cs1 (250KHz) */
|
|||
|
.modalias = "spi-cs1",
|
|||
|
.chip_select = 1,
|
|||
|
.max_speed_hz = 250 * 1000,
|
|||
|
},
|
|||
|
{ /* User accessable spi - cs2 (1MHz) */
|
|||
|
.modalias = "spi-cs2",
|
|||
|
.chip_select = 2,
|
|||
|
.max_speed_hz = 1 * 1000 * 1000,
|
|||
|
},
|
|||
|
{ /* User accessable spi - cs3 (10MHz) */
|
|||
|
.modalias = "spi-cs3",
|
|||
|
.chip_select = 3,
|
|||
|
.max_speed_hz = 10 * 1000 * 1000,
|
|||
|
},
|
|||
|
};
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La estructura \textit{spi\_board\_info} define los dispositivos SPI conectados al SoC, esta formada por la variable \textit{modalias}, \textit{chip\_select} y \textit{max\_speed\_hz}. Nuestro dispositivo DataFlash se controla utilizando un puerto SPI, por esto se define la variable \textit{platform\_data = \&my\_flash0\_platform}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static void __init ecb_at91board_init(void)
|
|||
|
{
|
|||
|
/* Serial */
|
|||
|
at91_add_device_serial();
|
|||
|
|
|||
|
/* USB Host */
|
|||
|
at91_add_device_usbh(&ecb_at91usbh_data);
|
|||
|
|
|||
|
/* I2C */
|
|||
|
at91_add_device_i2c(NULL, 0);
|
|||
|
|
|||
|
/* MMC */
|
|||
|
at91_add_device_mmc(0, &ecb_at91mmc_data);
|
|||
|
|
|||
|
/* SPI */
|
|||
|
at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
|
|||
|
|
|||
|
/* Programmable Clock 1*/
|
|||
|
at91_set_B_periph(AT91_PIN_PA4, 0);
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Una vez configurados los perif<69>ricos utilizados en la plataforma debemos agregar estos dispositos, con las funciones correspondientes \textit{at91\_add\_device\_(serial, usbh, i2c, mmc, spi) } estas funciones hacen un llamado a la funci<63>n \textit{platform\_device\_register} la que adiciona el dispositivo a nivel de plataforma.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
|
|||
|
/* Maintainer: emQbit.com */
|
|||
|
.phys_io = AT91_BASE_SYS,
|
|||
|
.io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
|
|||
|
.boot_params = AT91_SDRAM_BASE + 0x100,
|
|||
|
.timer = &at91rm9200_timer,
|
|||
|
.map_io = ecb_at91map_io,
|
|||
|
.init_irq = ecb_at91init_irq,
|
|||
|
.init_machine = ecb_at91board_init,
|
|||
|
MACHINE_END\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{Archivo de Configuraci<63>n del kernel}
|
|||
|
Finalmente debemos incluir un archivo de configuraci<63>n para el kernel (\textit{arch/arm/configs/ecbat91\_defconfig}) el cual contiene la configuraci<63>n inicial que cnfigura de forma correcta todos los perif<69>ricos de la plataforma.
|
|||
|
|
|||
|
\subsection{Imagen del kernel}
|
|||
|
En esta secci<63>n se realizar<61> una descripci<63>n de los pasos necesarios para compilar la im<69>gen del kernel de Linux para la familia de plataforma ECB\_AT91; despu<70>s, se realizar<61> un an<61>lisis de la imagen, indicando su composici<63>n.
|
|||
|
|
|||
|
\subsubsection{Compilaci<63>n de la Im<49>gen del kernel}
|
|||
|
En la secci<63>n anetrior vimos como dar soporte a nuestra plataforma, en esta secci<63>n describiremos el proceso de creaci<63>n de la im<69>gen del kernel. El primer paso obvio es obtener la im<69>gen del kernel, la que obtenemos del sitio oficial \textit{ftp.kernel.org}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
wget http://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.24.4.tar.bz2
|
|||
|
tar xjf linux-2.6.24.4.tar.bz2
|
|||
|
cd linux-2.6.24.4
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
A continuaci<63>n descargargamos un parche que mantienen los desarrolladores de la familia de SoCs de ATMEL, este parche modifica algunos archivos de la distribuci<63>n oficial de Linux para dar sopote completo y actualizado a los procesadores ATMEL.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
wget http://maxim.org.za/AT91RM9200/2.6/2.6.24-at91.patch.gz
|
|||
|
zcat 2.6.24-at91.patch.gz | patch -p1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Los cambios que se deben realizar en el c<>digo fuente, mencionados anteriormente fueron enviados a los encargados de mantener estas actualizaciones, por lo que no es necesario modificarlos para dar soporte a la familia de plataformas ECB\_AT91.
|
|||
|
|
|||
|
Finalmente debemos compilar el kernel utilizando la cadena de herramientas GNU, el resultado de este tipo de compilaciones son ejecutables para una arquitectura ARM, este proceso recibe el nombre de compilaci<63>n cruzada, debido a que da como resultado archivos que se ejecutan en una arquitectura diferente (ARM) a la que realiz<69> el proceso de compilaci<63>n (X86 en nuestro caso). Lo primero que debemos hacer es hacer visibles los ejecutables de la cadena de herramientas, esto se hace adicionando la ruta donde se encuentran instalados a la variable de entorno \textit{PATH}.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
export export PATH=$PATH:/home/at91/arm-2007q1/bin/
|
|||
|
alias crossmake='make ARCH=arm CROSS_COMPILE=arm-none-eabi-'
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
El alias \textit{crossmake} hace que cada vez que se escriba esta palabra el sistema lo reemplaze por \textit{make ARCH=arm CROSS\_COMPILE=arm-none-eabi-}, lo que ahorra tiempo al momento de pasar los par<61>metros a la herramienta make; estos par<61>metros son:
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
\item \textit{ARCH=arm} Define la arquitectura \textit{arm}.
|
|||
|
\item \textit{CROSS\_COMPILE=arm-none-eabi-} Indica que se realizar<61> una compilaci<63>n cruzada y que los ejecutables de la cadena de herramientas (\textit{gcc, c++, ld, objcopy, etc}) comienzan con el prefijo \textit{arm-none-eabi-} (por lo que el nombre del ejecutable del compilador de c es arm-none-eabi-gcc)
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
Una vez declaradas estas variables de entorno debemos generar el archivo oculto \textit{.config} \footnote{este archivo es utilizado por las herramientas de compilaci<63>n para determinar que soporte fu<66> incluido en el kernel} ejecutando el siguiente comando:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
crossmake ecbat91_defconfig
|
|||
|
o
|
|||
|
make ARCH=arm CROSS_COMPILE=arm-none-eabi- ecbat91_defconfig
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
A continuaci<63>n se muestra una secci<63>n de este archivo:
|
|||
|
\begin{lstlisting}
|
|||
|
#
|
|||
|
# Automatically generated make config: don't edit
|
|||
|
# Linux kernel version: 2.6.24.4
|
|||
|
# Sat Jul 25 11:39:07 2009
|
|||
|
#
|
|||
|
CONFIG_ARM=y
|
|||
|
.....
|
|||
|
#
|
|||
|
# AT91RM9200 Board Type
|
|||
|
#
|
|||
|
CONFIG_MACH_ECBAT91=y
|
|||
|
.....
|
|||
|
CONFIG_AEABI=y
|
|||
|
.....
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Finalmente damos incio al proceso de compilaci<63>n:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
crossmake -j2 (o make ARCH=arm CROSS_COMPILE=arm-none-eabi- -j2)
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Si no ocurre ning<6E>n error, al finalizar debemos observar lo siguiente:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
LD vmlinux
|
|||
|
SYSMAP System.map
|
|||
|
SYSMAP .tmp_System.map
|
|||
|
OBJCOPY arch/arm/boot/Image
|
|||
|
Building modules, stage 2.
|
|||
|
MODPOST 1 modules
|
|||
|
Kernel: arch/arm/boot/Image is ready
|
|||
|
AS arch/arm/boot/compressed/head.o
|
|||
|
CC drivers/scsi/scsi_wait_scan.mod.o
|
|||
|
GZIP arch/arm/boot/compressed/piggy.gz
|
|||
|
LD [M] drivers/scsi/scsi_wait_scan.ko
|
|||
|
CC arch/arm/boot/compressed/misc.o
|
|||
|
AS arch/arm/boot/compressed/head-at91rm9200.o
|
|||
|
AS arch/arm/boot/compressed/piggy.o
|
|||
|
LD arch/arm/boot/compressed/vmlinux
|
|||
|
OBJCOPY arch/arm/boot/zImage
|
|||
|
Kernel: arch/arm/boot/zImage is ready
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
y el contenido de los siguientes ditrectorios debe ser algo como:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ ls arch/arm/boot/
|
|||
|
bootp compressed Image install.sh Makefile zImage
|
|||
|
|
|||
|
$ ls vmlinux*
|
|||
|
vmlinux vmlinux.o
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{Componentes de la Im<49>gen del kernel}
|
|||
|
|
|||
|
Como nuestro inster<65>s en este punto es entender la estructura de la im<69>gen del kernel podemos indicarle a nuestra herramienta de compilaci<63>n que nos muestre m<>s informaci<63>n del proceso, ejecutando el comando:
|
|||
|
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
crossmake -j2 V=1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Al finalizar el proceso de compilaci<63>n obtenemos:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
arm-none-eabi-ld -EL -p --no-undefined -X -o vmlinux -T arch/arm/kernel/vmlinux.lds
|
|||
|
arch/arm/kernel/head.o arch/arm/kernel/init_task.o \
|
|||
|
init/built-in.o \
|
|||
|
--start-group \
|
|||
|
usr/built-in.o arch/arm/kernel/built-in.o \
|
|||
|
arch/arm/mm/built-in.o arch/arm/common/built-in.o \
|
|||
|
arch/arm/mach-at91/built-in.o arch/arm/nwfpe/built-in.o \
|
|||
|
kernel/built-in.o mm/built-in.o \
|
|||
|
fs/built-in.o ipc/built-in.o \
|
|||
|
security/built-in.o crypto/built-in.o \
|
|||
|
block/built-in.o arch/arm/lib/lib.a \
|
|||
|
lib/lib.a arch/arm/lib/built-in.o \
|
|||
|
lib/built-in.o drivers/built-in.o \
|
|||
|
sound/built-in.o net/built-in.o \
|
|||
|
--end-group \
|
|||
|
.tmp_kallsyms2.o
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
En la primera l<>nea de el listado anterior (\textit{arm-none-eabi-ld -EL -p --no-undefined -X -o vmlinux -T arch/arm/kernel/vmlinux.lds}) se realiza el proceso de enlace del archivo \textit{vmlinux}, utilizando el script de enlace \textit{vmlinux.lds}, incluyendo los objetos (archivos \textit{.o} indicados en la lista. N<>tese que el primer archivo enlazado es \textit{head.o}, el cual se genera a partir de \textit{arch/arm/kernel/head.S}, y contiene rutinas de inicializaci<63>n del kernel. Este proceso se explicar<61> detalladamente m<>s adelante. El siguiente objeto es \textit{init\_task.o}, el cual establece estructuras de datos e hilos que utilizar<61> el kernel. A continuaci<63>n se enlazan una serie de objetos con el nombre \textit{built-in.o}, la ruta del archivo indica la funci<63>n que realiza el objeto, por ejemplo el objeto \textit{arch/arm/mm/built-in.o} realiza operaciones de manejo de memoria espec<65>ficas a la arquitectura arm. En la Figura \ref{vmlinux_contents} se muestran los componentes de la im<69>gen vmlinux y un tama<6D>o de una compilaci<63>n en particular que nos da una idea de la relaci<63>n de tama<6D>os.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/vmlinux_contents} \end{center}
|
|||
|
\caption{Componentes de la Imag<61>n del kernel de Linux vmlinux}\label{vmlinux_contents}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
A continuaci<63>n se realiza la descripci<63>n de los componentes de la im<69>gen del kernel \textit{vmlinux}\cite{CH06}
|
|||
|
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
\item \textbf{arch/arm/kernel/head.o} C<>digo de inicializaci<63>n del kernel dependiente de la arquitectura.
|
|||
|
\item \textbf{init\_task.o} Hilos y estructuras inicialies utilizadas por el kernel.
|
|||
|
\item \textbf{init/built-in.o} C<>digo de inicializaci<63>n del kernel.
|
|||
|
\item \textbf{usr/built-in.o} Im<49>gen interna \textit{initramfs}.
|
|||
|
\item \textbf{arch/arm/kernel/built-in.o} C<>digo del kernel espec<65>fico de la arquitectura.
|
|||
|
\item \textbf{arch/arm/mm/built-in.o} C<>digo de manejo de memoria espec<65>fico de la arquitectura.
|
|||
|
\item \textbf{arch/arm/common/built-in.o} C<>digo gen<65>rico especifico de la arquitectura.
|
|||
|
\item \textbf{arch/arm/mach-at91/built-in.o} C<>digo de inicializaci<63>n espec<65>fico de la plataforma.
|
|||
|
\item \textbf{arch/arm/nwfpe/built-in.o} Emulaci<63>n de punto flot<6F>nte espec<65>fico de la arquitectura.
|
|||
|
\item \textbf{kernel/built-in.o} C<>digo de componentes com<6F>nes del kernel.
|
|||
|
\item \textbf{mm/built-in.o} C<>digo de componentes com<6F>nes de manejo de memoria.
|
|||
|
\item \textbf{ipc/built-in.o} Comunicaci<63>n Interproceso.
|
|||
|
\item \textbf{security/built-in.o} Componentes de seguridad de Linux.
|
|||
|
\item \textbf{lib/lib.a} Diferentes funciones auxiliares.
|
|||
|
\item \textbf{arch/arm/lib/lib.a} Diferentes funciones auxiliares, espec<65>fico de la aquitectura.
|
|||
|
\item \textbf{lib/built-in.o} Funciones auxiliares comunes del kernel.
|
|||
|
\item \textbf{drivers/built-in.o} Drivers internos o drivers no cargables.
|
|||
|
\item \textbf{sound/built-in.o} Drivers de sonido.
|
|||
|
\item \textbf{net/built-in.o} Red de Linux.
|
|||
|
\item \textbf{.tmp\_kallsyms2.o} Tabla de s<>mbolos.
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
|
|||
|
La im<69>gen \textit{vmlinux} generada tiene un tama<6D>o relativamente grande lo que la hace inconveniente para ser almacenada en un dispositivo Flash, por esta raz<61>n se acostrumbra comprimirla. A continuaci<63>n describiremos el proceso que se realiza para crear una im<69>gen compatible con \textit{u-boot}, el cargador de Linux m<>s utilizado para las plataformas embebidas. El primer paso para es reducir el tama<6D>o del ejecutable ELF \textit{vmlinux} es eliminar la informaci<63>n de depuraci<63>n (notas y comentarios).
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ crossmake -j3 vmlinux (4.4MBytes)
|
|||
|
$ arm-none-eabi-objcopy -O binary -R .note -R .comment -S vmlinux linux.bin (3.4MBytes)
|
|||
|
$ gzip -c -9 linux.bin > linux.bin.gz (1.6M)
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
A continuaci<63>n se comprime el archivo resultante utilizando la herramienta \textit{gzip}, como resultado obtenemos un archivo de 1.6M, la tercera parte del archivo original.
|
|||
|
|
|||
|
\section{Inicializaci<63>n del kernel}
|
|||
|
Como se mencion<6F> anteriormente, el SoC AT91RM9200, posee un programa residente en una peque<75>a ROM interna que revisa los controladores de memorias flash en busca de un programa v<>lido. En la familia de plataforma ECB\_AT91 se utiliza la memoria DataFlash para almacenar: el bootloader, el loader de Linux (u-boot) y la imagen del kernel. La Figura \ref{boot_process} indica la secuencia de ejecuci<63>n de aplicaciones cuando se energiza nuestra plataforma.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/boot_process} \end{center}
|
|||
|
\caption{Flujo de ejecuci<63>n en la inicializaci<63>n de plataforma ECB\_AT91}\label{boot_process}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
La primera aplicaci<63>n en ejecutarse es el loader de Darrel \footnote{Originalmente creado por Darrel Harmon: http://dlharmon.com/}. Debido a que la RAM interna del AT91RM9200 es de tan solo 16kBytes, es necesario utilizar otra aplicaci<63>n para poder cargar el loader de Linux U-boot en la memoria SDRAM externa (con capacida de de 32Mbytes). Recordemos que incialmente el SoC no posee ninguna aplicaci<63>n v<>lida en la memoria DataFlash, por lo que el programa interno de inicializaci<63>n dara comienzo a una comunicaci<63>n Xmodem, para que se descargue una aplicaci<63>n a la memoria RAM interna utilizando el puerto de depuraci<63>n serial a una velocidad de 115200 baudios.
|
|||
|
|
|||
|
|
|||
|
\subsection{Darrel's Loader}
|
|||
|
Esta aplicaci<63>n permite configurar la memoria externa SDRAM, configurar el puerto serie, implementar un protocolo xmodem que permita transferir aplicaciones a la memoria SDRAM, controlar la memoria DataFlash y almacenar aplicaciones en ella. El loader de Darrel est<73> basado en u-boot, es una versi<73>n reducida de este y permite <20>nicamente las operaciones mencioandas anteriormente, lo que resulta en un archivo adecuado para ser almacenado en la memoria RAM interna (9.3 kBytes).
|
|||
|
|
|||
|
Es interesante analizar esta aplicaci<63>n, ya que esta se ejecuta sin ning<6E>n soporte de sistema operativo, lo que lo hace interesante para plataformas en las que no se puede ejecutar Linux. Su c<>digo fuente lo podemos descargar utilizando el siguiente comando:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$svn co http://svn.arhuaco.org/svn/src/emqbit/ECB_AT91_V2/darrell-loader/
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La estructura del c<>digo fuente se muestra en el siguiente listado:
|
|||
|
\begin{lstlisting}
|
|||
|
|-- include
|
|||
|
| |-- asm
|
|||
|
| | |-- arch
|
|||
|
| | |-- proc
|
|||
|
| | `-- proc-armv
|
|||
|
| `-- linux
|
|||
|
| |-- byteorder
|
|||
|
| `-- mtd
|
|||
|
`-- src
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Antes de estudiar el c<>digo fuente demos un vistazo al archivo \textit{Makefile} para ver el proceso de compilaci<63>n. De ella podemos extraer las partes m<>s interesantes: Los objetos que hacen parte del ejecutable, el proceso de enlazado, y la creaci<63>n del archivo a descargar en la plataforma:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
AOBJS = src/start.o //ASSEMBLER OBJECTS
|
|||
|
COBJS = src/board.o src/serial.o src/xmodem.o src/dataflash.o src/div0.o src/interrupts.o
|
|||
|
LDSCRIPT := u-boot.lds
|
|||
|
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE)
|
|||
|
OBJCFLAGS += --gap-fill=0xff
|
|||
|
TEXT_BASE = 0x00000000
|
|||
|
|
|||
|
loader: $(AOBJS) $(COBJS) $(LDSCRIPT)
|
|||
|
$(LD) $(LDFLAGS) $(AOBJS) $(COBJS) \
|
|||
|
--start-group $(PLATFORM_LIBS) --end-group \
|
|||
|
-Map loader.map -o loader
|
|||
|
|
|||
|
loader.bin: loader
|
|||
|
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como podemos observar, esta aplicaci<63>n esta compuesta por el c<>digo en ensamblador \textit{src/start.S} y el c<>digo en C \textit{src/board.c src/serial.c src/xmodem.c src/dataflash.c src/div0.c src/interrupts.c}. Para generar el ejecutable \textit{loader} (en formato ELF), encadenamos los objetos AOBJS y COBJS utilizando el script de enlazado \textit{u-boot.lds}. A continuaci<63>n se muestra el comando ejecutado por las herramientas de compilaci<63>n al crear el ejecutable \textit{loader}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
arm-elf-ld -Bstatic -T u-boot.lds -Ttext 0x00000000
|
|||
|
src/start.o src/board.o src/serial.o src/xmodem.o src/dataflash.o src/div0.o src/interrupts.o
|
|||
|
--start-group
|
|||
|
--no-warn-mismatch -L /home/at91/gnutools/arm-elf/bin/../lib/gcc-lib/arm-elf/3.2.1 -lgcc
|
|||
|
--end-group -Map loader.map
|
|||
|
-o loader
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
A continuaci<63>n se muestra el contenido del archivo \textit{u-boot.lds}
|
|||
|
\begin{lstlisting}
|
|||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
|||
|
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
|
|||
|
OUTPUT_ARCH(arm)
|
|||
|
ENTRY(_start)
|
|||
|
SECTIONS
|
|||
|
{
|
|||
|
. = 0x00000000;
|
|||
|
|
|||
|
. = ALIGN(4);
|
|||
|
.text :
|
|||
|
{
|
|||
|
src/start.o (.text)
|
|||
|
*(.text)
|
|||
|
}
|
|||
|
|
|||
|
. = ALIGN(4);
|
|||
|
.rodata : { *(.rodata) }
|
|||
|
|
|||
|
. = ALIGN(4);
|
|||
|
.data : { *(.data) }
|
|||
|
|
|||
|
. = ALIGN(4);
|
|||
|
.got : { *(.got) }
|
|||
|
|
|||
|
. = ALIGN(4);
|
|||
|
__bss_start = .;
|
|||
|
.bss : { *(.bss) }
|
|||
|
_end = .;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Este archivo indica que la primera direcci<63>n del ejecutable es la 0x0 y que la primera instrucci<63>n en ejecutarse (definida por \textit{ENTRY}) se encuentra en el s<>mbolo \textit{\_start} definida en el archivo \textit{start.S}; por otro lado, este script de enlazado nos informa que las secciones \textit{.text} \textit{.rodata} \textit{.data} \textit{.got} y \textit{.bss} ser<65>n incluidas en el ejecutable y se encuentran en la misma regi<67>n de memoria (lo que era de esperarse ya que solo tenemos la memoria interna RAM).
|
|||
|
|
|||
|
\subsubsection{crt0.S (startup.S)}
|
|||
|
Cuando se crea un ejecutable para ser utilizado en una plataforma espec<65>fica, es necesario incluir el archivo \textit{crt0.S (C runtime startup code)}. Este archivo contiene el punto de entrada \textit{\_start} y est<73> encargado de las siguientes funciones:
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
\item Inicilizaci<63>n de las pilas (\textit{stacks}).
|
|||
|
\item Copiar el contenido de la secci<63>n \textit{.data} (datos inicializados) de la memoria no vol<6F>til.
|
|||
|
\item Inicializar la secci<63>n \textit{.bss}
|
|||
|
\item Hacer el llamado al punto de entrada \textit{main} ( \textit{start\_armboot} para el Darrel's loader)
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
Y esta compuesto por:
|
|||
|
\begin{enumerate}
|
|||
|
\item \textbf{\_vectors} Tabla de vectores de excepciones. Deben estar colocados en la direcci<63>n 0x0000.
|
|||
|
\item \textbf{reset\_handler} Esta funci<63>n maneja el reset , y es el punto de entrada principal de un ejecutable. Realiza operaciones de inicializaci<63>n espec<65>fica de la arquitectura.
|
|||
|
\item \textbf{undef\_handler} Es el manejador de las instrucciones no definidas.
|
|||
|
\item \textbf{swi\_handler} Manejador de las interrupciones software.
|
|||
|
\item \textbf{pabort\_handler} Manejador de las excepciones \textit{prefetch abort}.
|
|||
|
\item \textbf{dabort\_handler} Manejador de las excepciones \textit{data abort}.
|
|||
|
\item \textbf{irq\_handler} Manejador de las IRQ (Interrupt Request).
|
|||
|
\item \textbf{fiq\_handler} Manejador de las FIQ (Fast Iterrupt Request).
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
El archivo \textit{crt0.S} es escrito en languaje ensamblador, y es fuertemente dependiente de la arquitectura, solo programadores expertos con un muy buen conocimiento de la arquitectura podr<64>an escribirlo; sin embargo, los fabricantes proporcionan ejemplos de este tipo de archivos para que pueden ser utilizados sin tener que estudiar profundamente la arquitectura y el lenguaje ensamblador de la misma.
|
|||
|
|
|||
|
Una vez se han ejecutado las operaciones mendionadas anteriormente se hace un llamado al punto de entrada \textit{start\_armboot} (\textit{ldr pc,\_start\_armboot})
|
|||
|
|
|||
|
\subsubsection{serial.c, xmpdem.c, dataflash.c, div0.c, interrupts.c}
|
|||
|
A continuaci<63>n se realiza una descripci<63>n de los archivos que hacen parte del loader de Darrel:
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{serial.c}: Inicializa y configura el puerto serial de depuraci<63>n (DBGU) a uan velocidad ed 115200 baudios, 8 bits de datos, paridad, par. Adicionalmente proporciona las funciones:
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{putc}: Transmite un caracter por la interfaz serial de depuraci<63>n.
|
|||
|
\item \textit{puts}: Transmite una cadena de caracteres.
|
|||
|
\item \textit{getc}: Recibe un caracter por la interfaz serial de depuraci<63>n.
|
|||
|
\end{itemize}
|
|||
|
\item \textbf{xmodem.c}: Implementa la recepci<63>n serial utilizando elprotocolo xmodem.
|
|||
|
\item \textbf{dataflash.c}: Inicializa el puerto SPI, y proporciona funciones de alto nivel para la escritura de la DataFlash.
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{write\_dataflash(addr\_dest, addr\_src, size)}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\item \textbf{div0.c}: Remplazo (dummy) del manejador divisi<73>n por cero de GNU/Linux.
|
|||
|
\item \textbf{interrupts.c}: Proporciona funciones para el manejo de interrupciones e implementaci<63>n de retardos.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsubsection{board.c}
|
|||
|
El archivo \textit{board.c} proporciona el punto de entrada \textit{start\_armboot} y realiza las siguientes operaciones:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Configuraci<63>n del Controlador de manejo de potencia (PMC).
|
|||
|
\item Hace un llamado a la incializaci<63>n del puerto serie de depuraci<63>n \textit{serial\_init()}
|
|||
|
\item Configura la SDRAM externa \textit{try\_configure\_sdram}
|
|||
|
\item Despliega un men<65> de funciones.
|
|||
|
\item Realiza las operaciones del men<65>.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
Una vez se carga el archivo loader.bin, el que resulta de quitarle al archivo ELF la informaci<63>n de depuraci<63>n y notas:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
/home/at91/gnutools/arm-elf/bin/arm-elf-objcopy --gap-fill=0xff -O binary loader loader.bin
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
El programa desplegar<61> el siguiente men<65>:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
Darrell's loader - Thanks to the u-boot project
|
|||
|
Version 1.0. Build Jul 29 2007 12:04:04
|
|||
|
RAM:32MB
|
|||
|
|
|||
|
1: Upload Darrell's loader to Dataflash
|
|||
|
2: Upload u-boot to Dataflash
|
|||
|
3: Upload Kernel to Dataflash
|
|||
|
4: Start u-boot
|
|||
|
5: Upload Filesystem image
|
|||
|
6: Memory test
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La opci<63>n 1. del men<65> permite almacenar el archivo \textit{loader.bin} en la memoria DataFlash, una vez hecho esto, el programa de inicializaci<63>n almacenado en la memoria ROM interna lo ejecutar<61> cada vez que se reinicie la plataforma.
|
|||
|
|
|||
|
Las opciones 2 y 3 son similares a la 1, solo que se cargan las aplicaciones en diferentes direcciones de memoria, observemos el c<>digo fuente que implementa estas opciones:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
else if(key == '2'){
|
|||
|
puts("Please transfer u-boot.bin via Xmodem\n\0");
|
|||
|
len = rxmodem((char *)0x20000000);
|
|||
|
AT91F_DataflashInit ();
|
|||
|
dataflash_print_info ();
|
|||
|
if(write_dataflash(DATAFLASH_UBOOT_BASE, 0x20000000, len))
|
|||
|
puts("Dataflash write successful\n");
|
|||
|
dispmenu = 1;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Aca vemos como si se elije la opci<63>n 2, se despliega un mensaje indicandole al usuario que transmita el archivo \textit{u-boot.bin} utilizando el protocolo xmodem, despu<70>s se ejecuta la funci<63>n rxmodem la que recibe los datos por el serial y lo almacena en la SDRAM externa (direcci<63>n 0x20000000) y finalmente se almacena esta informaci<63>n en la direcci<63>n \textit{DATAFLASH\_UBOOT\_BASE}.
|
|||
|
|
|||
|
La opci<63>n 4. del men<65> transfiere la ejecuci<63>n
|
|||
|
\begin{lstlisting}
|
|||
|
else if(key == '4' || ((scans > 300000) && autoboot)){
|
|||
|
if(AT91F_DataflashInit ()){
|
|||
|
dataflash_print_info ();
|
|||
|
if(read_dataflash(DATAFLASH_UBOOT_BASE, 0x1C000, (char *)0x20700000)){
|
|||
|
puts("Dataflash read successful: Starting U-boot\n");
|
|||
|
asm("ldr pc, =0x20700000");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
En esta opci<63>n se copian 0x1C000 bytes del contenido de la memoria DataFlash comenzando en la posici<63>n \textit{DATAFLASH\_UBOOT\_BASE} a la direcci<63>n de memoria 0x20700000 (SDRAM externa) y luego se carga el contador de programa con la direcci<63>n 0x20700000, con lo que se inicia la ejecuci<63>n del programa almacenado en la DataFlash, es importante hacer notar que el programa debe ser enlazado para que las secciones est<73>n en la posici<63>n de memoria donde ser<65>n ejecutadas (0x20700000), no en la direcci<63>n donde son almacenadas.
|
|||
|
|
|||
|
\subsection{U-boot}
|
|||
|
La opci<63>n n<>mero 4 del men<65> copia el programa u-boot almacenado en la DataFlash a la memoria SDRAM y comienza su ejecuci<63>n, en esta secci<63>n se realizar<61> una descrici<63>n del loader u-boot.
|
|||
|
|
|||
|
U-boot es un \textit{bootloader} que permite cargar archivos utilizando una gran variedad de perif<69>ricos como: Puerto serie, Memoria SD, Memorias Flash Paraleas, seriales, NAND. NOR, Ethernet. Es cap<61>z de iniciar una variedad de tipos de archivos, adem<65>s de un formato especial propio; este <20>ltimo almacena informaci<63>n sobre el tipo de sistema operativo, la direcci<63>n de carga, el punto de entrada, verificaci<63>n de integridad via CRC, tipos de compresi<73>n, y textos descriptivos. La siguiente informaci<63>n es desplegada cuando \textit{u-boot} se inicializa una imagen del kernel de linux.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
## Booting image at c0021840 ...
|
|||
|
Image Name: Linux Kernel Image
|
|||
|
Image Type: ARM Linux Kernel Image (gzip compressed)
|
|||
|
Data Size: 1550369 Bytes = 1.5 MB
|
|||
|
Load Address: 20008000
|
|||
|
Entry Point: 20008000
|
|||
|
Verifying Checksum ... OK
|
|||
|
Uncompressing Kernel Image ... OK
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Para crear una im<69>gen con el formato \textit{U-boot} basta con ejecutar el siguiente comando:
|
|||
|
\begin{lstlisting}
|
|||
|
$ mkimage -A arm -O linux -T kernel -C gzip -a 0x20008000 -e 0x20008000 -n "Linux Kernel Image" \
|
|||
|
-d linux.bin.gz ecb_at91.img
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Ac<EFBFBD> definimos \textit{ARM} como arquitectura, \textit{linux} como sistema operativo, \textit{Kernel} como el tipo de im<69>gen, \textit{gzip} el m<>todo de compresi<73>n, \textit{0x20008000} la direcci<63>n de carga y punto de entrada (son iguales para kernels superiores al 2.3.X) \textit{Linux Kernel Image} el nombre de la im<69>gen \textit{linux.bin.gz} el archivo de entrada y \textit{ecb\_at91.img} el archivo de salida. Esta informaci<63>n es almacenada en el encabezado de la im<69>gen y puede ser leido utilizando el comando:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$mkimage -l /home/at91/binaries/ecb_at91.img
|
|||
|
|
|||
|
Image Name: Linux Kernel Image
|
|||
|
Created: Fri Jun 26 09:26:03 2009
|
|||
|
Image Type: ARM Linux Kernel Image (gzip compressed)
|
|||
|
Data Size: 1550369 Bytes = 1514.03 kB = 1.48 MB
|
|||
|
Load Address: 0x20008000
|
|||
|
Entry Point: 0x20008000
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
El siguiente listado muestra la estructura del envabezado definida por \textit{u-boot}, en ella podemos obervar sus componentes y el tama<6D>o de cada uno de ellos.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
typedef struct image_header {
|
|||
|
uint32_t ih_magic; /* Image Header Magic Number */
|
|||
|
uint32_t ih_hcrc; /* Image Header CRC Checksum */
|
|||
|
uint32_t ih_time; /* Image Creation Timestamp */
|
|||
|
uint32_t ih_size; /* Image Data Size */
|
|||
|
uint32_t ih_load; /* Data Load Address */
|
|||
|
uint32_t ih_ep; /* Entry Point Address */
|
|||
|
uint32_t ih_dcrc; /* Image Data CRC Checksum */
|
|||
|
uint8_t ih_os; /* Operating System */
|
|||
|
uint8_t ih_arch; /* CPU architecture */
|
|||
|
uint8_t ih_type; /* Image Type */
|
|||
|
uint8_t ih_comp; /* Compression Type */
|
|||
|
uint8_t ih_name[IH_NMLEN]; /* Image Name */
|
|||
|
} image_header_t;
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
\subsection{Portando U-boot a la familia de plataformas ECB\_AT91}
|
|||
|
Es necesario modificar varios archivos para que \textit{u-boot} soporte la familia de plataformas ECB\_AT91:
|
|||
|
|
|||
|
\subsubsection{Makefile}
|
|||
|
Se le debe indicar a las herramientas de compilaci<63>n la nueva plataforma, adicionando las siguientes l<>neas.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
ecb_at91_config : unconfig
|
|||
|
@$(MKCONFIG) $(@:_config=) arm arm920t ecb_at91 NULL at91rm9200
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{MAKEALL}
|
|||
|
Se debe agregar la siguiente entrada en el archivo MAKEALL:
|
|||
|
\begin{lstlisting}
|
|||
|
LIST_ARM9=" \
|
|||
|
-----
|
|||
|
at91rm9200dk cmc_pu2 ecb_at91
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{board/ecb\_at91/Makefile}
|
|||
|
En el directorio \textit{board/ecb\_at91} se alojan los archivos que dan soporte a la nueva arquitectura, el archivo de reglas de Configuraci<63>n se muestra a continuaci<63>n:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
|
|||
|
include $(TOPDIR)/config.mk
|
|||
|
|
|||
|
LIB = $(obj)lib$(BOARD).a
|
|||
|
|
|||
|
COBJS := $(BOARD).o at45.o flash.o
|
|||
|
|
|||
|
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
|
|||
|
OBJS := $(addprefix $(obj),$(COBJS))
|
|||
|
SOBJS := $(addprefix $(obj),$(SOBJS))
|
|||
|
|
|||
|
$(LIB): $(obj).depend $(OBJS) $(SOBJS)
|
|||
|
$(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS)
|
|||
|
|
|||
|
clean:
|
|||
|
rm -f $(SOBJS) $(OBJS)
|
|||
|
|
|||
|
distclean: clean
|
|||
|
rm -f $(LIB) core *.bak .depend
|
|||
|
|
|||
|
# defines $(obj).depend target
|
|||
|
include $(SRCTREE)/rules.mk
|
|||
|
sinclude $(obj).depend
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Este es el formato utilizado para todas las plataformas, la parte importante se encuentra en la definici<63>n de la variable \textit{COBJS}; en la que se incluyen los archivos \textit{ecb\_at91.o}: archivo de la plataforma \textit{at45.0}: soporte a las memorias DataFlash AT45 y \textit{flash.o}: soporte gen<65>rico para dispositivos flash\footnote{Estos archivos pueden ser descargados de: http://svn.arhuaco.org/svn/src/emqbit/ECB\_AT91\_V2/u-boot/u-boot-1.1.6-ecbat91.patch}.
|
|||
|
|
|||
|
\subsubsection{board/ecb\_at91/board.c}
|
|||
|
Este archivo contiene toda la configuraci<63>n espec<65>fica de la plataforma, y como se puede ver en el siguiente listado, fija el n<>mero de la plataforma a: MACH\_TYPE\_ECBAT91 (1072 definida en \textit{include/asm-arm/mach-types.h}) y los par<61>metros del boot en: \textit{PHYS\_SDRAM + 0x100;} (PHYS\_SDRAM = 0x20000000 est<73> definido en \textit{include/configs/ecb\_at91.h}). Adicionalmente, inicializa la SDRAM, la interfaz de red y la memoria DataFlash.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#include <common.h>
|
|||
|
#include <asm/arch/AT91RM9200.h>
|
|||
|
#include <at91rm9200_net.h>
|
|||
|
#include <lxt972.h>
|
|||
|
|
|||
|
DECLARE_GLOBAL_DATA_PTR;
|
|||
|
|
|||
|
/*
|
|||
|
* Miscelaneous platform dependant initialisations
|
|||
|
*/
|
|||
|
|
|||
|
void lowlevel_init(void)
|
|||
|
{
|
|||
|
/* Required by assembly functions - do nothing */
|
|||
|
}
|
|||
|
|
|||
|
int board_init (void)
|
|||
|
{
|
|||
|
/* Enable Ctrlc */
|
|||
|
console_init_f ();
|
|||
|
|
|||
|
/* arch number of ECB_AT91 board */
|
|||
|
gd->bd->bi_arch_number = MACH_TYPE_ECBAT91;
|
|||
|
|
|||
|
/* adress of boot parameters */
|
|||
|
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int dram_init (void)
|
|||
|
{
|
|||
|
gd->bd->bi_dram[0].start = PHYS_SDRAM;
|
|||
|
gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DRIVER_ETHER
|
|||
|
#if (CONFIG_COMMANDS & CFG_CMD_NET)
|
|||
|
|
|||
|
/*
|
|||
|
* Name:
|
|||
|
* at91rm9200_GetPhyInterface
|
|||
|
* Description:
|
|||
|
* Initialise the interface functions to the PHY
|
|||
|
* Arguments:
|
|||
|
* None
|
|||
|
* Return value:
|
|||
|
* None
|
|||
|
*/
|
|||
|
|
|||
|
void at91rm9200_GetPhyInterface(AT91PS_PhyOps p_phyops)
|
|||
|
{
|
|||
|
p_phyops->Init = lxt972_InitPhy;
|
|||
|
p_phyops->IsPhyConnected = lxt972_IsPhyConnected;
|
|||
|
p_phyops->GetLinkSpeed = lxt972_GetLinkSpeed;
|
|||
|
p_phyops->AutoNegotiate = lxt972_AutoNegotiate;
|
|||
|
}
|
|||
|
|
|||
|
#endif /* CONFIG_COMMANDS & CFG_CMD_NET */
|
|||
|
#endif /* CONFIG_DRIVER_ETHER */
|
|||
|
|
|||
|
#ifdef CONFIG_HAS_DATAFLASH
|
|||
|
#include <dataflash.h>
|
|||
|
|
|||
|
void AT91F_DataflashMapInit(void)
|
|||
|
{
|
|||
|
static int cs[][CFG_MAX_DATAFLASH_BANKS] = {
|
|||
|
/* Logical adress, CS */
|
|||
|
{CFG_DATAFLASH_LOGIC_ADDR_CS0, 0},
|
|||
|
};
|
|||
|
|
|||
|
static dataflash_protect_t area_list[NB_DATAFLASH_AREA] = {
|
|||
|
/*define the dataflash offsets*/
|
|||
|
{DATAFLASH_LOADER_BASE /* 0 */, DATAFLASH_UBOOT_BASE - 1,
|
|||
|
FLAG_PROTECT_SET, "Darrell loader"},
|
|||
|
{DATAFLASH_UBOOT_BASE, DATAFLASH_ENV_UBOOT_BASE - 1,
|
|||
|
FLAG_PROTECT_SET, "U-boot"},
|
|||
|
{DATAFLASH_ENV_UBOOT_BASE, DATAFLASH_KERNEL_BASE - 1,
|
|||
|
FLAG_PROTECT_CLEAR, "Environment"},
|
|||
|
{DATAFLASH_KERNEL_BASE, DATAFLASH_FILESYSTEM_BASE - 1,
|
|||
|
FLAG_PROTECT_CLEAR, "Kernel"},
|
|||
|
{DATAFLASH_FILESYSTEM_BASE, 0x1fffff, FLAG_PROTECT_SET, "Filesystem"},
|
|||
|
};
|
|||
|
|
|||
|
AT91F_MapInit (cs, area_list);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{include/configs/ecb\_at91.h}
|
|||
|
Este archivo contiene variables que son utilizadas para la inicializaci<63>n de la plataforma, algunas de estas ellas definen el valor de registros de configuraci<63>n de perif<69>ricos como: El controlador del reloj del sistema, controlador de memorias SDRAM y memorias Flash.
|
|||
|
|
|||
|
A continuaci<63>n se muestra un segmento de este archivo, en el que se define la arquitectura:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
|
|||
|
/* ARM asynchronous clock */
|
|||
|
#define AT91C_MAIN_CLOCK 180000000
|
|||
|
#define AT91C_MASTER_CLOCK 60000000
|
|||
|
|
|||
|
#define AT91_SLOW_CLOCK 32768 /* slow clock */
|
|||
|
|
|||
|
#define CONFIG_ARM920T 1 /* This is an ARM920T Core */
|
|||
|
#define CONFIG_AT91RM9200 1 /* It's an Atmel AT91RM9200 SoC */
|
|||
|
#define CONFIG_ECB_AT91 1 /* on an AT91RM9200DK Board */
|
|||
|
#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
|
|||
|
#define USE_920T_MMU 1
|
|||
|
|
|||
|
#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
|
|||
|
#define CONFIG_SETUP_MEMORY_TAGS 1
|
|||
|
#define CONFIG_INITRD_TAG 1
|
|||
|
|
|||
|
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
|||
|
#define CFG_LONGHELP
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Este archivo tambi<62>n incluye el valor predeterminado de las variables de entorno utilizadas por \textit{u-boot}:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#define CONFIG_BOOTARGS "mem=32M root=/dev/mmcblk0p1 rootfstype=ext3 console=ttyS0,115200n8 rootdelay=1"
|
|||
|
#define CONFIG_ETHADDR 00:00:00:00:00:5b
|
|||
|
#define CONFIG_NETMASK 255.255.255.0
|
|||
|
#define CONFIG_IPADDR 192.168.0.135
|
|||
|
#define CONFIG_SERVERIP 192.168.0.128
|
|||
|
#define CONFIG_BOOTDELAY 2
|
|||
|
#define CONFIG_BOOTCOMMAND "bootm C0021840"
|
|||
|
#define CONFIG_BOOTFILE "ecb_at91.img"
|
|||
|
#define CONFIG_ROOTPATH "/home/at91/rootfs"
|
|||
|
#define CONFIG_LOADADDR 0x20200000
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
La variable \textit{bootargs} son par<61>metros pasados al kernel en su inicializaci<63>n, y en este ejemplo fija la memoria RAM en 32 Mbytes, indica que el sistema de archivos se encuentra en el dispositivo \textit{/dev/mmcblk0p1} y utiliza el sistema de archivos \textit{ext3}, la consola es el dispositivo serial \textit{/dev/ttyS0} configurado a una velocidad de 115200 baudios, bit de paridad y 8 bits de datos y que debe esperar 1 segundo para montar el sistema de archivos.
|
|||
|
|
|||
|
Las variables \textit{ethaddr, netmask, ipaddr, serverip} configuran la interfaz de red y las direcciones IP de la plataforma y de un servidor de donde puede descargarse la im<69>gen del kernel. La variable \textit{bootdelay} fija el n<>mero de segundos que esperar<61> u-boot para ejecutar el comando almacenado en \textit{bootcmd}, este conteo puede detenerse para interactuar con u-boot. El comando \textit{bootm C0021840 (bootcmd)} es utilizado para iniciar la im<69>gen almacenada en la direcci<63>n de memoria 0xC0021840 (direcci<63>n donde almacena el loader de Darrel la im<69>gen del kernel), \textit{bootm} utiliza la informaci<63>n almacenada en el encabezado de la im<69>gen para utilizar el m<>todo de descompresi<73>n adecuado, almacenarlo en la direcci<63>n requerida y pasarle los par<61>metros almacenados en \textit{bootcmd}.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#define CONFIG_COMMANDS \
|
|||
|
((CONFIG_CMD_DFL | CFG_CMD_NET | CFG_CMD_PING | CFG_CMD_DHCP ) & \
|
|||
|
~(CFG_CMD_BDI | CFG_CMD_FPGA | CFG_CMD_MISC))
|
|||
|
|
|||
|
/* Remember that you must have the same mapping in the Darrell loader */
|
|||
|
#define NB_DATAFLASH_AREA 5 /* protected areas (4 + u-boot env) */
|
|||
|
#define DATAFLASH_MAX_PAGESIZE 1056
|
|||
|
#define DATAFLASH_LOADER_BASE (0*DATAFLASH_MAX_PAGESIZE)
|
|||
|
#define DATAFLASH_UBOOT_BASE (12*DATAFLASH_MAX_PAGESIZE)
|
|||
|
#define DATAFLASH_ENV_UBOOT_BASE (122*DATAFLASH_MAX_PAGESIZE)
|
|||
|
#define DATAFLASH_KERNEL_BASE (130*DATAFLASH_MAX_PAGESIZE)
|
|||
|
#define DATAFLASH_FILESYSTEM_BASE (1664*DATAFLASH_MAX_PAGESIZE)
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{Compilaci<63>n de U-boot en la familia de plataformas ECB\_AT91}
|
|||
|
A continuaci<63>n se indican los pasos necesarios para generar el archivo \textit{u-boot.bin} que ser<65> almacenado en la memoria DataFlash por el loader de Darrel.
|
|||
|
|
|||
|
El primer paso es obviamente descargar el c<>digo fuente de la versi<73>n 1.1.6 de \textit{http://sourceforge.net/projects/u-boot/}, despu<70>s debemos descargar el patch que da soporte a la familia de plataformas ECB\_AT91:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ wget http://svn.arhuaco.org/svn/src/emqbit/ECB_AT91_V2/u-boot/u-boot-1.1.6-ecbat91.patch
|
|||
|
$ tar xjf u-boot-1.1.6.tar.bz2
|
|||
|
$ cd u-boot-1.1.6
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Aplicamos el patch
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ cat ../u-boot-1.1.6-ecbat91.patch | patch -p1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Configuramos y generamos las herramientas utilizadas por \textit{u-boot} (entre ellas \textit{mkimage}).
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ make ecb_at91_config
|
|||
|
Configuring for ecb_at91 board... (Este es un comentario)
|
|||
|
$ make tools
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Por <20>ltimo compilamos \textit{u-boot}:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ make ARCH=arm CROSS_COMPILE=arm-none-eabi-
|
|||
|
o
|
|||
|
crossmake (si el alias crossmake est<73> definido)
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Si el proceso se sigui<75> correctamente y no se presentan errores al final del proceso obtenemos el mensaje:
|
|||
|
\begin{lstlisting}
|
|||
|
arm-none-eabi-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
|
|||
|
arm-none-eabi-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
|
|||
|
\end{lstlisting}
|
|||
|
Lo que nos indica que se gener<65> exitosamente el archivo \textit{u-boot.bin}, que puede ser descargado utilizando la opci<63>n 2 del men<65> del loader de Darrel (\textit{Upload u-boot to Dataflash}) y el protocolo xmodem.
|
|||
|
|
|||
|
Podemos verificar que el archivo fu<66> generado y almacenado en la Dataflash podemos ejecutar la opci<63>n n<>mero 4 del men<65> del loader de Darrel (\textit{Start u-boot}), como se mencion<6F> anteriormente esta opci<63>n copia el archivo \textit{u-boot} desde la DataFlash a la memoria SDRAM y es ejecutado desde alli, con lo que se desplegar<61> el siguiente mensaje:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
Dataflash read successful: Starting U-boot
|
|||
|
U-Boot 1.1.6 (Jul 29 2007 - 12:12:38)
|
|||
|
|
|||
|
DRAM: 32 MB
|
|||
|
Atmel: Flash: 0 kB
|
|||
|
DataFlash:AT45DB161
|
|||
|
Nb pages: 4096
|
|||
|
Page Size: 528
|
|||
|
Size= 2162688 bytes
|
|||
|
Logical address: 0xC0000000
|
|||
|
Area 0: C0000000 to C000317F (RO) Darrell loader
|
|||
|
Area 1: C0003180 to C001F73F (RO) U-boot
|
|||
|
Area 2: C001F740 to C002183F Environment
|
|||
|
Area 3: C0021840 to C01ACFFF Kernel
|
|||
|
Area 4: C01AD000 to C020FFFF (RO) Filesystem
|
|||
|
In: serial
|
|||
|
Out: serial
|
|||
|
Err: serial
|
|||
|
PHY not connected!!
|
|||
|
Hit any key to stop autoboot: 2
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Si se presiona cualquier tecla antes de que el contador llegue a \textit{0}, podemos interactuar con \textit{u-boot}, si ejecutamos el comando \textit{print} (Despliega en pantalla las variables de entorno definidas):
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
bootcmd=bootm C0021840
|
|||
|
bootdelay=2
|
|||
|
baudrate=115200
|
|||
|
ethaddr=00:00:00:00:00:5b
|
|||
|
ipaddr=192.168.0.135
|
|||
|
serverip=192.168.0.128
|
|||
|
rootpath="/home/at91/rootfs"
|
|||
|
netmask=255.255.255.0
|
|||
|
bootfile="ecb_at91.img"
|
|||
|
loadaddr=0x20200000
|
|||
|
bootargs=mem=32M root=/dev/mmcblk0p2 rootfstype=ext3 console=ttyS0,115200n8 rootdelay=1
|
|||
|
stdin=serial
|
|||
|
stdout=serial
|
|||
|
stderr=serial
|
|||
|
Environment size: 345/8188
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Podemos cambiar el valor predeterminado de la variable \textit{bootdelay} a \textit{1}:
|
|||
|
\begin{lstlisting}
|
|||
|
ecb_at91> setenv bootdelay 1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Y almacenamos los cambios realizados en una secci<63>n de la flash reservada para este fin con el comando:
|
|||
|
\begin{lstlisting}
|
|||
|
ecb_at91> save
|
|||
|
Saving Environment to dataflash...
|
|||
|
\end{lstlisting}s
|
|||
|
|
|||
|
Podemos generar una nueva variable de entorno, almacenarla en la DataFlash
|
|||
|
\begin{lstlisting}
|
|||
|
|
|||
|
ecb_at91> setenv nfsargs=mem=32M console=ttyS0,115200n8 root=/dev/nfs nfsroot=192.168.0.128:/home
|
|||
|
/at91/rootfs,timeo=200,retrans=500 ip=:::::eth0:on
|
|||
|
|
|||
|
ecb_at91> save
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
\subsection{Almacenamiento de la im<69>gen del kernel}
|
|||
|
Una vez creada la im<69>gen del kernel (\textit{ecb\_at91.img}) con el formato de \textit{U-boot} debemos probar su correcto funcionamiento; esto lo podemos hacer de dos formas: Almacenandola directamente en una memoria no vol<6F>til o carg<72>ndola en la memoria RAM y ejecut<75>ndola desde all<6C>.
|
|||
|
|
|||
|
\subsubsection{Almacenamiento en la memoria DataFlash}
|
|||
|
Cuando almacenamos la im<69>gen del kernel de Linux a un medio de almacenamiento no vol<6F>til, debemos tener presente que los ciclos de borrado y escritura de este toman un tiempo mucho mayor que en el caso de las memorias no vol<6F>tiles, por esto, se recomienda esta opci<63>n cuando ya se cuente con una im<69>gen estable o cuando no existan otros medios (como en el caso de la plataforma ECBOT).
|
|||
|
|
|||
|
Inicialmente debemos ejecutar el loader de Darrel, esto se hace presionando el pulsador de \textit{Reset} disponible en todas las plataformas de la familia \textit{ECB\_AT91}. Inmediatamente despu<70>s de observar el men<65> del loader debemos oprimir cualquier tecla para interrumpir la ejecuci<63>n autom<6F>tica del \textit{u-boot}.
|
|||
|
|
|||
|
Seleccionando la opci<63>n del men<65>: \textit{3: Upload linux to Dataflash}, podemos iniciar la transferencia de la im<69>gen a la memoria SDRAM de nuestra plataforma:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
Please transfer linux via Xmodem
|
|||
|
Receiving Xmodem transfer
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Cuando aparezca este mensaje se debe transmitir el archivo \textit{ecb\_at91.img} utilizando el protocolo xmodem. Unos minutos despu<70>s la transferencia finaliza, sin embargo, debemos esperar a que la informaci<63>n sea almacenada en la memoria DataFlash, mientras se completa la escritura la consola no mostrar<61> ninguna actividad, eso es normal y no se debe reiniciar la board. Una vez finalizada la escritura observaremos el mensaje:
|
|||
|
\begin{lstlisting}
|
|||
|
%%%%%%%%%%%%%%%%%%%%%
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsubsection{Almacenamiento en la memoria RAM}
|
|||
|
El proceso de grabaci<63>n en la memoria DataFlash puede tomar alrededor de 6 minutos, lo que no lo hace conveniente cuando se est<73> tratando de crear una imagen propia o se est<73>n realizando cambios a la misma. Cuando necesitamos modificar esta im<69>gen ya sea porque queremos hacerlo nosotros mismos o porque deseamos una versi<73>n de kernel m<>s moderna, es preferible utilizar un m<>todo de transferencia m<>s r<>pido.
|
|||
|
|
|||
|
La plataforma \textit{ECB\_AT91} posee una interfaz de red que puede ser controlada por \textit{u-boot}. Utilizando el protocolo \textit{tftp} \textit{U-boot} puede descargar la im<69>gen desde un servidor a la memoria SDRAM y ejecutarla desde all<6C>, ese proceso se realiza en segundos, facilitando de esta forma el proceso de desarrollo. A continuaci<63>n se desciben los pasos que deben seguirse para realizar esta operaci<63>n:
|
|||
|
|
|||
|
Primero debemos instalar y configurar el servidor \textit{tftp} en el computador donde se tiene las herramientas de desarrollo:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ aptitude install tftpd tftp.
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Se debe agregar la siguiente l<>nea al archivo \textit{/etc/inetd.conf}
|
|||
|
\begin{lstlisting}
|
|||
|
tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /srv/tftp
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Debe asegurarse que el protocolo \textit{tftp} utiliza el puerto \textit{UDP} 69
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ cat /etc/services | grep tftp
|
|||
|
tftp 69/udp
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Ahora creamos el directorio \textit{/srv/tftp}\footnote{Este directorio tiene restricciones de seguridad, debe contactarse con el administrador de su equipo para permitir el acceso a <20>l} y colocamos la imagen en <20>l:
|
|||
|
\begin{lstlisting}
|
|||
|
$ mkdir /srv/tftp/
|
|||
|
$ chown myuser. /srv/tftp/
|
|||
|
$ cp ecb_at91.img /srv/tftp/
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Para verificar la correcta configuraci<63>n del servidor, podemos utilizar un cliente \textit{tftp}:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
$ cd /tmp/
|
|||
|
$ tftp localhost # from the server
|
|||
|
tftp> get ecb_at91.img
|
|||
|
Received 1319525 bytes in 0.2 seconds
|
|||
|
tftp> quit
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Ahora se deben configurar algunas variables de entorno en nuestra plataforma para indicarle a \textit{u-boot} la direcci<63>n \textit{IP}, el nombre y la ubicaci<63>n de la im<69>gen del kernel. Estas variables deben ser modificadas para que contengan los siguientes valores:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
loadaddr=0x20200000
|
|||
|
bootdelay=1
|
|||
|
bootfile="ecb_at91.img"
|
|||
|
fileaddr=20200000
|
|||
|
gatewayip=192.168.0.1
|
|||
|
netmask=255.255.255.0
|
|||
|
serverip=192.168.0.128
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Estas variables fijan la direcci<63>n \textit{IP} de: la plataforma a \textit{192.168.0.2}, del gateway a \textit{192.168.0.1}, la del servidor \textit{tftp} a \textit{192.168.0.128\footnote{Direcci<63>n IP del PC donde est<73>n las herramientas de desarrollo}}. Adicionalmente define el nombre de la im<69>gen del kernel a \textit{ecb\_at91.img}. Una vez configurado \textit{U-boot} podemos descargar la im<69>gen a la direcci<63>n de memoria \textit{0x20200000}:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
ecb_at91 >tftp
|
|||
|
TFTP from server 192.168.0.1; our IP address is 192.168.0.2
|
|||
|
Filename 'ecb_at91.img'.
|
|||
|
Load address: 0x20200000
|
|||
|
Loading: #################################################################
|
|||
|
#################################################################
|
|||
|
#################################################################
|
|||
|
#################################################################
|
|||
|
################
|
|||
|
done
|
|||
|
Bytes transferred = 1409031 (158007 hex)
|
|||
|
ecb_at91 >
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
\subsection{Inicializaci<63>n del Kernel}
|
|||
|
En general los cargadores de Linux como el \textit{u-boot} realizan las siguientes funciones:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Configurar e inicializar la RAM}
|
|||
|
\item \textbf{Inicializar un puerto serial}
|
|||
|
\item \textbf{Detectar el tipo de m<>quina:} El boot loader debe proporcionar un valor \textit{MACH\_TYPE\_XXX} al kernel, como vimos anteriormente tanto \textit{u-boot} como \textit{Linux} fijan este valor a 1072.
|
|||
|
\item Configurar la \textit{kernel tagged list}: El boot loader debe crear e inicializar una estructura llamada \textit{kernel tagged list}, al cual comienza con \textit{ATAG\_CORE} y finaliza con \textit{ATAG\_NONE}. El tag \textit{ATAG\_CORE} puede o no estar desocupado, si se encuentra desocupado debe fijar el campo \textit{size} en '2'. El campo \textit{size} del tag \textit{ATAG\_NONE} debe fijarse en 0. Se pueden definir cualquier n<>mero de tags, pero se deben definir por lo menos el tama<6D>o y la localizaci<63>n de la memoria del sistema, y la localizaci<63>n del sistema de archivos. Esta \textit{tagged list} debe ser almacenada en RAM, en una regi<67>n que no pueda ser modificada por el descompresor del kernel o por el programa \textit{initrd}. Se recomienda colocarlo en los primeros 16kBytes de la RAM.
|
|||
|
|
|||
|
\item Hacer un llamado a la im<69>gen del kernel: Existen dos formas de hacer este llamado, directamente desde la flash o en en cualquier posici<63>n de la RAM. Los dos m<>todos deben cumplir las siguientes condiciones:
|
|||
|
\begin{itemize}
|
|||
|
\item Desactiva los dispositivos que tienen capacidad de DMA, de tal forma que la memoria no se corrompa.
|
|||
|
\item Fijar los registros de la CPU: \textit{r0 = 0}, \textit{r1 = t<>po de m<>quina}, \textit{r2 = direcci<63>n f<>sica de la \textit{tagged list} en RAM.}
|
|||
|
\item Modo de la CPU: Deshabilitar todas las interrupcione (IRQs y FIQs) y colocar a la CPU en modo SVC
|
|||
|
\item Caches, MMU: Debe estar desactivada la MMU, La cache de instrucci<63>nes puede estar activada o desactivada, la cache de datos debe estar desactivada.
|
|||
|
\end{itemize}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Llamado a la Im<49>gen del kernel}
|
|||
|
|
|||
|
Como mencionamos anteriormente, \textit{u-boot} ejecuta las instrucciones almacenadas en la variable de entorno \textit{bootcmd}; que para la familia de plataformas ECB\_AT91 almacena el comando \textit{bootm C0021840}, esta instrucci<63>n le indica a \textit{u-boot} que ejecute el comando \textit{bootm} con una im<69>gen almacenada en la posici<63>n de memoria \textit{0xC0021840}, en la que (como mencionamos anteriormente (Figura \ref{boot_process})) se almacena la im<69>gen del kernel. El c<>digo que implementa el comando \textit{bootm} se encuentra en el archivo \textit{common/cmd\_bootm.c}; analizando este archivo podemos descubrir el proceso que realiza \textit{u-boot} al hacer el llamado a la im<69>gen del kernel (la que almacenamos utilizando la opci<63>n 3 del loader de Darrel). La funci<63>n \textit{do\_bootm} realiza las siguientes operaciones:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Verificar la existencia de un n<>mero m<>gico en los primeros 4 bytes de la im<69>gen (0x27051956). Si no se encuentra este n<>mero se desplegar<61> el mensaje: \textit{Bad Magic Number}
|
|||
|
\item Verifica la integridad del encabezado de la im<69>gen. De no pasar esta prueba se mostrar<61> el mensaje: \textit{Bad Header Checksum}.
|
|||
|
\item Imprime el encabezado de la im<69>gen, aparecer<65> algo como:
|
|||
|
\item C<>lcula el CRC del archivo almacenado y lo compara con el almacenado en la cabecera de la im<69>gen. Si no se supera esta prueba, se desplegar<61> el mensaje: \textit{Bad Data CRC}
|
|||
|
\item Comprueba que la arquitectura est<73> soportada por \textit{u-boot}.
|
|||
|
\item Descomprime la im<69>gen almacenada en la direcci<63>n \textit{load\_address} (la cual se pasa como par<61>metro en el momento de la creaci<63>n de la im<69>gen).
|
|||
|
\item Transferir el control a Linux en la funci<63>n \textit{do\_bootm\_linux}\textit{U-boot es un loader que permite trabajar con: LYNXOS, RTEMS, VXWORKS, QNX, ARTOS, NETBSD}
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
La funci<63>n \textit{do\_bootm\_linux} hace el llamado a la imagen del kernel utilizando el siguiente comando:
|
|||
|
\begin{lstlisting}
|
|||
|
(*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
en donde:
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{kbd} Informaci<63>n de la plataforma de desarrollo:
|
|||
|
% \begin{itemize}\item
|
|||
|
\begin{lstlisting}
|
|||
|
typedef struct bd_info {
|
|||
|
int bi_baudrate; /* serial baudrate */
|
|||
|
unsigned long bi_ip_addr; /* IP Address */
|
|||
|
unsigned char bi_enetaddr[6]; /* Ethernet adress */
|
|||
|
struct environment_s *bi_env;
|
|||
|
ulong bi_arch_number; /* id for this board */
|
|||
|
ulong bi_boot_params; /* boot params */
|
|||
|
struct /* RAM configuration */
|
|||
|
{
|
|||
|
ulong start;
|
|||
|
ulong size;
|
|||
|
} bi_dram[CONFIG_NR_DRAM_BANKS];
|
|||
|
} bd_t; \end{itemize}
|
|||
|
\end{lstlisting}
|
|||
|
% \end{itemize}
|
|||
|
\item \textit{initrd\_start} - \textit{initrd\_end}: Linux permite que el sistema de archivos sea almacenado en la memoria RAM, el sistema es almacenado en alg<6C>n medio no vol<6F>til y despu<70>s es descomprimido en la RAM, esto acelera la ejecuci<63>n ya que como se mencion<6F> anteriormente, el acceso a las memorias vol<6F>tiles es mucho menor. \textit{initrd\_start} - \textit{initrd\_end} indican el inicio y fin de este archivo
|
|||
|
\item \textit{cmd\_start} - \textit{cmd\_end}: Posici<63>n de memoria donde se almacenan los par<61>metros pasados al kernel (\textit{mem=32M root=/dev/mmcblk0p2 rootfstype=ext3 console=ttyS0,115200n8 rootdelay=1})
|
|||
|
\end{itemize}
|
|||
|
En este punto termina el trabajo de \textit{u-boot} y el control es pasado al kernel. Como pudimos darnos cuenta lo m<>s atractivo de \textit{u-boot} es su capacidad para manejar diferentes dispositivos de almacenamiento no vol<6F>tiles como Memorias Flash, memorias SD y su capacidad para manejar interfaces de red y permitir utilizarlas para al carga de im<69>genes del kernel.
|
|||
|
|
|||
|
\subsubsection{Punto de Entrada del Kernel \textit{head.o}}
|
|||
|
Como puede verse en \ref{vmlinux_contents} el primer archivo encadenado en la im<69>gen del kernel es \textit{arch/arm/kernel/head.o}, y corresponde al punto de entrada del kernel de Linux, este archivo ejecuta las siguientes funciones:
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
\item Verificar que la arquitectura y el procesador sean v<>lidos. Si el procesador no es v<>lido se generar<61> un error y en la consola aparecer<65> una ``\textit{p}'', si la plataforma no corresponde se genera un error y se imprimir<69> una ``\textit{a}'' en la consola.
|
|||
|
\item Se genera una estructura de datos (\textit{page table}) que almacena el mapeo entre las direcciones de memoria virtual y la memoria f<>sica. Antes de pasar el control al kernel, el procesador corre un un modo \textit{real}, en el que las direcciones corresponden a direcciones reales de los dispositivos conectados f<>sicamente al procesador.
|
|||
|
\item Activa la unidad de manejo de memoria (MMU) del procesador. Cuando se activa la MMU el esquema de memoria f<>sico se remplaza por un direccionamiento virtual determinado por los desarrolladores del kernel.
|
|||
|
\item Establece un limitado mecanismo de detecci<63>n y reporte de errores.
|
|||
|
\item Hace un llamado a la funci<63>n \textit{start\_kernel} en \textit{init/main.c}
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
setup_arch(&command_line);
|
|||
|
setup_command_line(command_line);
|
|||
|
sched_init();
|
|||
|
preempt_disable();
|
|||
|
page_alloc_init();
|
|||
|
console_init();
|
|||
|
mem_init();
|
|||
|
kmem_cache_init();
|
|||
|
setup_per_cpu_pageset();
|
|||
|
numa_policy_init();
|
|||
|
calibrate_delay();
|
|||
|
pidmap_init();
|
|||
|
pgtable_cache_init();
|
|||
|
prio_tree_init();
|
|||
|
anon_vma_init();
|
|||
|
fork_init(num_physpages);
|
|||
|
proc_caches_init();
|
|||
|
buffer_init();
|
|||
|
unnamed_dev_init();
|
|||
|
key_init();
|
|||
|
security_init();
|
|||
|
vfs_caches_init(num_physpages);
|
|||
|
radix_tree_init();
|
|||
|
signals_init();
|
|||
|
|
|||
|
page_writeback_init();
|
|||
|
proc_root_init();
|
|||
|
cgroup_init();
|
|||
|
cpuset_init();
|
|||
|
taskstats_init_early();
|
|||
|
delayacct_init();
|
|||
|
acpi_early_init();
|
|||
|
schedule();
|
|||
|
preempt_disable();
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
En los <20>ltimos pasos en el proceso de arranque de Linux, se libera la memoria que ser<65> utilizada por los procesos de inicializaci<63>n, abre un dispositivo que permita la interacci<63>n con el usuario \textit{/dev/console} (consola serial en nuestro caso) y ejecuta el primer proceso en espacio de usuario \textit{init}. El siguiente listado muestra el c<>digo que implementa esta <20>ltima fase del proceso de arranque.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static int noinline init_post(void)
|
|||
|
{
|
|||
|
free_initmem();
|
|||
|
unlock_kernel();
|
|||
|
mark_rodata_ro();
|
|||
|
system_state = SYSTEM_RUNNING;
|
|||
|
numa_default_policy();
|
|||
|
|
|||
|
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
|
|||
|
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
|
|||
|
|
|||
|
(void) sys_dup(0);
|
|||
|
(void) sys_dup(0);
|
|||
|
|
|||
|
if (ramdisk_execute_command) {
|
|||
|
run_init_process(ramdisk_execute_command);
|
|||
|
printk(KERN_WARNING "Failed to execute %s\n",
|
|||
|
ramdisk_execute_command);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* We try each of these until one succeeds.
|
|||
|
*
|
|||
|
* The Bourne shell can be used instead of init if we are
|
|||
|
* trying to recover a really broken machine.
|
|||
|
*/
|
|||
|
if (execute_command) {
|
|||
|
run_init_process(execute_command);
|
|||
|
printk(KERN_WARNING "Failed to execute %s. Attempting "
|
|||
|
"defaults...\n", execute_command);
|
|||
|
}
|
|||
|
run_init_process("/sbin/init");
|
|||
|
run_init_process("/etc/init");
|
|||
|
run_init_process("/bin/init");
|
|||
|
run_init_process("/bin/sh");
|
|||
|
|
|||
|
panic("No init found. Try passing init= option to kernel.");
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como podemos obsever el <20>ltimo p<>so consiste en el llamado a un archivo en espacio de usuario llamado \textit{init} o \textit{sh}, en la siguiente subsecci<63>n se describir<69> las acciones que se realizan cuando se ejecuta este archivo. De no encontrarse se desplegar<61> el mensaje \textit{No init found. Try passing init= option to kernel.} y la plataforma pasar<61> a un estado de inactividad.
|
|||
|
|
|||
|
\section{Inicializaci<63>n del Sistema}
|
|||
|
En esta secci<63>n describiremos el proceso de inicializaci<63>n de la plataforma embebida, en la secci<63>n anterior se estudi<64> la inicializaci<63>n del kernel de Linux. En esta secci<63>n se realizar<61> una descripci<63>n del sistema de archivos que contiene aplicaciones que Linux requiere para inicializar servicios como los de red y la consola, cargar drivers (\textit{m<>dulos}) de dispositivos y montar sistemas de archivos adicionales.
|
|||
|
|
|||
|
\subsection{Sistema de Archivos}
|
|||
|
Anteriormente hemos hecho referencia a la localizaci<63>n de la ra<72>z del sistema de archivos (\textit{root}), e indicamos que est<73> se encuentra en una determinada memoria no vol<6F>til, estamos indicando donde se encuentra el nivel m<>s alto del sistema de archivos, el cual se denota como \textit{``/''}. Existen varias opciones entre las que se encuentran:
|
|||
|
\begin{itemize}
|
|||
|
\item \textbf{Second Extended File System (ext2)} : Este sistema de archivos utiliza bloques como unidad de almacenamiento b<>sico, inodes como medio para mentener un seguimiento de archivos y objetos de sistema, grupos de bloques para dividir l<>gicamente el disco en secciones m<>s menejables, directorios para proporcionar una organizaci<63>n jer<65>rquica de archivos, bloques y mapas de bits (\textit{bitmap}) de bloques e inodes para mantener un seguimiento de bloques e inodes asignados, y superbloques para definir los par<61>metros del sistema de archivos y su estado general. Adicionalmente posee la capacidad de crear enlaces simb<6D>licos, un tipo especial de archivo que contiene la referencia a otro archivo o directorio.
|
|||
|
|
|||
|
|
|||
|
\item \textbf{Third Extended File System (ext3)}: \textit{ext3} es una extensi<73>n del sistema de archivos \textit{ext2} con capacidades de \textit{journaling}. El \textit{Journaling} es utilizado para seguir cambios de archivos y tiene como prop<6F>sito asegurar que las transacciones sean procesadas de forma adecuada; adicionalmente permite arreglar da<64>os en el sistema de archivos originados por una falla en la fuente de alimentaci<63>n de la plataforma.
|
|||
|
|
|||
|
\item \textbf{ReiserFS}: Este sistema de archivos al igual que \textit{ext3} utiliza \textit{journaling}. Fu<46> creado con el f<>n de aumentar el desempe<70>o frente al sistema \textit{ext2}, es un sistema eficiente en espacio, y mejora el manejo de grandes directorios.
|
|||
|
|
|||
|
\item \textbf{Journalling FIle FLash System 2 (JFFS2)}: Sistema creado para trabajar con dispositivos Flash, los cuales son utilizados ampliamente en aplicaciones embebidas.
|
|||
|
|
|||
|
\item \textbf{Compresed ROM file system (cramfs)}: Sistema de solo lectura, es utilizado cuando se dispone de una peque<75>a memoria flash NOR. El m<>ximo tama<6D>o de cramfs es de 256MB. Los archivos en este sistema de archivos se encuentran comprimidos.
|
|||
|
|
|||
|
\item \textbf{Network File System}: Permite montar particiones de disco o directorios de sistemas remotos como un sistema de archivos local, esto permite compartir recursos como unidades de CDs, DVDs u otro medio de almacenamiento masivo. Por otro lado, reduce el tiempo de desarrollo ya que no es necesario transferir archivos entre el sitio donde se encuentran las herramientas de desarrollo y la plataforma.
|
|||
|
|
|||
|
\item \textbf{Pseudo File System} Este sistema de archivos es utilizado por Linux para representar el estado actual del kernel. Este sistema de archivos est<73> montado en el directorio \textit{/proc}, y dentro de <20>l podemos encontrar informaci<63>n detallada del hardware del sistema. Adicionalmente algunos archivos pueden ser manipulados para informar al kernel cambios en la configuraci<63>n. Este sistema de archivos es virtual y es constantemente actualizado por el kernel. Los archivos \textit{/proc/cpuinfo}, \textit{/proc/interrupt}, \textit{/proc/devices}, \textit{/proc/mounts} Proporcionan informaci<63>n sobre los dispositivos Hardware de la plataforma
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
|
|||
|
\subsubsection{Estructura del Sistema de Archivos}
|
|||
|
Todas las distribuciones de linux se basan en el standard \textit{Filesystem Hierarchy Standard \footnote{}} utilizado en los sistemas operativos UNIX. Este standard permite que los programas y los usuarios conozcan de antemano la localizaci<63>n de los archivos instalados. Los siguientes directorios o links simb<6D>licos son de uso obligatorio:
|
|||
|
|
|||
|
\begin{enumerate}
|
|||
|
|
|||
|
\item \textbf{bin} Ejecutables esenciales.
|
|||
|
\item \textbf{boot} Archivos est<73>ticos del boot loader.
|
|||
|
\item \textbf{dev} Archivos de dispositivos.
|
|||
|
\item \textbf{etc} Configuraci<63>n espec<65>fica del host.
|
|||
|
\item \textbf{lib} Librer<65>as esenciales y m<>dulos de kernel.
|
|||
|
\item \textbf{media} Punto de montaje para sispositivos removibles.
|
|||
|
\item \textbf{mnt} Punto de montaje temporal.
|
|||
|
\item \textbf{opt}
|
|||
|
\item \textbf{sbin} Ejecutables esenciales del sistema.
|
|||
|
\item \textbf{srv} Datos de servicios suministrados por el sistema.
|
|||
|
\item \textbf{tmp} Archivos temporales.
|
|||
|
\item \textbf{usr} Segunda jerarqu<71>a.
|
|||
|
\item \textbf{var} Datos variables.
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
\subsection{Primer Programa en Espacio de Usuario \textit{init}}
|
|||
|
|
|||
|
Como vimos anteriormente, la primera aplicaci<63>n en espacio de usuario que ejecuta el kernel es \textit{/sbin/init}, todos los procesos que no sean del kernel son generados de forma directa o indirecta por <20>l y es responsable de la inicializaci<63>n de los scripts y terminales. Su papel m<>s importante es generar procesos adicionales bajo la direcci<63>n de un archivo de configraci<63>n especial \textit{/etc/inittab}
|
|||
|
|
|||
|
\subsubsection{Modos de operaci<63>n}
|
|||
|
Existen dos modos de operaci<63>n en Linux: Modo usuario simple y Multi-usuario, en el primero solo se activa una l<>nea de comandos y el <20>nico usuario que puede utilizarla es el super-usuario \textit{root}; es utilizado para sistemas en mantenimiento y normalmente se le asigna el nivel de ejecuci<63>n 1. En este nivel de ejecuci<63>n, no existen procesos demonios\footnote{Proceso que se ejecuta de forma discreta sin intervenci<63>n del usuario y es activado por la ocurrencia de una condici<63>n espec<65>fica} en ejecuci<63>n, y la interfaz de red no est<73> configurada\cite{JF}.
|
|||
|
|
|||
|
El modo multi-usuario es el modo normal de ejecuci<63>n del sistema Linux, cuando Linux inicia en este modo se ejecutan los siguientes procesos:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Se revisa el estado del sistema de archivos con \textit{fsck}.
|
|||
|
\item Se monta en sistema de archivos.
|
|||
|
\item \textit{init} analiza el archivo \textit{/etc/inittab} y
|
|||
|
\begin{itemize}
|
|||
|
\item Determina el nivel de ejecuci<63>n
|
|||
|
\item Ejecuta los scripts asociados con este nivel de ejecuci<63>n.
|
|||
|
\end{itemize}
|
|||
|
\item Inicializa los demonios.
|
|||
|
\item Permite el acceso a usuarios.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\subsubsection{Niveles de ejecuci<63>n}
|
|||
|
Un nivel de ejecuci<63>n puede entenderse como un estado del sistema Hoy d<>a, la mayor<6F>a de las distribuciones utilizan los siguientes niveles de ejecuci<63>n\cite{JF}:
|
|||
|
\begin{enumerate}
|
|||
|
\item 0. Cierre o detenci<63>n del sistema (\textit{halt}).
|
|||
|
\item 1. Modo usuario simple para configuraci<63>n del sistema y mantenimiento.
|
|||
|
\item 2. Modo multi-usuario sin red remota.
|
|||
|
\item 3. Modo multi-usuario con red. Este es el modo de operaci<63>n normal de un usuario de un sistema sin capacidades gr<67>ficas.
|
|||
|
\item 4. No utilizado - Definido por el usuario.
|
|||
|
\item 5. Modo multi-usuario con interf<72>z gr<67>fica.
|
|||
|
\item 6. Re-inicializaci<63>n del sistema (\textit{reboot}).
|
|||
|
\end{enumerate}
|
|||
|
|
|||
|
El nivel de ejecuci<63>n pude ser cambiado por el super-usuario (\textit{root}) en cualquier momento utilizando el comando \textit{init n}, donde \textit{n} es el nivel de ejecuci<63>n deseado.
|
|||
|
|
|||
|
\subsubsection{El Archivo \textit{/etc/inittab}}
|
|||
|
Como se mencion<6F> anteriormente el programa \textit{init} est<73> encargado de montar el sistema de archivos y de analizar el archivo \textit{/etc/inittab}. Este archivo contiene:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Una entrada para el nivel de ejecuci<63>n por defecto. Nivel de ejecuci<63>n en que inicia el sistema a menos que especifique otra cosa en el boot loader.
|
|||
|
\item Entradas que deben ser ejecutadas en todos o en un espec<65>fico nivel de ejecuci<63>n, su sint<6E>xis es:
|
|||
|
\textit{id:runlevels:action:process [arguments]}
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{id} Cualquier cosa.
|
|||
|
\item \textit{runlevels} Puede ser un n<>mero o lista de n<>meros de 0 a 6.
|
|||
|
\item \textit{action} Acci<63>n a tomar:
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{respawn} El proceso debe ser re-iniciado una vez finalice.
|
|||
|
\item \textit{wait start} Ejecuta el proceso cuando se ingresa al nivel de ejecuci<63>n y espera por su terminaci<63>n.
|
|||
|
\item \textit{bootwait} El proceso debe ser ejecutado durante la incializaci<63>n del sistema.
|
|||
|
\item \textit{initdefault} Especifica el nivel de ejecuci<63>n al que se ingresa despu<70>s de la inicializaci<63>n del sistema.
|
|||
|
\item \textit{sysinit} El proceso debe ejecutarse durante la inicializaci<63>n del sistema. Debe ejecutarse antes de cualquier entrada \textit{boot} o \textit{bootinit}
|
|||
|
\end{itemize}
|
|||
|
\item \textit{process} Programa o script a ser ejecutado.
|
|||
|
\end{itemize}
|
|||
|
\end{itemize}
|
|||
|
En el siguiente listado se muestra un archivo \textit{inittab} t<>pico:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
# The default runlevel.
|
|||
|
id:5:initdefault:
|
|||
|
|
|||
|
# Boot-time system configuration/initialization script.
|
|||
|
# This is run first except when booting in emergency (-b) mode.
|
|||
|
si::sysinit:/etc/init.d/rcS
|
|||
|
|
|||
|
# What to do in single-user mode.
|
|||
|
~~:S:wait:/sbin/sulogin
|
|||
|
|
|||
|
# /etc/init.d executes the S and K scripts upon change
|
|||
|
# of runlevel.
|
|||
|
|
|||
|
l0:0:wait:/etc/init.d/rc 0
|
|||
|
l1:1:wait:/etc/init.d/rc 1
|
|||
|
l2:2:wait:/etc/init.d/rc 2
|
|||
|
l3:3:wait:/etc/init.d/rc 3
|
|||
|
l4:4:wait:/etc/init.d/rc 4
|
|||
|
l5:5:wait:/etc/init.d/rc 5
|
|||
|
l6:6:wait:/etc/init.d/rc 6
|
|||
|
# Normally not reached, but fallthrough in case of emergency.
|
|||
|
z6:6:respawn:/sbin/sulogin
|
|||
|
S:2345:respawn:/sbin/getty 115200 ttyS0
|
|||
|
# /sbin/getty invocations for the runlevels.
|
|||
|
|
|||
|
1:2345:respawn:/sbin/getty 38400 tty1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En este archivo se define el nivel de ejecuci<63>n 5 como el nivel por defecto. El primer script en ejecutarse es \textit{/etc/init.d/rcS} (ya que su acci<63>n es del tipo \textit{sysinit}). Luego se ingresa al nivel de ejecuci<63>n 5 y se ejecuta el script \textit{/etc/init.d/rc} pas<61>ndole el argumento ``5'' y espera hasta que el script se complete. \textit{/etc/init.d/rc} ejecuta los scripts localizados en directorios individuales para cada nivel: \textit{/etc/rcX.d} (X un entero de 0 a 6); el nombre de los archivos localizados en estos directorios deben comenzar con el caracter ``\textbf{S}'' (para iniciar procesos) o ``\textbf{K}'' (para ``matar'' procesos), y dos caracteres num<75>ricos: \textit{S[0-9][0-9]}, \textit{S[0-9][0-9]}. Un script t<>pico de inicializaci<63>n del demonio del servidor web \textit{cherokee} se muestra en el siguiente listado (\textit{/etc/rc5.d/S91cherokee}):
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#!/bin/sh
|
|||
|
DAEMON=/usr/sbin/cherokee
|
|||
|
CONFIG=/etc/cherokee/cherokee.conf
|
|||
|
PIDFILE=/var/run/cherokee.pid
|
|||
|
NAME="cherokee"
|
|||
|
DESC="Cherokee http server"
|
|||
|
|
|||
|
test -r /etc/default/cherokee && . /etc/default/cherokee
|
|||
|
test -x "$DAEMON" || exit 0
|
|||
|
test ! -r "$CONFIG" && exit 0
|
|||
|
|
|||
|
case "$1" in
|
|||
|
start)
|
|||
|
echo "Starting $DESC: "
|
|||
|
start-stop-daemon --oknodo -S -x $DAEMON -- -b -C $CONFIG
|
|||
|
;;
|
|||
|
|
|||
|
stop)
|
|||
|
echo "Stopping $DESC:"
|
|||
|
start-stop-daemon -K -p $PIDFILE
|
|||
|
;;
|
|||
|
|
|||
|
restart)
|
|||
|
$0 stop >/dev/null 2>&1
|
|||
|
$0 start
|
|||
|
;;
|
|||
|
|
|||
|
*)
|
|||
|
echo "Usage: $0 {start|stop|restart}"
|
|||
|
exit 0
|
|||
|
;;
|
|||
|
esac
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como podemos ver existen tres par<61>metros que podemos pasar al script: \textit{start}, \textit{stop} y \textit{restart}, cuyas acciones son iniciar, detener y reiniciar el demonio respectivamente. El directorio \textit{/etc/init.d} contiene todos los scripts utilizados en los diferentes niveles de ejecuci<63>n, el nombre de ellos en este directorio no incluyen los caracteres \textit{S[0-9][0-9]} o \textit{K[0-9][0-9]}.
|
|||
|
|
|||
|
La l<>nea \textit{S:2345:respawn:/sbin/getty 115200 ttyS0} inicia una consola por el puerto serial \textit{/dev/ttyS0} con una velocidad de 9200 baudios, cuando el nivel de ejecucion sea 2, 3, 4 o 5. Finalmente se crea una terminal virtual para los niveles de ejecuci<63>n multi-usuario.
|
|||
|
|
|||
|
Cuando el super-usuario cambia el nivel de ejecuci<63>n con el comando \textit{init}, los procesos <20>nicos al nievel anterior son terminados y los procesos <20>nicos del nuevo nivel son iniciados.
|
|||
|
|
|||
|
\subsection{Distribuciones Linux}
|
|||
|
Aunque es posible construir el sistema de atchivos nosotros mismos, no es nada pr<70>ctico ya que es una tarea tediosa que requiere cierto nivel de experiencia. En la actualidad, existen varias distribuciones que realizan estas tareas por nosotros, dentro de las m<>s utilizadas se encuentran:
|
|||
|
|
|||
|
\subsubsection{Busybox}
|
|||
|
Dise<EFBFBD>ado para optimizar el tama<6D>o y rendimiento de aplicaciones embebidas, BusyBox \footnote{http://www.busybox.net/} combina en un solo ejecutable m<>s de 70 utilidades est<73>ndares UNIX, en sus versiones ligeras. BusyBox es considerada la navaja suiza de los sistema embebidos, dado que permite sustituir la gran mayor<6F>a de utilidades que se suelen localizar en los paquetes GNU fileutils, shellutils, findutils, textutils, modutils, grep, gzip, tar, etc.
|
|||
|
|
|||
|
Busybox hace parte de la mayor<6F>a de distribuciones de Linux para sistemas embebidos y en la actualidad proporciona las siguientes funciones:
|
|||
|
|
|||
|
\textit{
|
|||
|
addgroup, adduser, adjtimex, ar, arping, ash, awk, basename, bunzip2, busybox, bzcat, cal, cat, chgrp,
|
|||
|
chmod, chown, chroot, chvt, clear, cmp, cp, cpio, crond, crontab, cut, date, dc, dd, deallocvt, delgroup,
|
|||
|
deluser, df, dirname, dmesg, dos2unix, dpkg, dpkg-deb, du, dumpkmap, dumpleases, echo, egrep, env, expr,
|
|||
|
false, fbset, fdflush, fdisk, fgrep, find, fold, free, freeramdisk, fsck.minix, ftpget, ftpput, getopt,
|
|||
|
getty, grep, gunzip, gzip, halt, head, hexdump, hostid, hostname, httpd, hwclock, id, ifconfig, ifdown,
|
|||
|
ifup, init, ip, ipaddr, ipcalc, iplink, iproute, iptunnel, kill, killall, klogd, last, length, linuxrc, ln,
|
|||
|
loadfont, loadkmap, logger, login, logname, logread, losetup, ls, makedevs, md5sum, mesg, mkdir, mkfifo,
|
|||
|
mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nameif, nc, netstat, nslookup, od, openvt, passwd,
|
|||
|
patch, pidof, ping, ping6, pivot\_root, poweroff, printf, ps, pwd, rdate, readlink, realpath, reboot,
|
|||
|
renice, reset, rm, rmdir, route, rpm, rpm2cpio, run-parts, sed, setkeycodes, sh, sha1sum, sleep, sort,
|
|||
|
start-stop-daemon, strings, stty, su, sulogin, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet,
|
|||
|
telnetd, test, tftp, time, top, touch, tr, traceroute, true, tty, udhcpc, udhcpd, umount, uname,
|
|||
|
uncompress, uniq, unix2dos, unzip, uptime, usleep, uudecode, uuencode, vi, vlock, watch, watchdog, wc,
|
|||
|
wget, which, who, whoami, xargs, yes, zcat}.
|
|||
|
|
|||
|
\subsubsection{Buildroot}
|
|||
|
Buildroot\footnote{http://buildroot.uclibc.org/} Es un grupo de \textit{Makefiles} y \textit{patches} que facilita la generaci<63>n de la cadena de herramientas y el sistema de archivos para un sistema embebido que usa Linux. Posee una interfaz que permite realizar de forma f<>cil la configuraci<63>n; utiliza busybox para generar la utilidades b<>sicas de Linux y permite adaptar software adicional de forma f<>cil \footnote{http://buildroot.uclibc.org/buildroot.html\#add\_software}.
|
|||
|
|
|||
|
\subsubsection{Openembedded}
|
|||
|
Al igual que Buildroot, el proyecto openembedded proporciona un entorno que permite generar la cadena de herramientas y el sistema de atchivos para un sistema embebido, utiliza busybox y permite la creaci<63>n de archivos que permiten compilar software que no se incluya en la distribuci<63>n original. Adicionalmente openembedded crea archivos de instalaci<63>n con un formato derivado del proyecto \textit{handhelds} \footnote{http://handhelds.org} \textit{ipk}, lo que permite la instalaci<63>n de paquetes de forma similar a la distribuci<63>n debian.
|
|||
|
|
|||
|
La informaci<63>n necesaria para generar una distribuci<63>n utilizando las herramientas de Openembedded se encuentra en http://www.emqbit.com/mediawiki/index.php/Main\_Page/ecb\_at91/OE.
|
|||
|
|
|||
|
\section{M<>dulos del kernel}
|
|||
|
Los m<>dulos son peque<75>as piezas de c<>digo que pueden ser cargadas y descargadas en el kernel en el momento que sea necesario. Ellos extienden la funcionalidad del kernel, sin la necesidad de reiniciar el sistema y recompilar el kernel. Por ejemplo, un tipo de m<>dulo es el controlador de dispositivo, el cual permite al kernel acceder a un dispositivo hardware conectado al sistema. Este tipo de m<>dulos ser<65>n estudiados en esta secci<63>n.
|
|||
|
|
|||
|
Existen tres tipos de dispositivos en Linux \cite{JCAR05}:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item Tipo Caracter: Puede accederse de forma similar a un archivo; este tipo de dispositivos permite por lo menos las operaciones \textit{open}, \textit{close}, \textit{read}. Ejemplos de este tipo de dispositivo son el puerto serie (\textit{/dev/ttyS0}) y la consola (\textit{/dev/console})
|
|||
|
\item Tipo Bloque: Este tipo de dispositivo puede hospedar un sistema de archivos; normalmente realiza operaci<63>nes de bloques de datos <20>nicamente; un ejemplo de este tipo de dispositivo es el disco duro (\textit{/dev/hda}).
|
|||
|
\item Red: Toda transacci<63>n de red se realiza a trav<61>s de una interfaz, esto es, un dispositivo hardware (\textit{/dev/eth0}) o software (\textit{loopback}) capaz de intercambiar datos con otros hosts.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.5]{./images/kernel_module} \end{center}
|
|||
|
\caption{ Interacci<63>n entre el <20>rea de usuario y el driver del dispositivo. Fuente: \cite{Mo05}}\label{kernel_module}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
|
|||
|
\subsection{Ejemplo de un driver tipo caracter}
|
|||
|
|
|||
|
Recuerde que una aplicaci<63>n en el <20>rea de usario, no puede acceder directamente al <20>rea del kernel; los dispositivos se acceden a trav<61>s de archivos de dispositivos, localizados en \textit{/dev} (ver figura \ref{kernel_module}), A continuaci<63>n se muestra la salida del comando \textit{ls -l /dev/}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
brw-rw---- 1 root disk 3, 0 Nov 27 hda
|
|||
|
brw-rw---- 1 root disk 3, 1 Nov 27 hda1
|
|||
|
brw-rw---- 1 root disk 3, 2 Nov 27 hda2
|
|||
|
crw-rw---- 1 root uucp 4, 64 Nov 27 ttyS0
|
|||
|
crw-rw---- 1 root uucp 4, 65 Nov 27 ttyS1
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
Los archivos tipo caracter est<73>n identificados por una \textit{``c''} en la primera columna, mientras que los dispositivos tipo bloque por una \textit{``b''}. Podemos observar que existen dos n<>meros (5ta y 6ta columna) que identifican al driver, el n<>mero de la 5ta columna recibe el nombre de \textit{major number} y el de la sexta \textit{minor number}; estos n<>meros son utilizados por el sistema operativo para determinar el dispositivo y el driver que deben ser accesados ante una solicitud a nivel de usuario.
|
|||
|
|
|||
|
El \textit{major number} identifica la clase o grupo del dispositivo, mientras que el \textit{minor number} se utiliza para identificar sub-dispositivos (Ver Figura \ref{major}).
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.5]{./images/major} \end{center}
|
|||
|
\caption{ \textit{major} y \textit{minor} footnote{http://uw713doc.sco.com/en/HDK\_concepts/ddT\_majmin.html} }\label{kernel_module}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
El kernel de linux permite que los drivers compartan el n<>mero mayor, como el caso del disco duro, hda posee dos particiones hda1 y hda2, las cuales son manejadas por el mismo driver, pero se asigna un n<>mero menor <20>nico a cada una; lo mismo sucede con el puerto serie.
|
|||
|
|
|||
|
\subsubsection{Implementaci<63>n del driver de un LED}
|
|||
|
A continuaci<63>n se realizar<61> la descripci<63>n de un driver tipo caracter para un dispositivo muy sencillo, un LED \cite{OPPS05}. Este ejemplo fue implementado en un procesador PXA255 de Intel y realiza las siguientes operaciones:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item \textit{init}: Se ejecuta cuando se carga el m<>dulo, el LED se apagar<61>.
|
|||
|
\item \textit{close}: Se ejecuta cuando se descarga el m<>dulo, el LED se encender<65>.
|
|||
|
\item \textit{open}: Se ejecuta cuando se realiza una operaci<63>n de lectura o escritura al dispositivo.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
Existen dos funciones que deben estar presentes en todo tipo de m<>dulo, estas son: \textit{module\_init} y \textit{module\_exit} las cuales se ejecutan cuando se carga y descarga el m<>dulo respectivamente.
|
|||
|
|
|||
|
\begin{lstlisting}[firstnumber=40]
|
|||
|
struct file_operations fops = {
|
|||
|
.open = device_open,
|
|||
|
.release = device_release,
|
|||
|
};
|
|||
|
|
|||
|
static int __init blink_init(void)
|
|||
|
{
|
|||
|
printk(KERN_INFO "BLINK module is Up.\n");
|
|||
|
|
|||
|
Major = register_chrdev(0, DEVICE_NAME, &fops);
|
|||
|
|
|||
|
if (Major < 0) {
|
|||
|
printk(KERN_ALERT "Registering char device failed
|
|||
|
with %d\n", Major);
|
|||
|
return Major;
|
|||
|
}
|
|||
|
|
|||
|
printk(KERN_ALERT "I was assigned major number %d.
|
|||
|
To talk to\n", Major);
|
|||
|
printk(KERN_ALERT "the driver, create a dev file
|
|||
|
with\n");
|
|||
|
printk(KERN_ALERT "'mknod /dev/%s c %d 0'.\n",
|
|||
|
DEVICE_NAME, Major);
|
|||
|
|
|||
|
pxa_gpio_mode(GPIO_LED_MD);
|
|||
|
pxa_gpio_mode(GPIO_LED_OFF); /* Turn LED OFF*/
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void __exit blink_exit(void)
|
|||
|
{
|
|||
|
int ret;
|
|||
|
|
|||
|
ret = unregister_chrdev(Major, DEVICE_NAME);
|
|||
|
if ( ret < 0 )
|
|||
|
printk( KERN_ALERT "Error in unregister_chrdev:
|
|||
|
%d\n", ret );
|
|||
|
printk( KERN_INFO "BLINK driver is down...\n" );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
module_init(blink_init);
|
|||
|
module_exit(blink_exit);
|
|||
|
|
|||
|
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
MODULE_AUTHOR("Carlos Camargo UNAL");
|
|||
|
MODULE_DESCRIPTION("BLINKER LED driver");
|
|||
|
MODULE_VERSION("1:0.1");
|
|||
|
\end{lstlisting} \normalsize
|
|||
|
|
|||
|
Las funciones \textit{module\_init} \textit{module\_exit} deben ser declaradas como \textit{static} ya que no ser<65>n visibles fuera del archivo. Como puede observarse en la l<>nea 83 se hace la definici<63>n de las funciones que deben ejecutarse al cargar y descargar el m<>dulo en nuestro caso \textit{blink\_init} y \textit{blink\_exit} respectivamente. La informaci<63>n sobre el m<>dulo aparece en las l<>neas 87-90.
|
|||
|
|
|||
|
En la l<>nea 40 se define la estructura de operaciones de archivo del m<>dulo; cada campo de la estructura corresponde a la direcci<63>n de una funci<63>n definida por el driver para manejar una solicitud determinada. En nuestro caso solo existe una funci<63>n \textit{open}, la cual ser<65> definida m<>s adelante.
|
|||
|
|
|||
|
Como se puede ver en la figura \ref{kernel_module} es necesario que el kernel sepa que driver est<73> encargado del dispositivo, esto es, el \textit{major number} del driver que lo maneja; por esto, lo primero que se debe hacer es obtener este n<>mero. En la funci<63>n \textit{blink\_init} (l<>nea 49) podemos observar la forma en que se realiza el registro de nuestro dispositivo. La funci<63>n \textit{register\_chrdev} retorna el n<>mero mayor asignado de forma din<69>mica, esto es recomendable ya que si se fijara un n<>mero de forma arbitaria, podr<64>a causar conflictos con otros dispositivos. De esta forma, al cargar el m<>dulo con el comando: \textit{insmod blinker.ko}, el LED se apagar<61> y aparecer<65> el siguiente mensaje en la consola:
|
|||
|
|
|||
|
\footnotesize
|
|||
|
\begin{lstlisting}[numbers=none]
|
|||
|
BLINK module is Up.
|
|||
|
I was assigned major number 253. To talk to
|
|||
|
the driver, create a dev file with
|
|||
|
'mknod /dev/blink c 253 0'.
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Con lo anterior, nuestro dispositivo es registrado y se le asigna el n<>mero 253 como \textit{major number}, en el archivo \textit{/proc/devices} aparecen los dispositivos que actualmente est<73>n siendo utilizados por el kernel, este archivo debe contener una entrada para blink de la forma: \textit{253 blink}.
|
|||
|
|
|||
|
En la funci<63>n \textit{blink\_exit} se realiza la liberaci<63>n del dispositivo ( la funci<63>n \textit{unregister\_chrdev}, l<>nea 75), la cual se ejecuta cuando se lanza el comando: \textit{rmmod blinker.ko}, el que a su vez hace que se encienda el LED y se imprima en la consola el mensaje:
|
|||
|
|
|||
|
\footnotesize
|
|||
|
\begin{lstlisting}[numbers=none]
|
|||
|
BLINK driver is down...
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Como se mencion<6F> anteriormente es posible manejar un archivo tipo caracter como si fuera un archivo de texto, por lo tanto, es posible adicionar funciones a las acciones de abrir, cerrar, escribir en o leer del dispositivo.
|
|||
|
|
|||
|
\begin{lstlisting}[firstnumber=20, numbers=right]
|
|||
|
static int device_open(struct inode *inode, \
|
|||
|
struct file *file)
|
|||
|
{
|
|||
|
unsigned int i;
|
|||
|
printk( KERN_INFO "Open BLINKER\n" );
|
|||
|
if (is_device_open)
|
|||
|
return -EBUSY;
|
|||
|
|
|||
|
is_device_open = 1;
|
|||
|
|
|||
|
for( i=0; i<5; i++ ){
|
|||
|
pxa_gpio_mode(GPIO_LED_ON);
|
|||
|
mdelay(0x0080);
|
|||
|
pxa_gpio_mode(GPIO_LED_OFF);
|
|||
|
mdelay(0x0080);
|
|||
|
}
|
|||
|
|
|||
|
try_module_get(THIS_MODULE);
|
|||
|
return SUCCESS;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Esta secci<63>n de c<>digo se ejecuta cada vez que el archivo de dispositivo /dev/blink es abierto, esto sucede en operaciones de lectura o escritura. Es decir si se utilizan los siguientes comandos:
|
|||
|
|
|||
|
\begin{lstlisting}[numbers=none]
|
|||
|
more /dev/blink
|
|||
|
cat file > /dev/blink
|
|||
|
cp file /dev/blink
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Con cada uno de estos comandos el LED se encender<65> y apagar<61> y en la consola se despliega el mensaje:
|
|||
|
|
|||
|
\begin{lstlisting}[numbers=none]
|
|||
|
Open BLINKER
|
|||
|
Close BLINKER
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\section{Interfaz con Perif<69>ricos dedicados}
|
|||
|
Es com<6F>n que algunas aplicaciones requieran ciertos perif<69>ricos especiales que les permitan cumplir las restricciones temporales, es decir, es necesario crear tareas Hardware que ayuden a las tareas software a cumplir con las restricciones de dise<73>o. Para esto es necesario implementar algunas funciones en perif<69>ricos externos al procesador. Si la tarea no se encuentra implementada en un dispositivo comercial es necesario implementarlas en un Dispositivo L<>gico Programable (PLD) o en un Circuito Integrado de Aplicaci<63>n Espec<65>fica (ASIC).
|
|||
|
|
|||
|
En esta secci<63>n realizaremos una explicaci<63>n detallada del proceso de comunicaci<63>n entre el procesador y un perif<69>rico implementado en una FPGA.
|
|||
|
|
|||
|
\subsection{Comunicaci<63>n Procesador - Perif<69>rico}
|
|||
|
La figura \ref{computer_arch} muestra una arquitectura b<>sica para la comunicaci<63>n de tareas Hardware - Software; en ella podemos observar que el procesador maneja tres buses:
|
|||
|
\begin{itemize}
|
|||
|
\item Bus de Datos: Bus bidireccional por donde se realiza el intercambio de informaci<63>n.
|
|||
|
\item Bus de Direcciones: Bis controlado por el procesador y es utilizado para direccionar un determinado perif<69>rico o una detrminada funcionalidad del mismo.
|
|||
|
\item Bus de control: Se<53>ales necesarias para indicarle a los perif<69>ricos el tipo de comunicaci<63>n (Lectura o escritura).
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.6]{./images/computer-simple} \end{center}
|
|||
|
\caption{Arquitectura b<>sica Hardware/Software}\label{computer_arch}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
Todos los perif<69>ricos que requieren intercambio de informaci<63>n con el procesador comparten el mismo bus de datos, por lo que es necesario que mientras el procesador no se comunique con ellos permanezcan en estadp de alta impedancia, esto es necesario para evitar corto - circuitos originados por diferentes niveles l<>gicos en el bus. Por lo tanto, las comunicaciones siempre son iniciadas por el procesador y se selecciona uno y solo un perif<69>rico. El decodificador de direcciones es el encargado de habilitar un determinado perif<69>rico ante una solicitud del procesador (mediante una direcci<63>n de memoria), esto lo hace activando la se<73>al \textit{CSX}, cuando esta se<73>al se encuentra en estado l<>gico alto el perif<69>rico coloca su bus de datos en alta impedancia, si se encuentra en estado l<>gico bajo el perif<69>rica escribe o lee el bus de datos, dependiendo de la activaci<63>n de las se<73>ales del bus de control RD y WR.
|
|||
|
|
|||
|
El decodificador de direcciones, como su nombre lo indica utiliza como entradas el bus de direcciones y activa solo una se<73>al de selecci<63>n de Chip (\textit{CSx}), bas<61>ndose en un rango de direcciones asignado a cada perif<69>rico, este rango de direcciones no debe traslaparse para asegurar que solo un chip es seleccionado. Este rango de direcciones que se asigna a cada dispositivo que puede ser accesado por la unidad de procesamiento recibe el nombre de \textit{mapa de memoria} y puede ser <20>nico para cada plataforma.
|
|||
|
|
|||
|
Cuando la unidad de procesamiento necesite comunicarse con un determinado perif<69>rico, colocar<61> en el bus de direcciones una valor que se encuentre en el rango de direcciones asignado para ese perif<69>rico, esto hace que el decodificador de direcciones active la se<73>al de selecci<63>n adecuada para informarle al perif<69>rico que el procesador va a iniciar una transferencia de informaci<63>n. La Figura \ref{rd_wr_timing} muestra el diagrama de tiempos para un ciclo de lectura y escritura del procesador.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/rd_wr_waveform} \end{center}
|
|||
|
\caption{Ciclo de lectura y escritura para la arquitectura de la Figura \ref{computer_arch}}\label{rd_wr_timing}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
De lo anterior podemos concluir que un perif<69>rico es visto por el procesador como una posici<63>n de memoria m<>s y las transacciones las inicia <20>nicamente el procesador.
|
|||
|
|
|||
|
\subsubsection{Implementaci<63>n de Perif<69>ricos en una FPGA}
|
|||
|
Es importante tener en cuenta los siguientes items cuando se implemente una tarea Hardware en una FPGA:
|
|||
|
\begin{itemize}
|
|||
|
\item La frecuencia del reloj de la FPGA es mucho mayor que la de las se<73>ales del bus de control, por lo que es necesario asegurarse que cada vez que el procesador realiza una solicitud de lectura o escritura, la se<73>al de activaci<63>n cambia del estado l<>gico alto al bajo; si solo se tiene en cuenta el estado bajo de la se<73>al \textit{CSX} el perif<69>rico puede ejecutar la tarea varias veces en el mismo ciclo de activaci<63>n, lo que puede llevar a resultados incorrectos.
|
|||
|
\item La fase de los relojes del procesador y la FPGA no es la misma, por lo que es necesario sincronizar las se<73>ales del procesador con el reloj de la FPGA; si esto no se hace las se<73>ales fuera de fase pueden originar un estado de metaestabilidad en los Flip-Flops internos y por lo tanto el mal-funcionamiento del sistema.
|
|||
|
\item El bus de datos es bidireccional, por lo que es necesario que la FPGA lo coloque en alta impedancia cuando no se est<73> habilitando un perif<69>rico.
|
|||
|
\item La FPGA no permite implementar buffers tri-estado internamente por lo que es necesario separar los buses de entrada y salida a cada perif<69>rico. El bus de entrada es com<6F>n a todos los perif<69>ricos mientra que es necesario utilizar un esquema de multiplexaci<63>n entre los buses de salida.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
La figura \ref{sw_hw_fpga_arch} muestra el diagrama de bloques de la interfaz necesaria para poder comunicar un grupo de perif<69>ricos o tareas Hardware con el bus de datos, direcci<63>n y control de un procesador. El bloque \textit{SYNC} se encarga de sincronizar las se<73>ales provenientes de la FPGA con el reloj interno de la misma.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/sw_hw_fpga_arch} \end{center}
|
|||
|
\caption{Diagrama de Bloques para la comunicaci<63>n de tareas HW-SW \ref{computer_arch}}\label{sw_hw_fpga_arch}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
El m<>dulo \textit{Write Pulse generator} genera un pulso cuando las se<73>ales \textit{sncs} y \textit{snwe} son activadas como se indica en la figura \ref{cs_we_pulse}. El decodificador de direcciones selecciona un determinado perif<69>rico dependiendo del rango especificado para cado uno. Como mencionamos anteriormente, las FPGAs no permiten implementar buffers tri-estado internamente , por lo que cada perif<69>rico debe tener un bus de entrada y uno de salida de datos, los buses de entrada de datos son comunes, mientras que los de salida deben ser manejados por un dispositivo de salida, el cual puede ser un multiplexor controlado por el decodificador de direcciones o una compuerta OR, para este <20>ltimo caso es necesario que los perif<69>ricos coloquen el bus de datos en ``0'' cuando no est<73>n seleccionados. Finalmente es necesario colocar un buffer tri-estado en los pines de la FPGA, este buffer est<73> controlado por las se<73>ales \textit{nwe, noe, ncs} y solo se activa cuando \textit{nwe = 1, noe = 0, ncs = 0}, es decir, cuando se selecciona el rango de memoria de la FPGA y el procesador inicia una operaci<63>n de lectura.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/cs_we_pulse} \end{center}
|
|||
|
\caption{Generaci<63>n del pulso de escritura}\label{cs_we_pulse}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
\subsubsection{Programa en Espacio de Usuario para la comunicaci<63>n}
|
|||
|
El kernel de Linux proporciona una interfaz que permite a una aplicaci<63>n \textit{mapear} un archivo en memoria, lo que hace que exista una correspondencia uno a uno entre las direcciones de memoria y el contenido del archivo. Linux implementa la llamada de sistema \textit{mmap()} para \textit{mapear} objetos en memoria.\cite{RL07}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#include <sys/mman.h>
|
|||
|
|
|||
|
void * mmap (void *addr,
|
|||
|
size_t len,
|
|||
|
int prot,
|
|||
|
int flags,
|
|||
|
int fd,
|
|||
|
off_t offset);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
Un llamado a \textit{mmap()} le pide al kernel hacer un mapeo en la memoria de \textit{len} bytes del objeto representado por el descriptor de archivo \textit{fd}, comenzando a \textit{offset} bytes dentro del archivo. Si se especifica \textit{addr}, se utiliza este valor como la direcci<63>n inicial en la memoria. Los permisos de acceso son determinados por \textit{prot}; PROT\_READ habilita la lectura, PROT\_WRITE habilita escritura y PROT\_EXEC habilita la ejecuci<63>n. El argumento \textit{flasgs} describe el tipo de mapeo, y algunos elementos de su comportamiento y puede tomar los valores:
|
|||
|
|
|||
|
\begin{itemize}
|
|||
|
\item MAP\_FIXED: hace que \textit{addr} sea un requerimiento, si el kernel es incapaz de hacer el mapeo en esta direcci<63>n el llamado falla, si los par<61>metros de direcci<63>n y longitud traslapan un mapeo existente se descartan las <20>reas que se traslapan y se remplazan por el nuevo mapeo.
|
|||
|
\item MAP\_PRIVATE: Establece que el mapeo no es compartido. Los cambios realizados a la memoria por este proceso no se reflejan en el archivo actual o en el mapeo de los otros procesos.
|
|||
|
\item MAP\_SHARED: Comparte el mapeo con otros procesos que usan el mismo archivo. Escribir en el mapeo equivale a escribir en el archivo.
|
|||
|
\end{itemize}
|
|||
|
|
|||
|
A continuaci<63>n se lista un ejemplo de la utilizaci<63>n del llamado \textit{mmap}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
#define MAP_SIZE 0x2000000l // ECBOT USE A11 to A25
|
|||
|
#define MAP_MASK (MAP_SIZE - 1)
|
|||
|
|
|||
|
int fd;
|
|||
|
unsigned long i, j;
|
|||
|
void *base;
|
|||
|
volatile unsigned short *virt_addr;
|
|||
|
|
|||
|
io_map(0xFFFFFF7C); // Configure CS3 as 16 bit Memory and 0 Wait States
|
|||
|
off_t address = 0x40000000; // CS3 Base Address
|
|||
|
|
|||
|
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC)) == -1){
|
|||
|
printf ("Cannot open /dev/mem.\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
printf ("/dev/mem opened.\n");
|
|||
|
|
|||
|
base = mmap (0, MAP_SIZE, PROT_READ | PROT_WRITE,
|
|||
|
MAP_SHARED, fd, address);
|
|||
|
if (base == (void *) -1){
|
|||
|
printf ("Cannot mmap.\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
printf ("Memory mapped at address %p.\n", base);
|
|||
|
|
|||
|
virt_addr = base;
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En este ejemplo utilizamos el llamado \textit{mmap} para hacer un mapeo de la direcci<63>n de memoria correspondiente al CS3 (0x40000000). El descriptor del archvio utilizado es el dispositivo \textit{/dev/mem} el cual permite operaciones de lectura y escritura a la memoria virtual. Adicionalmente permitimos operaciones de lectura/escritura (PROT\_READ | PROT\_WRITE) y permitimos el acceso a otros proceso. Finalmente podemos usar la variable \textit{virt\_addres} para escribir en cualquier posici<63>n de memoria desde \textit{0x40000000} hasta \textit{0x40000000 + MAP\_SIZE}. El siguiente listado muestra un ejemplo de la forma de hacer estas operaciones.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
printf("Writing Memory..\n");
|
|||
|
for (i = 0 ; i <32; i++){
|
|||
|
virt_addr[i<<10] = i*3; // ECBOT use A11 to A25
|
|||
|
}
|
|||
|
|
|||
|
printf("Reading Memory..\n");
|
|||
|
for (i = 0 ; i < 32; i++)
|
|||
|
{
|
|||
|
j = virt_addr[i<<10];
|
|||
|
printf("%X = %X\n", i, j );
|
|||
|
}
|
|||
|
if (munmap (base, MAP_SIZE) == -1)
|
|||
|
{
|
|||
|
printf ("Cannot munmap.\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
\subsection{Comunicaci<63>n Perif<69>rico - Procesador}
|
|||
|
|
|||
|
Cuando un perif<69>rico requiere atenci<63>n por parte de la CPU debido a que termin<69> de realizar un proceso o porque requiere nuevas instrucciones para seguir operando, o un evento originado por un usuario necesita ser atendido, se debe iniciar un proceso para que la unidad de procesamiento se comunique con <20>l. Como se mencion<6F> anteriormente la unidad de procesamiento est<73> encargada de forma exclusiva de iniciar las operaciones de lectura/ecritura con los perif<69>ricos, por esta raz<61>n, el perif<69>rico utiliza una se<73>al (IRQ) para informarle al procesador que requiere ser atendido. Algunas arquitecturas poseen un mecanismo que permite el acceso a la memoria por parte de los perif<69>ricos sin utilizar el procesador, esto permite que perif<69>ricos de diferentes velocidades se comuniquen sin someter al procesador a una carga excesiva. En esta secci<63>n hablaremos de la forma de definir las interrupciones en un driver de Linux.
|
|||
|
|
|||
|
\subsubsection{Manejo de Interrupciones}
|
|||
|
A continuaci<63>n se describir<69> la forma de manejar las interrupciones utilizando un driver de Linux. Analicemos la funci<63>n \textit{qem\_init}
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static int __init qem_init(void)
|
|||
|
{
|
|||
|
int res;
|
|||
|
printk(KERN_INFO "FPGA module is Up.\n");
|
|||
|
|
|||
|
Major = register_chrdev(0, DEVICE_NAME, &fops);
|
|||
|
|
|||
|
if (Major < 0) {
|
|||
|
return Major;
|
|||
|
}
|
|||
|
|
|||
|
/* Set up the FGPA irq line */
|
|||
|
at91_set_gpio_input(FPGA_IRQ_PIN, 0);
|
|||
|
at91_set_deglitch(FPGA_IRQ_PIN, 1);
|
|||
|
|
|||
|
res = request_irq(FPGA_IRQ_PIN, irq_handler, IRQF_DISABLED, "FPGA - IRQ", NULL);
|
|||
|
|
|||
|
set_irq_type(FPGA_IRQ, IRQT_RISING);
|
|||
|
|
|||
|
ioaddress = ioremap(FPGA_BASE, 0x4000);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Esta rutina es similar a la presentada anteriormente, solo se agrega un par de comandos para definir un pin del procesador como entrada, para poder utilizarlo como se<73>al IRQ, en la l<>nea:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
res = request_irq(FPGA_IRQ_PIN, irq_handler, IRQF_DISABLED, "FPGA - IRQ", NULL);
|
|||
|
request_irq (int irq, handler, irqflags, devname, dev_id);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Se hace un llamado a la funci<63>n \textit{request\_irq} que asigna recursos a la interrupci<63>n, habilita el manejador y la l<>nea de interrupci<63>n. En nuestro caso define el pin \textit{FPGA\_IRQ\_PIN} como la l<>nea de interrupci<63>n, la rutina \textit{irq\_handler} ser<65> ejecutada cuando se presente una interrupci<63>n, el flag \textit{IRQF\_DISABLED} deshabilita las interrupciones locales mientras se procesa, el nombre del dispositivo que realiza la interrupci<63>n es \textit{FPGA - IRQ}.
|
|||
|
|
|||
|
La funci<63>n \textit{ioremap(offset, size)}, una secuencia de operaciones que permiten que la memoria de la CPU se pueda acceder con las funciones \textit{readb/readw/readl/writeb/writew/write}, utilizando la variable \textit{ioaddress}. Finalmente se define el tipo de interrupci<63>n del pin \textit{FPGA\_IRQ\_PIN} como \textit{IRQT\_RISING}.
|
|||
|
|
|||
|
La funci<63>n que se ejecuta cuando se presenta la interrupci<63>n, se define en el siguiente listado:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
|
|||
|
{
|
|||
|
if(irq_enabled)
|
|||
|
{
|
|||
|
interrupt_counter++;
|
|||
|
printk(KERN_INFO "interrupt_counter=%d\n",interrupt_counter);
|
|||
|
printk("\n kernel: IREG_LP:%X \n", readb( &ioaddress[0x40] ) );
|
|||
|
wake_up_interruptible(&wq);
|
|||
|
}
|
|||
|
return IRQ_HANDLED;
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Cada vez que se produce una interrupci<63>n y si la variable global \textit{irq\_enabled} es igual a 1, se aumenta en 1 el valor de \textit{interrupt\_counter}, se imprime su valor y el de un registro interno del perif<69>rico.
|
|||
|
|
|||
|
En este driver utilizaremos la funci<63>n \textit{device\_read} para enviar informaci<63>n a un programa en espacio de usuario.
|
|||
|
\begin{lstlisting}
|
|||
|
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
|
|||
|
char *buffer, /* buffer to fill with data */
|
|||
|
size_t count, /* length of the buffer */
|
|||
|
loff_t * offset)
|
|||
|
{
|
|||
|
if(irq_enabled){
|
|||
|
wait_event_interruptible(wq, interrupt_counter!=0);
|
|||
|
copy_to_user ( buffer, &interrupt_counter, sizeof(interrupt_counter) );
|
|||
|
interrupt_counter=0;
|
|||
|
}
|
|||
|
else{
|
|||
|
interrupt_counter = -1;
|
|||
|
copy_to_user ( buffer, &interrupt_counter, sizeof(interrupt_counter) );
|
|||
|
}
|
|||
|
return sizeof(interrupt_counter);
|
|||
|
}
|
|||
|
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Cuando se realice una operaci<63>n de lectura desde espacio de usuario, el proceso quedar<61> bloqueado por la funci<63>n \textit{wait\_event\_interruptible} hasta que la rutina de atenci<63>n a la interrupci<63>n ejecute la funci<63>n \textit{wake\_up\_interruptible}, pero es necesario que se cumpla la condici<63>n evaluada por \textit{wait\_event\_interruptible} para que se ejecute la tarea. Para este ejemplo:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
wait\_event\_interruptible(wq, interrupt\_counter!=0);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Por lo que \textit{irq\_handler} debe hacer:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
interrupt_counter++;
|
|||
|
wake_up_interruptible(&wq);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Si no se hace esto el proceso nunca se despertar<61> y el proceso de lectura quedar<61> bloqueado.
|
|||
|
|
|||
|
En la l<>nea:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
copy_to_user ( buffer, &interrupt_counter, sizeof(interrupt_counter) );
|
|||
|
copy_to_user ( to, from, long n);
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
Se utiliza la funci<63>n \textit{copy\_to\_user} para intercambiar informaci<63>n con el programa que se ejecuta en espacio de usuario. En este caso se copia a \textit{char *buffer}, la variable \textit{interrupt\_counter}. Existe una funci<63>n an<61>loga que recibe informaci<63>n proveniente del espacio de usuario \textit{copy\_from\_user} En la Figura \ref{copy_to_from_user} se muestran estas operaciones.
|
|||
|
|
|||
|
\begin{figure}[h]
|
|||
|
\begin{center} \includegraphics[scale=.7]{./images/copy_to_from_user} \end{center}
|
|||
|
\caption{Intercambio de informaci<63>n entre los espacios de kernel y usuario\label{copy_to_from_user}}
|
|||
|
\end{figure}
|
|||
|
|
|||
|
En la funci<63>n \textit{qem\_exit} se liberan los recursos de la interrupci<63>n y la variable \textit{ioaddress}.
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
static void __exit qem_exit(void)
|
|||
|
{
|
|||
|
int ret;
|
|||
|
/*Tho order for free_irq, iounmap & unregister is very important */
|
|||
|
free_irq(FPGA_IRQ_PIN, NULL);
|
|||
|
iounmap(ioaddress);
|
|||
|
unregister_chrdev(Major, DEVICE_NAME);
|
|||
|
|
|||
|
printk(KERN_INFO "FPGA driver is down...\n");
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
|
|||
|
Finalmente el programa en espacion de usuario es:
|
|||
|
|
|||
|
\begin{lstlisting}
|
|||
|
int main(void) {
|
|||
|
|
|||
|
int fileNum, bytes;
|
|||
|
char data[40];
|
|||
|
|
|||
|
fileNum = open("/dev/fpga", O_RDWR);
|
|||
|
if (fileNum < 0) {
|
|||
|
printf(" Unable to open file\n");
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
|
|||
|
printf(" Opened device\n");
|
|||
|
|
|||
|
bytes = read(fileNum, data, sizeof(data));
|
|||
|
|
|||
|
if (bytes > 0)
|
|||
|
printf("%x\n", data);
|
|||
|
|
|||
|
close(fileNum);
|
|||
|
|
|||
|
return (0);
|
|||
|
}
|
|||
|
\end{lstlisting}
|
|||
|
|
|||
|
En este programa se abre el dispositivo \textit{/dev/fpga} que corresponde a nuestro driver y se utiliza la funci<63>n \textit{read} para leer la informaci<63>n suministrada por el driver.
|