Exercise 4 - Kernel modules
Formål
Denne øvelse
giver erfaring med at skrive, kompilere og indsætte kernemoduler. Kernemoduler
er de "containere" i hvilke vi fremadrette vil lægge vore Linux
Device Drivere. Forståelsen af disse er derfor grundlæggende for at kunne
skrive device drivere. Som første trin i at kunne lave device drivers,
koncentrerer vi os derfor om kerne moduler.
Du skal have et
funktionelt VM-Ware Image og et Devkit8000.
Desuden skal følgende være udført:
Desuden skal følgende være udført:
§
Du skal have en udpakket version af linux-3.2.6 source
træet (brug 7zr fra pakken p7zip pakken, som skal installeres)
§
Det at bygge en kerne er en flertrins raket. Først
bruges en default konfiguration iha_devkit8000_defconfig, dernæst
kompiles kernen. Se nedenfor:
~/source/linux-3.2.6$ make ARCH=arm CROSS_COMPILE=arm-angstrom-linux-gnueabi-
iha_devkit8000_defconfig
~/source/linux-3.2.6$ make ARCH=arm
CROSS_COMPILE=arm-angstrom-linux-gnueabi- -j4 uImage
Som det fremgår
laves der et uImage (makefile target). Dette uImage kan I lægge ned på
partitionen der hedder LABEL1 på jeres SD kort, hvorved at det
bliver denne kerne som systemet booter på næste gang.
Bemærk at
kompileringen af kernemoduler kan være lidt besværlig første gang, men når
først tingene er sat rigtig op vha. make filer, source tree mm, så kører det
ret gnidningsløst.
Første stop på
vejen til at skrive en device driver, er at bygge et kerne modul og prøve at
indsætte det i kernen. Dette er hvad dagens første øvelse går ud på. Som vi
oplevede i sidste øvelse, så tilgås de fleste enheder som filer i Linux. I
øvelse step 2 vil vi prøve at tilgå lysdioden fra sidste gang, men denne gang
fra en user space applikation.
Lav et
”hello_world” kerne modul og indsæt det i kernen.
a) Skriv
”hello_world” programmet: Lad dig inspirere kraftigt af kapitlet (se kapitel 2)
i Linux
Device Drivers (LDD3). Dermed også sagt driveren skal kunne det samme som
"hello_world" driveren, hverken mere eller mindre end driver der
beskrives i LDD3.
b) Skriv en
Makefile:
Se slides igennem og kapitlet i bogen, bemærk at linierne med $(MAKE) SKAL begynde med en tab !!! Ellers se på makefile opgaven fra I3ISU. Hvor er jeres kernel source henne?
c) Kompilér
programmet og kopiér det til target vha scp (dvs du skal bruge USB kablet)
Compile:
/..../hello_world$ scp hello.ko root@10.9.8.2:
Kan du ikke få
forbindelse til target, så check din netværksopsætning og skriv evt:
/..../hello_world$ sudo ifup usb0
evt.
/..../hello_world$ sudo ifdown usb0
forinden.
Har du
stadigvæk problemer, så se øvelse fra ISU: "Connecting to Target"
For at læse
kerne beskeder, altså de som bliver outputtet med ”printk”, kan du benytte
”dmesg” kommandoen på target. Evt kan du åbne en ny terminal.
Copy to target
d) Indsæt
modulet i kernen (insmod) og check med dmesg at det lykkedes.
e) Tag modulet
ud igen (rmmod) og se at det også lykkedes.
Et kernemodul arbejder
som bekendt i Linux kernen, hvor vi har adgang til alle ressourcer. Du skal i
det følgende prøve at få SYS_LED2 tænde og slukke, ligesom i sidste øvelse. I
dit hello_world modul skal du indsætte følgende kodestumper. Find selv ud af
hvor de skal være, men det at tænde for SYS_LED2 skal placeres i init funktion,
og den at slukke i exit funktionen. Bemærk ligeledes at der
skal ryddes op igen i exit funktionen.
LÆS grundigt
alle detaljer inden du går igang!!!
// Libraries
#include <linux/gpio.h>
#include <linux/ioport.h>
#include <asm/io.h>
// Pointere til IO6 Registre
volatile unsigned long *REG_GPIO6_OE;
volatile unsigned long *REG_GPIO6_DIN;
volatile unsigned long *REG_GPIO6_DOUT;
// Bede kernen om lov til at benytte
memory området
if (request_mem_region (0x49058034, 12,
"hello") == NULL) {
printk ("Allocation for I/O memory range is failed\n");
return 0;
}
// Tildele addresser til pointere (mappet
til en anden end den fysiske)
REG_GPIO6_OE = ioremap( 0x49058034, 1);
REG_GPIO6_DIN = ioremap(0x49058038, 1);
REG_GPIO6_DOUT = ioremap(0x4905803c, 1);
// Skrive 32-bit
iowrite32(<value>, <address
pointer>);
Når du skal
tilgå memory skal du bruge følgende funktioner:
// Læse 32-bit
<value> = ioread32(<address pointer>);
I din exit
funktion skal du indsætte:
// Frigiv memory
release_mem_region (0x49058034, 12);
Du skal nu
bruge ioread32/iowrite32 til at tænde for SYS_LED når modulet indsættes og
slukke for den når det tages ud.
Explanation of the code above.
I/O memory regions must be allocated prior to use. The interface for
allocation of memory regions (defined in <linux/ioport.h>)
is:
struct resource
*request_mem_region(unsigned long start_adr, unsigned long len, char
*name);
This function allocates a memory region of “len” bytes, starting at “start_adr”. If all goes well, a non-NULL pointer is returned; otherwise the return value is NULL. All I/O memory allocations are listed in /proc/iomem.
NOTE: In this exercise we need to set OE for the
SYS_LED3, read it’s value and write a new value (so that we only change the bit
controlling SYS_LED3).
This means that we need the addresses:
- 0x49058034
- 0x49058038
- 0x4905803c
Each address fills out 4 bytes but are otherwise
consecutive. This means we need to allocate 12 bytes from starting address
0x49058034.
Memory regions should be freed when no longer needed,
using:
void
release_mem_region(unsigned long start_adr, unsigned long len);
void *ioremap( unsigned long phys_addr,
unsigned long size )
Remap I/O into kernel address space. Phys_addr is the
beginning of the physical address range. Size is the size of a physical address
range. It returns a virtual start of
mapped range.
Code LED.c:
Code Makefile:
Compile:
Execute:
Verification:
Sysled_2 is on after running insmod LED.ko, and off
after running rmmod LED.ko.
Skriv en
applikation som sætter tænder/slukker for en lysdiode.
For at tilgå
enhederne som der allerede er skrevet device drivers til benyttes fil operationer.
I applikationen skal du således benytte posix C I/O funktionerne: open(),
close(), read(), write(). Læs mere om funktionerne her:http://linux.die.net/man/2/open /
close / read / write
Skal man styre
lysdioden i en applikation skal man gøre således:
§
Åbne filen som write-only (da dette er et output fra
systemet)
§
Skrive værdien til filen
§
Lukke filen
For at åbne
filen gør man sådan her:
fd = open("/sys/class/leds/<led name>/brightness",
O_WRONLY)
Fil pointeren
(fd) bruges så til de efterfølgende operationer.
Du kan skrive
ls /sys/class/leds for at se hvilke LEDs som er tilrådighed
Du skal
inkludere følgende biblioteker:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
For at skrive
til lysdioden skal du skrive en enkelt char indeholdene ascii ’0’ eller ’1’.
Endnu mere om
open/close mm kan findes her:http://www.opengroup.org/onlinepubs/007908775/xsh/open.html
Ingen kommentarer:
Send en kommentar