
\section{Sistema Operativo}

\subsection{Interrupciones}

% desarrollar un poco más, agregar explicaciones.

Las excepciones Undefined Instruction, Data \& Prefetch Abort no cumplen ninguna función de peso en este sistema operativo.
Son utilizadas como medio para obtener información acerca de los problemas que puedan surgir.
Por ese motivo la única tarea que realizan es avisar, dar información del error y detener la ejecución del sistema.
Las rutinas de atención de las 3 excepciones son implementadas de forma similar, todas muestran un volcado de los registros al momento de la interrupción.
Cada interrupción, además, brinda información extra a ser la dirección en donde se generó y el motivo.

Por ejemplo, el siguiente código en la tarea \emph{init} ocasiona un error en los permisos de escritura.

\begin{lstlisting}[language=C]
int main()
{
    *((uint32_t *) 0) = 4;
    ...

\end{lstlisting}

La tarea no tiene privilegios de escritura en la dirección \emph{0x00000000}, por lo que se produce una excepción.
La excepción se imprime junto con la causa y un detalle del contenido de la pila al momento de la interrupción.

\begin{lstlisting}
[ex] Data Abort
[db] 0x00000000 - Fault Address Register
[db] Data Fault Register
	@ AXI decode error caused the abort
	@ Write access caused the abort
	@ Status: Permission section fault

[db] Stack
	0x7FFFFFBC: 0x00000000 (0)
	0x7FFFFFC0: 0x00000000 (0)
	0x7FFFFFC4: 0x00000004 (4)
	0x7FFFFFC8: 0x00000000 (0)
	0x7FFFFFCC: 0x00000000 (0)
	0x7FFFFFD0: 0x00000000 (0)
	0x7FFFFFD4: 0x00000000 (0)
	0x7FFFFFD8: 0x00000000 (0)
	0x7FFFFFDC: 0x00000000 (0)
	0x7FFFFFE0: 0x00000000 (0)
	0x7FFFFFE4: 0x00000000 (0)
	0x7FFFFFE8: 0x7FFFCFFC (2147471356)
	0x7FFFFFEC: 0x00000000 (0)
	0x7FFFFFF0: 0x7FFFFFF8 (2147483640)
	0x7FFFFFF4: 0x40000000 (1073741824)
	0x7FFFFFF8: 0x40000014 (1073741844)
	0x7FFFFFFC: 0x00000050 (80)

[db] System halt
\end{lstlisting}

La rutina de atención de la excepción Interrupt Request se utiliza para averiguar la procedencia de la misma y luego atenderla.
Los dos dipositivos que utilizan esta interrupción son el reloj de sistema, y el puerto de comunicación serial mini UART al recibir o enviar datos.

Las llamadas a sistema se realizan a través de la excepción \emph{Software Interrupt} (\emph{SWI}).
La misma se dispará cuando un programa o aplicación ejecuta la instrucción \emph{swi}.
La intrucción toma un número de 24-bits que utiliza para saber de que llamada a sistema se trata.
Durante la ejecución de la rutina, se obtiene la instrucción swi ejecutada para obtener este número.
El número indexa una tabla de direcciones donde se encuentran las funciones de sistema.
Luego realiza una llamada a la función pedida, de forma transparente.

La excepción Fast Interrupt Request no es utilizada.

%\newpage

\subsection{Administración de memoria física}

% Explicar mejor

La memoria RAM del dispositivo se administra mediante un mapa de bits.
Cada bit en el mapa representa una sección de la misma de tamaño igual a 4K.

\hfill

El mapa de bits está divido en dos partes, la parte con las direcciones más bajas (área de sistema) se utiliza para crear las estructuras que necesita el sistema.
Esta área se encuentra virtualizada utilizando \emph{identity mapping}.
De esta forma no debemos virtualizar una página previamente a utilizarla como estructura para el sistema de paginación.

El área de direcciones más altas (área usuario) se usa para contener código y datos.
Esta región no se encuentra virtualizada.

\hfill

Luego de la creación del mapa de bits, se alojan las páginas ya utilizadas: el área donde reside el kernel, la pila, el vector de interrupciones, etc.
Las direcciones de dichas secciones se obtienen de las variables definidas en el proceso de enlazado.

\hfill

Se brindan funciones para las siguientes operaciones.

\begin{enumerate}
\item Pedir 1 página de 4K.
\item Pedir 1 página de 4K, previamente virtualizada. Utilizadas para generar las tablas de traducción de nivel 2 (Coarse).
\item Pedir 4 páginas de 4K contiguas, previamente virtualizadas. Se utiliza más que nada para generar las tablas de traducción de nivel 1 (Master).
\item Liberar páginas no utilizadas.
\end{enumerate}

\hfill

\subsubsection{Organización de la Memoria}

La figura ~\ref{fig:mem} muestra la disposición de la memoria física, y como la misma se encuentra virtualizada.

El vector de excepciones, la pila utilizada por el sistema, el kernel, dispositivos de I/O, memoria libre de sistema y de video, se encuentran virtualizadas con \emph{identity mapping} (es decir, sus direcciones físicas y virtuales son las mismas).

En el espacio de direcciones virtuales el heap del kernel se ubica donde comienza la memoria de usuario libre, a continuación del área de sistema.

\begin{figure}[!ht]
	\centering
	\begin{subfigure}[b]{0.2\textwidth}
		\includegraphics[scale=.5]{img/mem_phys}
		\caption{Mapa de memoria física.}
		\label{fig:phys}
	\end{subfigure}
	\begin{subfigure}[b]{0.2\textwidth}
		\includegraphics[scale=.5]{img/mem_virt}
		\caption{Mapa de memoria virtual.}
		\label{fig:virt}
	\end{subfigure}
	\caption{Memoria virtual y física.}
	\label{fig:mem}
\end{figure}

\newpage

\subsection{Heap del sistema}

El administrador de memoria virtual se encarga de buscar bloques de memoria libres para su uso.
Se implementa utilizando listas doblemente enlazadas, una de bloques libres y otra de bloques usados.

Cada bloque de memoria pedido al sistema posee un encabezado que contiene un par de punteros indicando el próximo bloque libre (en caso de estar libre) o usado (en caso de estar en uso).
Además posee información sobre el tamaño de dicho bloque.

El administrador también guarda la ubicación de los comienzos de ambas listas y de su tamaño total, en la primera sección del heap.

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.7\textwidth]{img/parva}
	\caption{Estructura generada por el administrador de memoria.}
	\label{fig:parva}
