linux device driver lab4part_b

6
L a b 4 B. L in u x b oot - up on XUP b oa rd a nd writi n g De vice Drivers for Custom-IP Objective In this wee k, we will write the de vice drive r for a CustomIP (the m ul tipl ie r tha t we lea rnt to cre at e in L a b 3) and run it on th e Linux OS. Device Drivers I n the ke rnel, e verythi ng tha t the syste m inte racts with is represente d by a de vice driver. Drivers can be implemented in two different ways: as a built-in piece of static kernel code , or as a d ynam ic pie ce of code known a s a m odul e. A bui lt- in driver i s, as th e na me sugg e sts, com pile d in sta ticall y to the kerne l, and is always re ad y to be call e d. A kerne l m odule, however, is a se paratepieceof code which can be loade d a nd unl oade d f rom the kernel on the fly. While you must load a module to be able to use it, the advantage is that it doesn't take up m em ory when you don't nee d it. We sha ll be usi ng the m odul e s ap proach. A kerne l m odul e (drivers a re kerne l m odul e s) m us t be com pi le d a s a ".o" f ile (not linke d to a n e xe cuta bl e ). I n this res pe ct, it is diffe ren t from conventional programs. Rather than executing it, you install it into the running Linux ke rne l at run time.  Th e Unix way of loo k ing a t de v ices dis t inguishes between t h r ee de v ice t ypes. Each module usually implements one of these types, and thus is classifiable as a char m odu le , a bl ock m odule , or a networ k m odule . We shall be writing the driver for a character (char) de vice. A cha r device i s one th at ca n be acces se d as a streamof byte s (l ike a fi le). An useful resource for this lab is O’Reilly Linu x De vice Dri ve rs, 2 nd Edition . Note that you need to look at the second edition of the book which deals with linux kernel versions 2.0 through 2.4, with focus on all the features available to device driver writers in 2.4. Please read Chapter 3 of this book (Char Drivers) to understand how to write a complete char device driver. Procedure 1.  Log on to the linux m ach ine usi ng th e s sh cl ie nt with your id a nd pa ssword. 2.  Create a di rec tory calle d MODULES in you r home di rec tory. We sha ll be creating all subdirectories for our modules within this directory. We will start with a de vice d rive r for the si m pl e “h e llo world” progra m . I n your hom e directory, mkdir –p MODULES/hello cd MODULES/hello  3.  In thehe llo directory, cre a te a file ca lle d h ello.c with t he following code : #i ncl ude < l i nux/ ker nel . h> # i ncl ude < l i nux/ m od ul e. h>

Upload: vinod-gupta

Post on 03-Apr-2018

219 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 1/6

Lab 4B. Linux boot-up on XUP board and writing DeviceDrivers for Custom-IP

ObjectiveIn this week, we will write the device driver for a Custom IP (the multiplier that we learntto create in Lab 3) and run it on the Linux OS.

Device Drivers

In the kernel, everything that the system interacts with is represented by a device driver.Drivers can be implemented in two different ways: as a built-in piece of static kernelcode, or as a dynamic piece of code known as a module. A built-in driver is, as the namesuggests, compiled in statically to the kernel, and is always ready to be called. A kernelmodule, however, is a separate piece of code which can be loaded and unloaded from the

kernel on the fly. While you must load a module to be able to use it, the advantage is thatit doesn't take up memory when you don't need it.

We shall be using the modules approach. A kernel module (drivers are kernel modules)must be compiled as a ".o" file (not linked to an executable). In this respect, it is differentfrom conventional programs. Rather than executing it, you install it into the runningLinux kernel at runtime.

 The Unix way of looking at devices distinguishes between three device types. Eachmodule usually implements one of these types, and thus is classifiable as achar module,ablock module, or anetwork module. We shall be writing the driver for a character (char)

device. A char device is one that can be accessed as a stream of bytes (like a file).An useful resource for this lab is O’Reilly Linux Device Drivers, 2nd Edition. Note thatyou need to look at the second edition of the book which deals with linux kernel versions2.0 through 2.4, with focus on all the features available to device driver writers in 2.4.Please read Chapter 3 of this book (Char Drivers) to understand how to write a completechar device driver.

Procedure1.  Log on to the linux machine using the ssh client with your id and password.2.   Create a directory called MODULES in your home directory. We shall be

creating all subdirectories for our modules within this directory. We will start

with a device driver for the simple “hello world” program. In your homedirectory,

mkdir –p MODULES/hellocd MODULES/hello 

3.  In the hello directory, create a file called hello.c with the following code:

#i ncl ude <l i nux/ ker nel . h>#i ncl ude <l i nux/ modul e. h>

Page 2: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 2/6

 stati c i nt i ni t _modul e( voi d) {

pr i nt k( "Hel l o wor l d! \ n") ;r et ur n 0;

}

st at i c voi d cl eanup_modul e( voi d) {pr i nt k(" Bye, cruel wor l d\ n") ;

}

