aos/doc/015-disk-driver-arch/flounder-ahci.tex
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

203 lines
8.3 KiB
TeX

\section{Introduction}
\subsection{Purpose}
The goal of the \acs{ahci} Flounder backend is twofold: first, it should allow
specifying \ac{ata} messages declaratively, making adding messages easier and
reducing the amount of code potentially containing bugs. Second, sending such
\ac{ata} messages to a disk should behave just like general-purpose
inter-dispatch messaging, enabling transparent proxying of messages should no
direct connection be available between a dispatcher and a suitable I/O
controller.
\subsection{Design}
However, our use of Flounder also represents a major extension to its purpose.
So far, Flounder transports have simply been responsible for transferring data,
i.e. marshalling, packaging and transmission. Our backend differs in that it
must understand the purpose of each data item: depending on that purpose, it
must be formatted in a particular way, other actions may be necessary, and
certain restrictions (in particular on the size and type of the data) may
apply.
What this means for our project is that we must extend Flounder's syntax with
message meta-data, i.e. parameters providing additional information about a
message definition but not contributing to the runtime message payload. An
example of our current syntax can be seen in figure~\ref{fig:flounder-example}.
\begin{figure}[htb]
\begin{center}
\begin{lstlisting}
interface ata_rw28 "ATA read & write with 28-bit LBA" {
@ata(command=0xC8, dma_arg=buffer, dma_size=read_size,
lba=start_lba)
rpc read_dma(in uint32 read_size, in uint32 start_lba,
out uint8 buffer[buffer_size]);
@ata(command=0xC8, dma_arg=buffer, dma_size=512, lba=lba)
rpc read_dma_block(in uint32 lba, out uint8 buffer[buffer_size]);
@ata(command=0xCA, dma_arg=buffer, is_write=1, lba=lba)
rpc write_dma(in uint8 buffer[buffer_size], in uint32 lba,
out errval status);
@ata(command=0xEC, dma_arg=buffer, dma_size=512)
rpc identify_device(out uint8 buffer[buffer_size]);
@ata(command=0xE7)
rpc flush_cache(out errval status);
};
\end{lstlisting}
\caption{Example \acs{ata} message definitions}
\label{fig:flounder-example}
\end{center}
\end{figure}
\section{Discussion}
\subsection{Targeting: Compiler vs. Topic}
As seen in the syntax example, a set of meta-parameters is targeted using the
``@'' notation. Two possibilities exist for the interpretation of the target
specifier:
\begin{itemize}
\item The target may specify a compiler name (e.g. \verb+@AHCI_Stubs+),
with each compiler receiving only the meta-parameters targeted to it.
Among other things, this requires an additional step between parsing
and compiling, thus a compiler no longer receives the interface
definition's full AST.
Also, compilers are unable to share such parameters, e.g. if backends
exist for different \ac{ata} command transports, parameters related to
formatting of \ac{ata} commands must be repeated for each backend's
compiler.
\item The target may specify a generic ``topic''. This does not require
the extra preprocessing step and allows sharing of meta-parameters, but
requires compilers to match their interpretation of shared parameters.
Nonetheless, the sharing of parameters (also between header and stub
compilers of the same backend) may make this solution preferable.
\end{itemize}
While the initial implementation used the former solution, this was replaced
and we now use the second option.
\subsection{Parameter Analysis}
Extracting information from parameters and meta-parameters can be done in
various ways. Their presence, absence, type and (for meta-parameters) value can
all be used as sources of information. The question is therefore how best to
handle this information, as demonstrated in the following examples:
\begin{itemize}
\item The presence of an output parameter \lstinline+status+ of type
\lstinline+errval_t+ may imply that it should be used for a status
result. But what if the type is different, or there is a
\lstinline+errval_t+-typed parameter with a different name?
\item The size of a buffer may be extracted from its type if that is an
array typedef. If it is a dynamic array, the may be the dynamic length
parameter. In either case, the size might also be specified as a
meta-parameter. Which of these information sources should be accepted?
\end{itemize}
\section{Generated Interface}
\newcommand{\flifname}{\textit{if\_name}}
\newcommand{\flahcib}{\flifname\lstinline+_ahci_binding+\xspace}
\subsection{Initialization}
Initialization is done with \flifname\lstinline+_ahci_init+. The client must
first initialize libahci, at which point the target device is specified with
the \lstinline+port+ parameter of \lstinline+ahci_init+. Also, the client must
allocate a suitable \flahcib.
\subsection{Binding Type}
The \flahcib\ type extends the generic binding type, allowing the generated
\acs{ahci} bindings to be used anywhere the generic binding type is used. In
particular, the RPCClient can be wrapped around \acs{ahci} bindings, greatly
simplifying their usage.
Additionally, an \acs{ahci} binding contains a libahci binding, used internally
for communication with the library.
\subsection{Interface methods}
Because \acs{ahci} Flounder bindings use the generic binding as a base, the
generic messaging methods can be used, with the \flahcib cast to the generic
\flifname\lstinline+_binding+.
\section{Implementation}
\subsection{Command Completion}
To generate Flounder responses, the \ac{ahci} backend must associate command
completion callbacks from libahci with information from the original command.
This is done using libahci's command tags; before issuing a command, a
\lstinline+completed_rx_st+ ``command completion'' struct is allocated and
filled. The address of this struct is sent as the command tag for
\lstinline+issue_command+. Upon command completion, the tag is cast to a
\lstinline+completed_rx_st+, and the \lstinline+completed_fn+ callback function
pointer is called.
The \lstinline+completed_rx_st+ contains information for the message-specific
completion handler. Currently, this consists of the \flahcib and the region
used for \acs{dma}. If the message is supposed to perform a \acs{dma} read, the
data must be copied out of the \acs{dma} region into an allocated buffer to be
passed to the client. If \acs{dma} is used at all, the region must also be
freed.
Finally, the \lstinline+completed_rx_st+ is used by the
\lstinline+issue_command_cb+ for freeing the allocated \ac{fis} and calling the
message send user continuation.
\subsection{DMA Handling}
When parameter analysis indicates a \acs{dma} transfer is expected, the
\ac{ahci} backend must generate code to setup \acs{dma} regions, copying in TX
data before issuing the command, and copying out RX data after the command
completes.
To perform \acs{dma}, a \lstinline+dma_arg+ must be specified in the
\lstinline+ata+-targeted message meta-arguments. When the \ac{ahci} backend
detects this argument, it expects the value to be an identifier that
corresponds to one of the formal message arguments. The \acs{dma} direction is
then the direction of that message argument; \lstinline+in+ is a transmit,
\lstinline+out+ is a receive.
Because the \acs{dma} region must be allocated before the command is issued, if
a \acs{dma} argument is present, the size of the \acs{dma} must either be
specified in the interface file, or must be determinable upon receiving the rpc
call from the client. The size of the \acs{dma} may therefore be specified with
any of the following means:
\begin{itemize}
\item If \lstinline+dma_arg+ is a dynamic array, its size argument is used.
(transmit only)
\item If \lstinline+dma_arg+'s type is an array of fixed size, that is
used.
\item If a meta-argument \lstinline+dma_size+ is present and is an integer,
that is used.
\item If a meta-argument \lstinline+dma_size+ is present and is an
identifier, the \acs{rpc} must have an \lstinline+in+ argument with
that name, the value of which is used.
\end{itemize}
Finally, the \acs{dma} data must be copied in and out of suitably mapped
regions, managed using libahci's \lstinline+ahci_dma_region+ API. This is
necessary because flounder semantics require that the client owns buffer
memory.
\subsection{FIS Setup}
To issue a command over \ac{ahci}, the \acs{ahci} backend must first set up a
suitable \ac{fis}. This is done using the \lstinline+sata_fis+ API in libahci.