\end{figure}

Cada vez que se desea un bloque de memoria se busca el bloque libre más grande (Worst Fit Policy).
A continuación se lo secciona en 2 partes formando 2 bloques, de manera que el bloque de memoria restante quede en la lista y no deba ser vuelto a insertar.
El otro bloque se inserta al principio de la lista de usados.
Finalmente se retorna la dirección del bloque de memoria listo para su uso.
Si el bloque es del mismo tamño que el pedido, no es modificado y se retorna para ser utilizado.

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.7\textwidth]{img/parva2}
	\caption{\emph{malloc}, pedido de memoria.}
	\label{fig:parva1}
\end{figure}

Para devolver memoria, el sistema recupera la dirección del encabezado del bloque.
Luego lo quita de la lista de usados, lo inserta por dirección en la lista de nodos libres y comprueba si puede funsionar el bloque con otro (también libre).
Debido a que la lista de bloques libres se encuentra organizada por dirección es más fácil realizar la fusión de 2 bloques.
Sólo debemos ver si el bloque siguiente y anterior son contiguos.

%\newpage

\subsection{Procesos}

% quizás hablar del formato elf32 ARM, imagen de proceso

Las tareas se compilan a parte y sus archivos en formato ejecutable (Elf 32 para ARM) se añaden a la sección de datos de sólo lectura del kernel.
Al momento de cargar la tarea, el archivo Elf32 es analizado, y con la información obtenida se generan las secciones de la tarea.

Cada sección es copiada a una página y mapeada a la correspondiente dirección virtual, en la tabla de páginas del proceso.

Las tareas no solo son lanzadas con este sistema, también se utilizan las funciones \emph{fork} y \emph{exec} combinadas para clonar y reemplazar procesos, creando nuevas tareas.

Cada proceso se identifica con un PID (Process ID).

\begin{figure}[!ht]
\centering
\begin{lstlisting}[language=C,breaklines=true]
struct process_t
{
	int pid; // Identificador de proceso
	