Note that the kernel code uses ‘printk’ instead of printf statements. 

4.   The Makefile to compile this code will be:

COMPI LER = powerpc- l i nux- gccLD = power pc- l i nux- l dUCFRONT = ~/ uCl i nux- di st / t ool s/ ucf r ont - gcc

COMPI LER_FLAGS=COMPI LER_FLAGS+= - D__KERNEL__ 

COMPI LER_FLAGS+=- DMODULE

PATH : = $( PATH) : ~/ uCl i nux- di st / t ool s: ~/ power pc- el f - t ool s/ bi n

RELEASEDI R=I NCLUDES=- I . / .

SOURCES = hel l o. cOUT = hel l o. o

al l : hel l o

hel l o: $(SOURCES)echo "Compi l i ng modul e"

$( COMPI LER) $( COMPI LER_FLAGS) $( I NCLUDES) - c - o $( OUT)( SOURCES)  

5.  Run ‘make’ in the hello directory. It should generate hello.o file for you. This isthe driver ‘.o’ file that needs to be inserted in the kernel.We need to copy this ‘.o’ inside our linux filesystem. To do this, change directoryto ‘uClinux-dist’ and open the file ‘uClinux-dist/vendors/Xilinx/powerpc-auto/Makefile’. Scroll down till you find the command:

$(ROMFSINST) -s bin /sbinBelow this command, add the following lines:

[ -d $(ROMFSDIR)/module ] || mkdir $(ROMFSDIR)/module

cp ~/MODULES/hello/hello.o $(ROMFSDIR)/module/hello.o

 This will create a directory called module in the linux filesystem, and place thefile hello.o inside it.Now type ‘make’ in the uClinux-dist directory to generated the updated image.elf file. Check that a directory called ‘module’ is indeed created in uClinux-dist/romfs and it contains the hello.o file.

Page 3: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 3/6

Use this new image.elf file to create the system.ace file. Boot linux on thehyperterminal.

6.   On the hyperterminal screen, type:cd module

insmod hello.o The insmod command invokes the init_module routine of your driver code. Youshould thus see ‘Hel l o wor l d! ’ printed on the hyperterminal screen.Also, when you do ‘lsmod’, it should show the ‘hello’ module. Remove thismodule by ‘rmmod hello’ command. This will invoke the cleanup_moduleroutine. You should see the print statement corresponding to cleanup_module onthe hyperterminal screen. 

7.   Now, let us write a simple driver for the ‘multiply’ Custom IP. Copy the filemultiply.h from lab4/drivers/multiply_v1_00_a/src/multiply.h on your Windowsmachine to Desktop (on Windows machine) and open it with Notepad/Wordpad.

Find and replace allXuint32

byu32

and then copy this file toMODULES/multiply on the linux box.

For the multiplier, make the following changes in the Makefile (compared to theone for the hello module).

I NCLUDES+= - I ~/ uCl i nux- di st / l i nux- 2. 4. x/ i ncl udeI NCLUDES+= - I ~/ uCl i nux- di st / l i nux- 2. 4. x/ ar ch/ ppcI NCLUDES+= - I ~/ uCl i nux- di st / l i nux-2. 4. x/ ar ch/ ppc/ pl at f or ms/ xi l i nx_ocp

SOURCES = mul t i pl y. cI NCLUDEDI R = mul t i pl y. h

OUT = mul t i pl y. o

al l : mul t i pl y

mul t i pl y: $(SOURCES) $( I NCLUDEFI LES)echo "Compi l i ng modul e"$( COMPI LER) $( COMPI LER_FLAGS) $( I NCLUDES) - c - o $( OUT)

( SOURCES)

8.  Add the following code to multiply.c

#i ncl ude <l i nux/ modul e. h>#i ncl ude <l i nux/ i ni t . h>#i ncl ude <l i nux/ aut oconf . h> / / Thi s i s t he f i l e f r om EDK wi t hdef i nes

/ / Thi s f i l e ener at ed by t he EDK #i ncl ude "mul t i pl y. h"

/ / Decl are some var i abl es/ / The physi cal base addr ess f or t he mul t i pl i er devi ce.unsi gned phy_add = CONFI G_XI LI NX_MULTI PLY_ 0_BASEADDR;

Page 4: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 4/6

 / / The si ze of memor y al l ocat ed t o the mul t i pl i er devi ce.unsi gned r emapSi ze = CONFI G_XI LI NX_MULTI PLY_ 0_HI GHADDR -

CONFI G_XI LI NX_MULTI PLY_0_BASEADDR + 1;/ / Thi s wi l l be t he vi r t ual addr ess used t o poi nt t o mul t i pl i erunsi gned vi r t _add;

