]> rtime.felk.cvut.cz Git - mf6xx.git/commitdiff
Diploma thesis text.
authorRostislav Lisovy <lisovy@gmail.com>
Tue, 5 Apr 2011 16:25:55 +0000 (18:25 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Tue, 5 Apr 2011 16:25:55 +0000 (18:25 +0200)
doc/diploma_thesis/text/dip_text.tex

index fbba26a35357212ea6944fa2bd1e273fa94d88ad..d00652ab6fe893646107d11faf4a8ddb527300f4 100644 (file)
@@ -8,7 +8,7 @@
 \usepackage{amssymb,amsmath}
 \usepackage{url}
 
-\newcommand{\ibox}[1]{ \begin{center}\begin{small} \fbox{\parbox{12cm}{ #1 }} \end{small}\end{center}}
+\newcommand{\ibox}[1]{ \begin{center} \fbox{\parbox{12cm}{ #1 }} \end{center}}
 
 %opening
 \title{\textsf{\begin{huge}Prostředí pro výuku vývoje PCI ovladačů do OS GNU/Linux\end{huge}\\
@@ -33,6 +33,15 @@ Od čtenáře se očekává základní znalost používání operačního systé
 %\end{abstract}
 \newpage
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Motivace}
+Zadání této práce vzešlo z akademického prostředí a reaguje na nedostatek studijních materiálů v českém jazyce pro začátečníky, popisujících vývoj ovladačů (v tomto případě PCI zařízení) pro operační systém GNU/Linux.
+
+Text obsahuje pouze nezbytné množství teorie, která je podložená četnými příklady pro snadnější pochopení čtenářem.
+
+Pro čtenáře neznalého psaní programů těsně svázaných s hardwarem se snažím názorně vysvětlit základní principy a úskalí tohoto druhu programování.
+
+V případě dalšího zájmu o problematiku může čtenář sáhnout po 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Hardware}
 \section{Komunikace s hardwarem}
@@ -109,11 +118,11 @@ Informaci o tom, kolik (a jaké) paměti karta bude potřebovat má před nakonf
 
 Zmínil jsem 6 BAR registrů, které každá z karet obsahuje. Mezi další registry, které je potřeba při implementaci ovladačů znát, patří:
 \begin{description}
-\item[Vendor ID] -- Obsahuje unikátní 16bitové číslo identifikující výrobce zařízení. Za poplatek je udělováno PCI-SIG (\textit{PCI Special Interest Group}) organizací.\footnote{V Debianu, po nainstalování balíčku \texttt{hwdata}, se seznam těchto identifikátorů nachází v souboru \texttt{/usr/share/hwdata/pci.ids}}
-\item[Device ID] -- Obsahuje 16bitové číslo identifikující model zařízení. Hodnotu tohoto identifikátoru si volí sám výrobce zařízení.
-\item[Class code] -- Označuje druh zařízení -- zda se jedná např. o grafickou kartu, zvukovou kartu nebo kartu zpracovávající signál.
+\item[Vendor ID]~\\Obsahuje unikátní 16bitové číslo identifikující výrobce zařízení. Za poplatek je udělováno PCI-SIG (\textit{PCI Special Interest Group}) organizací.\footnote{V Debianu, po nainstalování balíčku \texttt{hwdata}, se seznam těchto identifikátorů nachází v souboru \texttt{/usr/share/hwdata/pci.ids}}
+\item[Device ID]~\\Obsahuje 16bitové číslo identifikující model zařízení. Hodnotu tohoto identifikátoru si volí sám výrobce zařízení.
+\item[Class code]~\\Označuje druh zařízení -- zda se jedná např. o grafickou kartu, zvukovou kartu nebo kartu zpracovávající signál.
 \item[Subsystem Vendor ID] -- Podobá se \texttt{Vendor ID}. V případě, že naše karta využívá PCI řadič třetí strany, jako \texttt{Vendor ID} se zobrazí ID výrobce tohoto řadiče. Abychom byli schopni naše zařízení odlišit od jiného, které využívá stejný řadič, ID našeho zařízení bude uloženo v tomot registru. (V případě, že v registru \texttt{Vendor ID} je skutečně naše ID, může být opět i v tomto registru).
-\item[Subsystem ID] -- Opět se jedná o údaj podobný \texttt{Device ID}. 
+\item[Subsystem ID]~\\Opět se jedná o údaj podobný \texttt{Device ID}. 
 \end{description}
 
 Tyto registry slouží operačnímu systému k jednoznačné identifikaci zažízení, při volbě správného ovladače.
@@ -374,10 +383,10 @@ První věc, kterou ovladač PCI zařízení potřebuje udělat, aby se stal sou
 \subsection{Struktura \texttt{struct pci\_driver}}
 Tato struktura obsahuje základní informace o našem ovladači. Mezi hlavní položky patří:
 \begin{description}
-\item[\texttt{const char name*}] -- Název ovladače. Tento název by měl být unikátní mezi všemi ovladači PCI zařízení. Většinou je totožný s názvem modulu.
-\item[\texttt{const struct pci\_device\_id *id\_table}] -- Pole struktur popisujících, pro která zařízení je ovladač vytvořen (jednotlivé položky struktury jsou popsány níže).
-\item[\texttt{int (*probe) (struct pci\_dev *dev, const struct pci\_device\_id *id)}] -- \\Ukazatel na funkci, která je volána PCI subsystémem, v případě, že je přítomno zařízení, pro které je tento ovladač vytvořen.
-\item[\texttt{void (*remove) (struct pci\_dev *dev)}] -- Ukazatel na funkci, která je volána poté, co je tento ovladač odstraňován ze seznamu ovladačů aktuálně používaných PCI subsystémem.
+\item[\texttt{const char name*}]~\\Název ovladače. Tento název by měl být unikátní mezi všemi ovladači PCI zařízení. Většinou je totožný s názvem modulu.
+\item[\texttt{const struct pci\_device\_id *id\_table}]~\\Pole struktur popisujících, pro která zařízení je ovladač vytvořen (jednotlivé položky struktury jsou popsány níže).
+\item[\texttt{int (*probe) (struct pci\_dev *dev, const struct pci\_device\_id *id)}]~\\Ukazatel na funkci, která je volána PCI subsystémem, v případě, že je přítomno zařízení, pro které je tento ovladač vytvořen.
+\item[\texttt{void (*remove) (struct pci\_dev *dev)}]~\\Ukazatel na funkci, která je volána poté, co je tento ovladač odstraňován ze seznamu ovladačů aktuálně používaných PCI subsystémem.
 \end{description}
 
 Příklad, jak může být struktura \texttt{pci\_driver} inicializována a následně zaregistrována:
@@ -413,7 +422,7 @@ Jak již bylo zmíněno, struktura \texttt{struct pci\_device\_id} slouží k id
 
 
 \subsection{Funkce \texttt{probe()}}
-\ibox{\texttt{int probe(struct pci\_dev *dev, const struct pci\_device\_id *id)}}
+\ibox{\texttt{int probe(struct pci\_dev *dev, const struct pci\_device\_id *id);}}
 
 Funkce \texttt{probe()} náležící danému ovladači zařízení je volána poté, co subsystém PCI zařízení zjistí, že se v systému nachází zařízení, pro které je tento ovladač určen. Tato funkce má na starosti inicializaci zařízení.
 
@@ -454,65 +463,64 @@ Funkce je volána, když PCI subsystém ze svého seznamu odstraňuje strukturu
 
 Tato funkce by se měla postarat o úklid všech naalokovaných prostředků apod. Měla by obsahovat volání:
 \begin{description}
-\item[\texttt{iounmap()}] -- Uvolnění virtuální paměti namapované voláním \texttt{pci\_ioremap\_bar()}.
-\item[\texttt{pci\_release\_regions()}] -- Uvolnění zdrojů karty, které byly zarezervovány voláním \texttt{pci\_request\_regions()}.
-\item[\texttt{pci\_disable\_device()}] -- Opak k volání \texttt{pci\_enable\_device()}.
+\item[\texttt{iounmap()}]~\\Uvolnění virtuální paměti namapované voláním \texttt{pci\_ioremap\_bar()}.
+\item[\texttt{pci\_release\_regions()}]~\\Uvolnění zdrojů karty, které byly zarezervovány voláním \texttt{pci\_request\_regions()}.
+\item[\texttt{pci\_disable\_device()}]~\\Opak k volání \texttt{pci\_enable\_device()}.
 \end{description}
 
  
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{UIO ovladač}
-V případě, že je vytvářen ovladač pro linuxové jádro, mělo by být promyšleno, kterého subsystému se stane součástí -- např. zda jde o jednoduché znakové zařízení, síťovou kartu nebo zvukovou kartu.
+V případě, že je vytvářen ovladač pro linuxové jádro, mělo by být rozhodnuto, kterého subsystému se stane součástí -- např. zda jde o jednoduché znakové zařízení, síťovou kartu nebo zvukovou kartu. Tato volba uřčí, kterou sadu pomocných funkcí bude moci ovladač používat a jakým způsobem bude zpřístupněno zařízení do uživatelského prostoru.
 
-V případě, že jde o PCI zařízení, které nelze snadno zařadit do žádné kategorie, je možné použít tzv. UIO ovladač. Tento ovladač se skládá ze dvou částí: jaderného modulu a aplikace v uživatelském prostoru. Mezi jeho hlavní výhody patří to, že v jádře je obsažena pouze malá obecná část, která zpřístupňuje zdroje zařízení do uživatelského prostoru (její implementace je poměrně snadná).
+V případě, že jde o PCI zařízení, které nelze snadno zařadit do žádné kategorie (jedná-li se například o neobvyklou průmyslovou kartu), je možné použít tzv. UIO (\textit{Userspace I/O}) ovladač. Tento ovladač se skládá ze dvou částí: jaderného modulu a aplikace v uživatelském prostoru. Mezi jeho hlavní výhody patří to, že v jádře je obsažena pouze malá obecná část, která zpřístupňuje zdroje zařízení do uživatelského prostoru (její implementace je poměrně snadná).
 
 Druhou částí je aplikace v uživateském prosotru, která přistupuje k jednotlivým zdrojům karty a tvoří hlavní logiku ovladače. Většina vývoje tedy probíhá v uživatelském prostoru, čímž klesá riziko narušení stability jádra.
 
 \subsection{Jaderný modul}
-Jaderný modul UIO ovladače obsahuje:
+Jaderný modul UIO ovladače by měl obsahovat:
 \begin{itemize}
 \item Funkci volanou PCI subsystémem při registraci ovladače
-\item Volání funkcí pro zpřístupnění regionů zařízení
-\item Registraci do UIO subsystému
-\item Funkce pro \textit{úklid} a uvolnění zdrojů karty
+\item Volání funkcí pro namapování regionů zařízení
+\item Inicializaci struktury \texttt{struct uio\_info} a registraci do UIO subsystému
+\item Funkce pro \textit{úklid} a uvolnění regionů karty
 \end{itemize}
 
-Většina z těchto úkonů byla již popsána v kapitole \ref{pcich} a jsou zcela standardní pro jakýkoliv ovladač PCI zažízení, navíc je zde pouze \textit{registraci do UIO subsystému}.
+Většina z těchto úkonů již byla popsána v kapitole \ref{pcich} a jsou zcela standardní pro jakýkoliv ovladač PCI zažízení, navíc je zde pouze \textit{registrace do UIO subsystému}.
 
 \ibox{\texttt{int uio\_register\_device(struct device *parent, struct uio\_info *info);}}
 
-\ibox{FIXME co je \&pci\_device-dev?}
-Ta se provede zavoláním funkce \texttt{uio\_register\_device()}, kde se jako druhý parametr předá ukazatel na strukturu \texttt{struct uio\_info}.
+Ta se provede zavoláním funkce \texttt{uio\_register\_device()}, které se jako první parametr předá \textit{rodič} struktury \texttt{struct pci\_dev} struktury -- tj. ukazatel na její položku \texttt{dev}.\footnote{FIXME; WTF is this?} Druhý parametr předá ukazatel na strukturu \texttt{struct uio\_info}.
 
 \subsubsection{Struktura \texttt{struct uio\_info}}
 Mezi její hlavní položky patří:
 \begin{description}
-\item[\texttt{const char *name}] -- Název ovladače
-\item[\texttt{const char *version}] -- Verze ovladače
-\item[\texttt{struct uio\_mem mem[MAX\_UIO\_MAPS]}] -- Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do paměťového prostoru
-\item[\texttt{struct uio\_port port[MAX\_UIO\_PORT\_REGIONS]}] -- Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do vstupně-výstupního prostoru.
+\item[\texttt{const char *name}]~\\Název ovladače
+\item[\texttt{const char *version}]~\\Verze ovladače
+\item[\texttt{struct uio\_mem mem[MAX\_UIO\_MAPS]}]~\\Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do paměťového prostoru
+\item[\texttt{struct uio\_port port[MAX\_UIO\_PORT\_REGIONS]}]~\\Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do vstupně-výstupního prostoru.
 %\item[\texttt{}]
 \end{description}
 
 \subsubsection{Struktura \texttt{struct uio\_mem} a \texttt{struct uio\_port}}
-Tyto struktury obsahují imformace o regionech zařízení -- která ze dvou struktur bude inicializována se rozhoduje na základě toho, zda karta mapuje regiony do paměťového nebo vstupně-výstupního prostoru.
+Tyto struktury obsahují imformace o regionech zařízení. Které (a kolik) z těchto dvou struktur budou inicializovány záleží na tom, zda karta mapuje regiony do paměťového nebo vstupně-výstupního prostoru.
 
 Struktura \texttt{struct uio\_mem} obsahuje položky:
 \begin{description}
-\item[\texttt{const char *name}] -- Textový popis daného regionu (viditelný z uživatelského prostoru).
-\item[\texttt{unsigned long addr}] -- Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
-\item[\texttt{unsigned long size}] -- Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
-\item[\texttt{int memtype}] -- Typ paměti. Pro fyzickou paměť na zařízení se použije \texttt{UIO\_MEM\_PHYS}.
-\item[\texttt{void \_\_iomem *internal\_addr}] -- Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}
+\item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
+\item[\texttt{unsigned long addr}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
+\item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
+\item[\texttt{int memtype}]~\\Typ paměti. Pro fyzickou paměť na zařízení se použije \texttt{UIO\_MEM\_PHYS}.
+\item[\texttt{void \_\_iomem *internal\_addr}]~\\Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}
 \end{description}
 
 Struktura \texttt{struct uio\_port} obsahuje položky:
 \begin{description}
-\item[\texttt{const char *name}] -- Textový popis daného regionu (viditelný z uživatelského prostoru).
-\item[\texttt{unsigned long start}] -- Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
-\item[\texttt{unsigned long size}] -- Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
-\item[\texttt{int porttype}] -- Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}
+\item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
+\item[\texttt{unsigned long start}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
+\item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
+\item[\texttt{int porttype}]~\\Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}
 \end{description}
 
 ~\\
@@ -548,7 +556,7 @@ Na posledním řádku je, dosud nepopsané, volání \texttt{pci\_set\_drvdata()
 \subsection{Program v uživatelském prostoru}
 Poté, co je jaderná část UIO ovladače úspěšně zkompilována a zavedena do systému, je rozhraní mezi tímto modulem a uživatelským prostorem tvořeno:
 \begin{itemize}
-\item souborem \texttt{/dev/uio0\footnote{Pro názornost zde uvádím konkrétní zařízení \texttt{uio0}. V případě, že systém obsahuje více aktivních UIO ovladačů, jsou postupně číslovány od 0 výše.}}.
+\item souborem \texttt{/dev/uio0\footnote{Pro názornost v textu uvádím konkrétní zařízení \texttt{uio0}. V případě, že systém obsahuje více aktivních UIO ovladačů, jsou postupně číslovány od 0 výše.}}.
 \item složkou \texttt{/sys/class/uio/uio0}, která obsahuje informace o regionech, které jsou zpřístupněny skrze UIO modul v jádře.
 \end{itemize}
 
@@ -558,22 +566,46 @@ Tato složka obsahuje soubory převážně pouze pro čtení. Obsahuje podložku
 \subsubsection{Soubor \texttt{/dev/uio0}}
 Tento soubor je využíván k samotnému přístupu k regionům karty. K souboru se přistupuje pomocí volání \texttt{mmap()}.
 
-\ibox{void *mmap(void *addr, size\_t length, int prot, int flags, int fd, off\_t offset);}
+\ibox{\texttt{void *mmap(void *addr, size\_t length, int prot, int flags, int fd, off\_t offset);}}
 
+Tato funkce slouží k \textit{namapování} souboru nebo zařízení do operační paměti. V případě, že funkci zavoláme na soubor, proběhne-li vše správně, návratová hodnota bude obsahovat ukazatel do paměti, kam je možné přistu\-povat k obsahu souboru pomocí ukazatelové aritmetiky -- stejně, jako by to byla paměť.
  
 \begin{description}
 \item[Parametr \texttt{addr}] -- v případě, že není nulový -- určí, na jakou adresu by měla být paměť mapována.
 \item[Parametr \texttt{length}] udává velikost mapované paměti v násobcích velikosti paměťové stránky. 
-\item[Parametr \texttt{prot}] obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis.
-\item[Parametr \texttt{flags}] říká FIXME
-\item[Parametr \texttt{fd}] obsahuje \textit{filedescriptor} na zařízení, které chceme mapovat (v tomto případě \texttt{/dev/uio0}).
-\item[Parametr \texttt{offset}] určuje, zda se zaný soubor/zařízení začne mapovat od posunuté adresy. V případě UIO ovladače je možné jako offset používat násobky velikosti paměťové stránky. Tento offset určí, který z regionů má být namapován.
+\item[Parametr \texttt{prot}] obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis, apod.
+\item[Parametr \texttt{flags}] pomocí příznaku určuje, zda se mají změny zapisovat pouze do \textit{lokální kopie} (příznak \texttt{MAP\_PRIVATE}) nebo zda mají být zapisovány do původního souboru/zařízení (příznak \texttt{MAP\_SHARED}).
+\item[Parametr \texttt{fd}] obsahuje \textit{filedescriptor} na zařízení, které má být namapováno (v tomto případě \texttt{/dev/uio0}).
+\item[Parametr \texttt{offset}] určuje, zda se zaný soubor/zařízení začne mapovat od posunuté adresy. V případě UIO ovladače je možné jako offset používat násobky velikosti paměťové stránky -- tento offset určí, který z regionů zpřístupněných jadernou částí ovladače má být namapován.
 \end{description}
 
-FIXME
+Příklad, jak takové volání může vypadat (bez ošetření chybných stavů):
+\begin{verbatim}
+1 |  #define BAR2_offset       (1 * sysconf(_SC_PAGESIZE))
+2 |  void* mf624_BAR2 = NULL;
+3 |  int device_fd = open("/dev/uio0", O_RDWR);
+4 |  
+5 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
+6 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
+7 |                    device_fd, BAR2_offset);
+\end{verbatim}
+
+S adresou vrácenou voláním \texttt{mmap()} však není možné vždy ihned pracovat. Může se stát, že mapovaný region PCI zařízení (reprezentovaný zařízením \texttt{/dev/uio0}, na které je \texttt{mmap()} volán) je menší než je velikost celé stránky, \texttt{mmap()} však vrací ukazatel zarovnaný na velikost stránky. Je tedy potřeba se v rámci této stránky posunout na tu část, která odpovídá požadovanému regionu.
 
+Jak velký je potřeba udělat \textit{posun} pomůže zjistit soubor \texttt{/sys/class/uio/ /ui0/maps/map1/addr}\footnote{Pro názornost uvádím konkrétní cestu -- jedná se tedy o \textit{druhý} paměťový region zažízení \textit{uio0}.} -- ten obsahuje fyzickou adresu požadovaného regionu. Z té je možné následujícím trikem získat ukazatel, se kterým je již možné pracovat (nejnižší bity totiž budou zachovány z fyzické adresy):
+\begin{verbatim}
+mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
+  |                \-- Fyzická adresa
+  \-- Ukazatel vrácený voláním mmap()                 
+\end{verbatim}
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Comedi ovladač}
+UIO ovladač dává uživateli možnost využít 100 \% všech funkcí zařízení -- daní za to je pomalejší odezva než v případě plnohodnotného jaderného ovladače.
+
+Pro ovladače měřících karet existuje v Linuxu subsystém -- tzv. Comedi (Control and Measurement Device Interface).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Závěr}
 
 %\appendix
 %\chapter{Qemu a Humusoft MF624}\label{qemu}