	process_t *parent; // Puntero a proceso padre
	Queue *children; // Procesos hijos
	
	pcb_t *pcb; // Bloque de control de proceso
	
	uint32_t quantum; // Quantum (valor asignado)
	uint32_t ticks; // Ticks faltantes (contador usado por scheduler)
	uint32_t state; // Estado de proceso

	segment_t *text; // Segmentos de programa
	segment_t *rodata;
	segment_t *data;
	segment_t *bss;
	segment_t *svc_stack;
	segment_t *usr_stack;
	segment_t *heap;

	List *mutexes; // Mutex pedidos por el proceso
	segment_t *shared; // Memoria compartida, actualmente solo se puede compartir 1 pag de 4k
};
\end{lstlisting}
\caption{Estructura de un proceso.}
\label{fig:process}
\end{figure}

\newpage

La figura ~\ref{fig:proc_virt} muestra como está conformado el espacio virtual de los procesos.
El mismo comienza en la dirección virtual \emph{0x40000000}.

\begin{figure}[!ht]
	\centering
	\includegraphics[scale=.5]{img/proc_virt}
	\caption{Imagen de un proceso en memoria virtual.}
	\label{fig:proc_virt}
\end{figure}

\subsubsection{Clonar un proceso: \emph{fork()}}

\emph{fork()} es una función utilizada para clonar un proceso.
La misma devuelve el pid (Process Id) del proceso clonado.

En la estructura de proceso, se guarda información acerca del comienzo, longitud y attributos de cada sección de programa.
Cada sección del programa se copia a una página física, la cual se virtualiza en un nuevo directorio de páginas.
Este nuevo directorio de páginas se utilizará para el proceso clon.
La única sección que no se replica es la memoria compartida, pero sí se registra en el directorio del nuevo proceso.

El último paso es inicializar la estructura \emph{pcb\_t} de tal forma que el nuevo proceso reanude la ejecución como si fuera el proceso original.
Para ello se utiliza una función en ensamblador, \emph{saveContext}.

Luego de salvar el contexto, los dos procesos quedan en el mismo estado y con los mismos datos.
Lo que distingue entre uno y otro, y determina el valor de retorno de la función \emph{fork()} es el siguiente código.


\begin{lstlisting}[language=C,breaklines=true]
	if(scheduler.running->pid != copy->pid)
	{
		// Si soy quien ejecuto fork ...
		// Ingreso la tarea clon en el planificador.
	 	scheduler_admit(copy);

	 	// Devuelvo el pid de la nueva tarea.
	 	return copy->pid;
	}

	// Si soy la copia... devuelvo 0.
	return 0;
\end{lstlisting}

Si lo vemos desde la perspectiva de la tarea que ejecutó la función \emph{fork()} originalmente, debe devolver el pid del proceso generado.
También debe ubicar la tarea en la cola del planificador para su posterior ejecución.

Cuando vemos que sucede en el proceso clonado, la ejecución se retoma al volver de la función \emph{fork()}.
El valor devuelto es 0 ya que se trata del proceso clonado.

\subsubsection{Reemplazar un proceso: \emph{exec()}}

La función \emph{exec()} modifica el espacio virtual de un proceso para convertirlo en otro.
Las secciones (\emph{segment\_t*}) del proceso original son descartadas y reemplazadas por las secciones del nuevo.

A pesar de deshechar las secciones de código y datos, muchas otras se conservan.
Las dos pilas (nivel privilegiado y no privilegiado), se restauran.
El heap de la aplicación libera toda la memoria que fue tomada por el proceso anterior y es reutilizado.
La sección compartida no se deshecha, es heredada por la nueva tarea.

La estructura \emph{pcb\_t} es reinicializada y se utiliza la función \emph{loadContext} para comenzar la ejecución.

\newpage

\subsection{Planificador de Tareas}

Como planificador de tareas se implemento un Virtual Round Robin.
El planificador tiene 2 colas, una la llamaremos ``ready'' y la otra ``auxiliary'' (ver figura ~\ref{fig:scheduler}).