/ / Thi s i s t he code t hat gets execut ed upon l oadi ng of t hemodul e. I t i s cal l ed i nst ead of i ni t _modul e( ) because of a macr odecl ar ed at t he bot t om of t he f i l e.i nt mul t i pl i er I ni t ( voi d) {

i nt res;/ / Map the devi ce' s addr essesvi r t _add = ( unsi gned) i oremap( phy_add, r emapSi ze) ;pr i ntk( "MULTI PLY PA of 0x%x has mapped t o a VA of 0x%x\ n",

phy_add, vi r t _add) ;

/ / Wr i t e t o r egi ster 0pr i nt k(" Wr i t i ng a 7 t o r egi st er 0\ n") ;MULTI PLY_mWr i t eReg( vi r t _add, 0, 7) ;

/ / Wr i t e t o r egi ster 1pr i nt k(" Wr i t i ng a 2 t o r egi st er 1\ n") ;MULTI PLY_mWr i t eReg( vi r t _add, 4, 2) ;

pr i nt k( "Read %d f r omr egi st er 0\ n" , MULTI PLY_mReadReg( vi r t _add,0)) ;

pr i nt k( "Read %d f r omr egi st er 1\ n" , MULTI PLY_mReadReg( vi r t _add,4)) ;

pr i nt k( "Read %d f r omr egi st er 2\ n" , MULTI PLY_mReadReg( vi r t _add,8)) ;

r et ur n 0;}

/ / Thi s i s t he r out i ne cal l ed when t he modul e i s unl oaded. I t/ / essent i al l y un- does what t he i ni t i al i zat i on code di d.voi d mul t i pl i er Exi t ( voi d) {

/ / Unmap t he vi r t ual addr ess f or t he devi cei ounmap( ( voi d *) vi r t _add) ;

}

/ / Tel l compi l er t o not expor t anyt hi ng at al l f r om t hi s modul ef or use by ot her s.EXPORT_NO_SYMBOLS;

/ / Decl are names of i ni t and cl eanup f unct i onsmodul e_i ni t ( mul t i pl i er I ni t ) ;

modul e_exi t ( mul t i pl i er Exi t ) ;

Compile this code with the ‘make’ command. Add multiply.o in your linuxfilesystem. When you insmod ‘multiply.o’, the multiplierInit routine will beexecuted.- In function calls to MULTI PLY_ mWr i t eReg ( and MULTI PLY_ mReadReg) , inkernel space, note that virtual address is used instead of the physical address.- Also, the size of each of the registers (declared in your Verilog Custom IP) is 32

Page 5: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 5/6

bits (4 bytes). The offset for register0 is 0, register1 is 4 and register2 is 8. Thesenumbers are same as the numbers you would have used in the multiplier IP of Lab3.

9.  Note that we have still not registered a device and written a driver for that. All the

functionality is provided in the init_module routine itself. This is not typicallyhow practical device drivers are written. ‘insmod’ is used to register the deviceand obtain a virtual address for the device. The read/ write routines are thencalled, as required. When you do not need the device any longer, cleanup_moduleroutine is called to unregister the device and unmap the virtual address for thedevice.

10. Create a directory called ‘multiplier’ in your MODULES directory on the linuxbox (note that we are calling this module ‘multiplier’, while your last module wascalled ‘multiply’. This is to differentiate between the two. You will be able toinsmod both your ‘multiply’ and ‘multiplier’ modules one after the other. Two

modules cannot have the same name, two modules can however be used to drivethe same device). You will now write the init, exit, read and write routines for your driver. You willalso write a file called devtest.c to test your multiplier. We need to modify theMakefile to include the command to compile devtest.c. Following lines need to beadded:

al l : mul t i pl i er devt est

devtest: devtest. c$(UCFRONT) $( COMPI LER) - Os - g - f omi t - f r ame- poi nt er - f no-

common - f no- bui l t i n - Wal l - DEMBED - Dl i nux - D__ l i nux__ - Duni x -D__uCl i nux__ - Wal l - O - c - o devtest . o devtest . c

$(UCFRONT) $(COMPI LER) devt est . o - o devt est

 The modified Makefile, along with the skeleton for multiplier.c and devtest.c canbe copied from ‘/software/module/multiplier’ directory.

11.  The skeleton files are commented to indicate what functions you need to use.Please read Chapter 3 of Linux Device Drivers, 2nd Editionto understand thearguments to these functions.

Some useful information is provided below:- To link normal files with a kernel module two numbers are used: ‘major

number’ and ‘minor number’. The major number is the one the kernel uses to linka file with its driver. It is common for a driver to control several devices (asshown in the listing); the minor number provides a way for the driver todifferentiate among them. The minor number is used by the driver for interfacingwith multiple devices.

- To interface the normal files with the kernel module (using major and minornumbers as discussed above), a file (which will be used to access the device

Page 6: Linux Device Driver Lab4part_b

7/28/2019 Linux Device Driver Lab4part_b

http://slidepdf.com/reader/full/linux-device-driver-lab4partb 6/6