En un Round Robin convencional cada tarea se ejecuta por una cantidad de tiempo finito.
Cuando se le acaba el tiempo, el planificador desaloja la tarea y le da lugar a otra.
En este sistema también sucede lo mismo.
Cada vez que una tarea gasta su tiempo de ejecución, llamado quantum, es desalojada y encolada en ``ready''.
Para cargar una nueva tarea el planificador desencola una tarea de la cola ``ready'' o ``auxiliary'', dependiendo de cuál no esté vacía.
La cola ``auxiliary'' tiene mayor prioridad que la otra, es decir que el planificador intentará primero quitar una tarea de esta.

Una tarea puede bloquearse por una operación de entrada o salida a un dispositivo o simplemente ceder el control de ejecución en determinado momento (poner la tarea a dormir).
Al hacerlo, la tarea no gasta la totalidad de su quantum y queda bloqueada.
Una tarea bloqueada no reingresa a las colas del planificador debido a que no volverá a ejecutarse hasta que se complete la operación de entrada o salida.
Cuando la tarea se desbloquee, esta ingresara en la cola ``auxiliary'' y el valor de quantum será aquel que no gastó a causa del bloqueo.
Cuando el bloqueo termina la tarea está lista para procesar, es por eso que la cola ``auxiliary'' tiene más prioridad.

Las casusas por las cuales la tarea puede bloquearse son por el uso de las funciones sleep, getch, putch y la utilización de variables candado.

\begin{figure}[!ht]
	\centering
	\includegraphics{img/scheduler}
	\caption{Virtual Round Robin.}
	\label{fig:scheduler}
\end{figure}

Gracias a el reloj de sistema, el cuál interrumpe cada 1 milisegundo, se puede saber cuando una tarea a terminado su turno en la CPU.
Cada tarea es ejecutada por 50 milisegundos (quantum).
Como valor mínimo para amortizar los tiempos muertos, se utiliza un valor de 20 milisegundos.
Es decir, si la tarea se bloqueó y su quantum restante es de 5 milisegundos, este se incrementa a 20 automáticamente.

\newpage

\subsection{Cambio de contexto}

El código del listado ~\ref{fig:contextSwitch}, es la rutina utilizada para cambiar de contexto.
La misma almacena todos los registros utilizados por la tarea en cuentión en una estructura conocida como \emph{pcb\_t} (Process Control Block).

Para poder acceder a los registros del modo usuario, es necesario cambiar al modo Sistema.
En el mismo se tiene acceso a los registros de modo usuario pero sin perder los privilegios.
Se realiza de esta forma porque es imposible regresar a un modo privilegiado luego de haber ingresado al modo usuario, debido a que no se tiene permiso de escritura necesario sobre el registro \emph{CPSR}.

La tabla de traducciones de páginas es reemplazada por la del próximo proceso.
La \emph{TLB} es vaciada para prevenir errores en la traducción (borrar las traducciones del proceso anterior).

Una vez terminado el cambio de contexto, la instrucción \emph{movs} restaura el contador de programa y el estado previo del registro \emph{CPSR}.

\begin{figure}[!ht]
\centering
\begin{lstlisting}[breaklines=true]
contextSwitch:
	@ r0 := Current Task Control Block
	@ r1 := Next Task Control Block

	stmfd sp!, {r1} @ Almacenar r1
	cps #Sys32md
	stmea r0, {r0-r14} @ Guardar R0-R14
	cps #SVC32md
	mov r1, sp
	add r1, #4
	str r1, [r0, #60] @ Guardar sp_svc corregido, +4 (debido al primer stmfd)
	str lr, [r0, #64] @ Guardar lr_svc (retorno a rutina)
	mrs r1, cpsr
	str r1, [r0, #68] @ Guardar spsr_svc
	mrc p15, 0, r1, c2, c0, 0
	str r1, [r0, #72] @ Guardar ttb0
	ldmfd sp!, {r0} @ Cargar tcb tarea siguiente
	ldr r1, [r0, #72]
	mcr p15, 0, r1, c2, c0, 0 @ Cargar ttb0
	mov r1, #0
	mcr p15, 0, r1, c8, c7, 0 @ Flush TLB
	ldr r1, [r0, #68]
	msr spsr, r1 @ Restaurar spsr
	ldr r1, [r0, #64]
	mov lr, r1 @ Restaurar lr
	ldr r1, [r0, #60]
	mov sp, r1 @ Restaurar sp
	cps #Sys32md
	ldmfd r0, {r0-r14} @ Restaurar registros de usuario
	cps #SVC32md
	movs pc, lr @ Volver
\end{lstlisting}
\caption{Cambio de contexto entre 2 procesos.}
\label{fig:contextSwitch}
\end{figure}

\newpage

\subsubsection{Espera no bloqueante: \emph{sleep()}}

La función \emph{sleep} se utiliza como espera no activa.
La tarea es puesta a dormir y por lo tanto retirada de la CPU durante una cantidad fija de milisegundos (pasados a la función).
Una vez que el plazo de tiempo acordado se cumplió, el sistema vuelve a colocar el proceso en la cola de mayor prioridad.

Llamemos a las tareas TX, con X un número natural (T1, T2, etc). Además notaremos t(TX) al tiempo que la tarea debe de esperar.

Para saber cuando una tarea a finalizado su espera se utiliza una cola delta (delta queue).
Las tareas ingresan a la cola con un valor igual a t(TX).
Por ejemplo en la figura ~\ref{fig:dque1}, se ve ingresar a la delta queue a la tarea 1 (T1) con t(T1) igual a 10 (milisegundos).

\begin{figure}[!ht]
	\centering
	\includegraphics{img/dqueue1}
	\caption{La tarea 1 (T1) ingresa a la cola con $t(T1) = 10$.}
	\label{fig:dque1}
\end{figure}

El valor t(TX) del primer elemento se verá reducido en 1 unidad luego de cada milisegundo (marcado por el reloj de sistema).
Cuanto t(TX) llegue a cero se desencola la tarea y desbloquea.

Si ingresara una segunda tarea (T2) se compara t(T1) con t(T2).
En caso de t(T2) ser mayor a t(T1), ver figura ~\ref{fig:dque2}, se inserta T2 detrás de T1 con valor $t'(T2) = t(T2) - t(T1)$.
De esta forma cuando se quite a T1 de la cola, faltarán $t(T2) - t(T1)$ milisegundos para despertar a T2.

\begin{figure}[!ht]
	\centering
	\includegraphics{img/dqueue2}
	\caption{La tarea 2 (T2) ingresa a la cola con valor 15.}
	\label{fig:dque2}
\end{figure}

Si t(T2) fuera menor que t(T1), T2 se posicionaría delante de T1 con su valor t(T2) sin modificar.
El valor de T1 se vería reducido en t(T2), $ t'(T1) = t(T1) - t(T2) $.

\begin{figure}[!ht]
	\centering
	\includegraphics{img/dqueue3}
	\caption{La tarea 2 (T2) ingresa a la cola con valor 5.}
	\label{fig:dque3}
\end{figure}

% generalización??

\newpage

\subsubsection{Variables candado: \emph{Mutex}}

El sistema utiliza las interrupciones como sistema de exclusión mutua.
Esto puede hacerse gracias a que las interrupciones no son reentrantes.

Se cuenta con 3 llamadas a sistema que posibilitan su utilización.

\begin{enumerate}
\item \emph{mutex\_create}, crea un mutex.
\item \emph{mutex\_adquire}, pide la variable candado.
\item \emph{mutex\_release}, libera el mutex.
\end{enumerate}

Cuando se crea un mutex, el sistema lo anexa a un vector.
Es la posición en ese vector lo que se utiliza como ``key'' o ``id'' para identificar la variable candado.

Cuando se realiza una llamada a sistema, se desactivan las interrupciones.
Por esta razón el planificador de tareas no desalojará a la tarea actual.
Se utiliza este comportamiento como sistema de exclusión al momento de leer y escribir la variable candado, ya que no habrá ningún otro proceso ejecutándose.

Cuando el mutex es solicitado, de estar ``bloqueado'', la tarea que lo pidió es desalojada.
El proceso permanecerá bloqueado hasta que otro libere el recurso.
La tarea desalojada es encolada en una estructura utilizada sólo por el mutex en cuestión.

Al momento de liberarse un mutex, si la cola asociada tenía procesos esperando, se desencolará uno e inmediatamente será puesto a ejecutarse.

La figura ~\ref{fig:mutexadquire} muestra como es el proceso de bloquear un mutex, mientras que la figura ~\ref{fig:mutexrelease} muestra como se libera.

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.3\textwidth]{img/mutex1}
	\caption{Liberar un mutex.}
	\label{fig:mutexadquire}
\end{figure}

\newpage

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.5\textwidth]{img/mutex2}
	\caption{Adquirir un mutex.}
	\label{fig:mutexrelease}
\end{figure}

\subsubsection{Impresión por puerto serial: \emph{print()}}

La función \emph{print()}, es el equivalente a \emph{printf()} de la librería estándar de C.
Internamente utiliza la función \emph{putch()}, para imprimir de a un caracter a la vez.

Si dos tareas corriendo sobre el mismo procesador utilizaran la función print a la vez, un cambio de contexto podría producir que se mezclen las salidas de ambas.
Es por eso que se creo un mutex (su ID es 0), para regular el acceso a la salida.
Cada vez que se llama a la función en cuestión, la primer tarea a realizar es pedir este mutex para obtener el acceso exclusivo a la salida.
Una vez que la impresión concluye, el mutex es liberado.

\begin{lstlisting}[language=C,breaklines=true]
	#define print(fmt, ...) \
        mutex_adquire(0); \
        __print(fmt, __VA_ARGS__); \
        mutex_release(0)
\end{lstlisting}

En el código de arriba se puede apreciar la utilización del mutex.

\newpage

\subsection{Controlador Mini UART}

La Raspberry Pi dispone de un puerto serial mini UART (implementación mínima de un PL011).
Una rutina de incialización le configura de la siguiente forma:

\begin{itemize}
\item Sin control de errores
\item Sin control de flujo
\item Dato de 8-bits
\item 1 bit de parada
\item 9600 baudios
\end{itemize}

Se implemento un controlador para el mismo, de manera tal que pueda reemplazar la funcionalidad del teclado.
Las funciones \emph{getch} y \emph{putch} se utilizan para obtener y enviar un caracter de 1 byte a través del puerto.

El sistema utiliza buffers circulares para almacenar los caracteres recibidos y a transmitir.
Ambas funciones bloquean el proceso de no ser posible completar la acción satisfactoriamente.

\subsubsection{\emph{putch()}}

La función \emph{putch} intenta colocar un caracter en el buffer de transmisión.
Si el buffer se encuentra lleno, la tarea que invocó a \emph{putch} será bloqueada hasta que el buffer tenga al menos un lugar libre.

El puerto mini UART interrumpe cada vez que el buffer de salida físico tiene al menos 1 posición disponible.
Cuando esto sucede, los bytes almacenados en el buffer circular de transmisión son tranportados al buffer del puerto.
Finalmente si una tarea estaba esperando para escribir, es nuevamente activada.

El diagrama ~\ref{fig:putch} muestra la operación descripta.

\begin{figure}[!ht]
	\centering
	\includegraphics{img/uart2}
	\caption{Llamada a sistema \emph{putch}.}
	\label{fig:putch}
\end{figure}

\newpage

\subsubsection{\emph{getch()}}

Posee la misma forma de proceder que \emph{putch}.
Esta vez se bloquea un tarea sólo cuando el buffer circular de recepción está vacío.
Si el buffer de recepción está vacío, se bloquea la tarea hasta que un byte sea recibido.

Cuando se recibe un byte por el puerto, este ingresa en el buffer físico del mismo.
También se produce una interrupción, en la misma se leen los datos recibidos y se vuelcan sobre el buffer circular de recepción.
Además, si una tarea se encontraba esperando, se desbloquea.

A continuación un diagrama con la descripción de la operación ~\ref{fig:getch}.

\begin{figure}[!ht]
	\centering
	\includegraphics{img/uart1}
	\caption{Llamada a sistema \emph{getch}.}
	\label{fig:getch}
\end{figure}

\subsection{Pines de propósito general}

El kernel posee 3 \emph{syscalls} dedicadas al manejo de los pines de propósito general.

\begin{description}
\item[gpio\_fsel] \hfill \\
La misma se utiliza para seleccionar la función del pin elegido. Puede ser entrada, salida o cumplir alguna otra función alternativa.
Varios de los pines son utilizados por otros dispositivos (opcionalmente) como el UART, o el SPI.
\item[gpio\_set] \hfill \\
En caso de ser utilizado como salida, esta función envía una señal alta, interpretada como un 1 lógico (+3.3v), a través del pin especificado.
\item[gpio\_clear] \hfill \\
Operación inversa a \emph{gpio\_set}. Envía una señal baja, interpretada como un 0 lógico.
\end{description}

\subsection{Tarea: init}

Esta tarea es la primera en inciar. Una vez que se activan las interrupciones y el planificador empieza a funcionar (recibe interrupciones del reloj de sistema), el primer cambio de contexto se produce entre el sistema y la tarea init.

Init realiza una llamada a la función \emph{fork}. Una copia del proceso asignado como hijo de init comenzará a ejecutarse luego de que las demás tareas en la cola del planificador terminen su quantum.

El hijo de init ejecutará \emph{exec(1)}, convirtiendo así al proceso en la tarea speaker, de la cuál hablaremos en la siguiente sección.

Por otro lado, init, imprimirá un mensaje identificándose y manipulará un pin de propósito general para prender y apagar un led indefinidamente.

\begin{figure}[!ht]
	\centering
\begin{lstlisting}[language=C,breaklines=true]
int main()
{
	int child = fork();

	if(child != 0)
	{
		gpio_fsel(25, FSEL_OUTPUT);

		print("Soy el proceso init, mi pid es %d\n", getpid());

		while(1)
		{
			gpio_set(25);
			sleep(300);
			gpio_clear(25);
			sleep(300);
		}

	}
	else
	{
		print("Soy hijo del proceso init, mi pid es %d\n", getpid());

		exec(1); // speaker
	}

	while(1);
	return 0;
}
\end{lstlisting}
	\caption{Estracto de la tarea init.}
	\label{fig:initTask}
\end{figure}

\newpage

\subsection{Tarea: speaker}

La función de la tarea será reproducir una canción utilizando un speaker (de PC).

La tarea speaker, al igual que el proceso init, utiliza \emph{fork} para clonarse.
El padre (la tarea speaker original) se encargará de simular una señal cuadrada de un período determinado por la nota que debe reproducirse.
El hijo (el clon), deberá leer las notas de un arreglo y depositarlas en memoria compartida para que el proceso padre pueda saber que tocar.
La duración de la nota está dada por la cantidad de tiempo que queda almacenada (sin cambiar) en memoria compartida.
El tiempo de la duración de la nota se toma utilizando \emph{sleep}.

La función \emph{usleep} realiza espera activa, se utiliza de esta forma porque las resoluciones de tiempo que manejan son menores a 1 milisegundo que es lo mínimo que acepta \emph{sleep}.

\begin{figure}[!ht]
	\centering
	\includegraphics[width=0.7\textwidth]{img/speaker}
	\caption{Salida por consola de la tarea speaker.}
	\label{fig:speaker}
\end{figure}

\newpage

\begin{figure}[!ht]
	\centering
\begin{lstlisting}[language=C,breaklines=true]
int main()
{
	gpio_fsel(pin, FSEL_OUTPUT);
	gpio_set(pin);

	int child;
	uint32_t *halfPeriod = share_mem();

	*halfPeriod = 0;

	child = fork();

	if(child != 0)
	{

		print("Yo soy speaker (pid %d), toco la nota que me dicen\n", getpid());

		while(1)
		{
			gpio_set(pin);
			usleep(*halfPeriod);
			gpio_clear(pin);
			usleep(*halfPeriod);
		}
	}
	else
	{
		uint32_t note, duration, pause;

		print("Yo soy hijo de speaker (pid %d), le digo que nota tocar\n", getpid());
		
		while(1)
		{
			for(int i = 0; i < SONG02_SIZE; i++)
			{
				note = song02[0][i];
				duration = 1000 / song02[1][i];
				pause = (duration * 30) / 100;

				tone(halfPeriod, note);
				sleep(duration);

				tone(halfPeriod, 0);
				sleep(pause);
			}
		}
	}
	return 0;
}
\end{lstlisting}
	\caption{Estracto de la tarea speaker.}
	\label{fig:speakerTask}
\end{figure}
