1 uClinux course Day 5 of 5 - the debugger (gdb) and uClinux device drivers
2 Author: D L Johnson gdb overview u Gdb stands for Gnu debugger u It can perform the following functions +Start your program, specifying anything that might affect its behavior. +Make your program stop on specified conditions. +Examine what has happened, when your program has stopped. +Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another. u Gdb is often packaged with a GUI version such as Insight which creates a graphical wrapper around gdb u To start gdb in text mode (which we will use for this course) add the following switch to all gdb commands +gdb -nw
3 Author: D L Johnson Invoking gdb u Normall gdb is started with the program name as its argument +gdb hello –Make sure that the program was compiled with the –g option –gcc –g hello.c –o hello u Gdb normally looks for an initialisation file called.gdbinit in the directory the application is being debugged from. u The initialisation file can setup any gdb configuration options that are use often. If you don’t want to use it type +gdb –nx u Run your program by typing +run +r u Continue a program after any break by typing +continue +c
4 Author: D L Johnson gdb - examining source files u Examining source files +list 10 +l 10 –Prints source code lines cantered around line 10 of the current source file +list function1 –Prints lines centered around the beginning of function function1 +list –Continues printing more lines following the previous list command +list – –Prints lines just before the lines last printed +set listsize 20 –Changes the number of source lines printed to 20 (default is 10)
5 Author: D L Johnson gdb - examining source files +disas main –Disassemble source code of function main +disas 0x804843e 0x –Disassemble source code from address 0x804843e to 0x
6 Author: D L Johnson gdb - Setting breakpoints, watchpoints, catchpoints u Breakpoints make your program stop whenever a certain point in the program is reached u Watchpoints are special breakpoints that stop your program when the value of an expression changes u Catchpoints are special breakpoints that stop your program when a certain kind of event occurs such as throwing an exception
7 Author: D L Johnson gdb - breakpoints u Breakpoints are set with the break command or just using the abbreviation b +b myfunction1 –Sets a breakpoint at entry to function myfunction1 +b +offset or b -offset –Sets breakpoint offset number of lines forward or backward from current position +b linenum –Sets a breakpoint at linenum in the current source file +b filename:linenum +b filename:myfunction1 –As described above but breakpoint is set in file filename +b *address –Set a breakpoint at address address (this can set breakpoints in programs which fo not have debugging info or source files)
8 Author: D L Johnson +info breakpoints –Prints a table of all breakpoints that looks as follows u Clearing breakpoints +clear –Delete any breakpoints at the next instruction to be executed +clear linenum –Delete any breakpoints set at specified line linenum +delete +d –Delete all breakpoints, watchpoints and catchpoints +delete 4 –Delete breakpoint lablelled as breakpoint 4 +delete 1-5 –Delete breakpoints labelled 1 to 5 gdb - breakpoints
9 Author: D L Johnson gdb - breakpoints u Disabling/enabling breakpoints +disable 1 –Disables breakpoint labelled 1 in the breakpoint table shown by the “info b” command +disable 1-4 –Disables breakpoints labelled 1 to 4 in the breakpoint table +enable 1 –Enables breakpoint labelled 1 in the breakpoint table +enable once 2 –Enables breakpoint labelled 2 and disable subsequent to stopping program +enable delete 1-4 –Enables breakpoints labelled 1-4 and delete subsequent to stopping program
10 Author: D L Johnson gdb - breakpoints +condition 1 j==2 –Adds condition to breakpoint 1 stating that j must be equal to 2 to stop u Breakpoint command lists +break 8 if i>10 +commands +silent +printf “i is %d\n",I +i += 50 +cont +end –Sets up a set of commands that are executed at just before line 8 is executed if that value of I is greater than 10, it will print the value of I and modify it by adding 50, it will also continue execution of the program
11 Author: D L Johnson gdb - Continuing and stepping u Continuing and stepping +continue +c –Resume program execution at address where program last stopped +step +s –Continue running program until control reaches a different source line +step 10 –Continue as in step, but do so 10 times +next +n –Continue next source line in the current stack frame. Ie. If there is a call into a function only stop when returning from this function call.
12 Author: D L Johnson gdb - Continuing and stepping +next 10 –Continue as in next, but do so 10 times +finish –Continue running until just after function in selected stack frame returns +until +u –When reaching end of loop after single stepping through it, until makes the program continue execution until it exits the loop +stepi +si –Execute one machine instruction at a time (often useful to fo ‘display/I $pc’ when stepping through machine instructions – this makes gdb display next instruction to be executed
13 Author: D L Johnson gdb - Examining data u Examining data +print i +p i –Print the contents of variable I u Formatting data xRegard the bits of the value as an integer, and print the integer in hexadecimal. dPrint as integer in signed decimal. uPrint as integer in unsigned decimal oPrint as integer in octal tPrint as integer in binary. The letter `t' stands for "two“ cRegard as an integer and print it as a character constant. fRegard the bits of the value as a floating point number and print using typical floating point syntax. aPrint as an address, both absolute in hexadecimal and as an offset from the nearest preceding symbol. You can use this format used to discover where (in what function) an unknown address is located:
14 Author: D L Johnson gdb - Examining data u Example +p/x i –prints the value of variable I as hexadecimal u Examining a block of memory +x 0x80483bc –Displays single memory address contents 0x80483bc with disasembly +x/nfu addr –n = repeat count –f = display format - (i = instructions, x = hex) –u = unit size (b-bytes, h=2 bytes, w=4 bytes, g=8 bytes) +x/100xw 0x80483bc –Display bytes (word) blocks of memory in hex starting at 0x80483bc
15 Author: D L Johnson gdb - Automatic display u Automatic display +display expr –displays value of expr after each line is executed +display addr –displays contents of addr after each line is executed +display i+j –displays value of I+j after each line line is executed +info display –Shows list of all expressions to display automatically +delete display dnum +disable display dnum +enable display dnum –delete,disable or enable display dnum
16 Author: D L Johnson gdb - registers u Registers +info registers –print the name and values of all registers except floating point registers +info all-registers –print the name and values of all registers, including floating-point +info registers regname –print the value of register regname u Standard register names +p/x $pc –prints the program counter in hex +p/i $pc –prints the next instruction to be executed +p/x $sp –prints the stack pointer in hex
17 Author: D L Johnson gdb - various u Back tracing +backtrace +bt –prints a back trace of the entire stack u information on symbols +whatis myvar – prints the data type of variable myvar +info address symbol –Describe where the data for symbol is stored u Continuing at a different address +jump 14 –continue execution at line 14 of current code +jump *0x –Continue execution at address 0x
18 Author: D L Johnson Unix Device drivers
19 Author: D L Johnson Unix Device drivers - overview u Key issues when writing device drivers +Write kernel code to access the hardware, don’t force particular policies on the user as different users have different needs +The driver should deal with making hardware available +Leave issues about how to use the hardware to the applications +Occasionally policy decisions are made to simplify user applications such as offering byte-wide access to hardware instead of having to handle individual bits +Drivers should have the following characteristics –support synchronous and asynchronous operation –can be opened multiple times –exploit full capabilities of the hardware
20 Author: D L Johnson Unix Device drivers - Splitting the kernel In a Unix system, several concurrent processes attend to different tasks. Each process asks for system resources such as computing power, memory, network connectivity etc. The kernel is the big chunk of executable code in charge of handling all such requests. Though the distinction between the different the kernels role can be split into the following parts: +Process management: Create and destroy processes, handle their connection to the outside world and communication among different processes through signals, pipes etc. The scheduler controls how processes share the CPU +Memory management: calls such as malloc/free need to intelligently use the memory of the system to avoid memory holes or inefficient use of memory
21 Author: D L Johnson Unix Device drivers - Splitting the kernel +File systems: Unix is based heavily on a filesystem concept: almost everythin in Unix can be trated as a file. The kernel builds a structured filesystem on top of unstructured hardware (example filesystems are FAT and ext2) +Device control: Almost every system operation eventually maps to a physical device. All device control operations are performed by device driver code which is specific to the device being addressed (keyboards, mice, network cards) with the exception of the processor and memory. +Networking: Also managed by the operating system as most network operation are not specific to a process: incoming packets are asynchronous events. These packets must be collected identified and dispatched before a process takes care of them.
22 Author: D L Johnson Unix Device drivers - Splitting the kernel
23 Author: D L Johnson Unix device drivers - Classes of devices u Character devices +This is a device that can be accessed as a stream of bytes (like a file). The text console (/dev/console) and the serial ports (/dev/ttyS0) are examples of char devices. Unlike files these devices are characterised by sequential access u Block devices +A block device is a device that can host a file system such as a disk. It can only be accessed as multiples of a block where a block is usually a power of 2 block such as a kilobyte. Random access is possible on block devices. u Network interfaces +Not really a device - any network transaction is made through an interface, which is able to exchange data with other hosts. Communication between kernel and network device is completely different from that used with char and block devices - it uses functions related to packet transmission.
24 Author: D L Johnson Unix device drivers - Building and running modules u The following code is a “hello world” module which will be loaded into the kernel +#define MODULE +#include +int init_module(void) { printk(" Hello, world\n"); return 0; } +void cleanup_module(void) { printk(" Goodbye cruel world\n"); } –printk prints kernel level messages –The string is the priority of the message u You can test the module by inserting or removing it from the kernel +root# gcc -c hello.c +root# insmod./hello.o +Hello, world +root# rmmod hello +Goodbye cruel world
25 Author: D L Johnson Unix device drivers - Building and running modules u Difference between a module and an application +Applications performs a single task from begnning to end +Applications call functions they don’t define and resolve externals at linking stage using the appropriate library - printf uses libc for example +A module registers itself in order to serve future requests +A module is linked into the kernel and the only functions it can use are the ones exported by the kernel - printk is defined within the kernel
26 Author: D L Johnson Unix device drivers - kernel modules
27 Author: D L Johnson Unix device drivers - char driver u Devices are accessed through names in the file system u The device files or nodes are located in the /dev directory u Character devices are identified by a ‘c’ in the first column of the output of a ls -l u Block devices are also located in the /dev/ directory and are identified by a ‘b’ in the first column
28 Author: D L Johnson Unix device drivers - char driver u You will also have noticed two numbers (seperated by a comma) in the output of a ls -l command u These numbers are the major device number and the minor device number u The major number identifies the driver associated with the device (e.g. device 3 is a tty device) u It is common for a driver to control several devices; the minor number provides a way to differentiate among them
29 Author: D L Johnson Unix device drivers - char driver u For the driver to be used, the driver node must exist as a file in the /dev directory u This is done using the following command +mknod /dev/button0 c –This will make a character device called button0 whose major number is 254 and whose minor number is 0 u You can also view all the major numbers that are currently assigned to devices using +vi /proc/devices u You can request dynamic assignment of a major numbers in your code but you will have to first check which majot numbers were assigned before making the file nodes
30 Author: D L Johnson Unix device drivers - char driver u Char Device drivers in uClinux are written in the following directory: linux-2.4.x/drivers/char u Device drivers will use low level hardware addresses to communicate with the hardware, for the Atmel AT91 processor these are found in +linux-2.4.x/include/asm-armnommu/arch-atmel +for example in hardware.h –#define ARM_CLK( ) –#define AT91_USART_CNT 2 –#define AT91_USART0_BASE(0xfffd0000) –#define AT91_USART1_BASE(0xfffcc000) –#define AT91_TC_BASE(0xfffe0000) –#define AIC_BASE(0xfffff000) –#define AT91_PIOA_BASE(0xffff0000) –#define AT91_SF_CIDR(0xfff00000)
31 Author: D L Johnson Unix device drivers - char driver The function which make up a device driver are as follows:
32 Author: D L Johnson Unix device drivers - char driver
33 Author: D L Johnson u A new system to register devices has been introduced into the kernel 2.4.x called the device filesystem u The main advantages of devfs are as follows: +Device entry points in /dev are created at device initialization and removed at device removal. +The device driver can specify device names, ownership, and permission bits, but user-space programs can still change ownership and permission (but not the filename). +There is no need to allocate a major number for the device driver and deal with minor numbers. u u This can be called with –devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, umode_t mode, void *ops, void *info); or simplified with a wrapper function –misc_register(minor_num, name, fops)
34 Author: D L Johnson Unix device drivers - armbutton code u /* u * ARM Button Driver u *Copyright (C) CSIR David Johnson 2003 u * u */ u #include u #include u #include "armbutton.h" u static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ u static char button_output_buffer[32];/* Stores data to write out of device */ u static int bcount;/* The number of bytes in the buffer */ u /* u * This handler is called when the orange button is pressed (GPIO 10 of the u * SuperIO chip, which maps to logical IRQ 26). If the press_count is 0, u * this is the first press, so it starts a timer and increments the counter. u * If it is higher than 0, it deletes the old timer, starts a new one, and u * increments the counter. u */
35 Author: D L Johnson Unix device drivers - armbutton code u static void button_handler (int irq, void *dev_id, struct pt_regs *regs) u { u bcount = sprintf(button_output_buffer, "button pressed"); u wake_up_interruptible (&button_wait_queue); u } u /* u * This function is called when a user space program attempts to read u * /dev/armbutton. It puts the device to sleep on the wait queue until u * button_sequence_finished writes some data to the buffer and flushes u * the queue, at which point it writes the data out to the device and u * returns the number of characters it has written. This function is u * reentrant, so that many processes can be attempting to read from the u * device at any one time. u */ u static int button_read (struct file *filp, char *buffer, u size_t count, loff_t *ppos) u { u interruptible_sleep_on (&button_wait_queue); u return (copy_to_user (buffer, &button_output_buffer, bcount)) u ? -EFAULT : bcount; u } u /* u * This structure is the file operations structure, which specifies what u * callbacks functions the kernel should call when a user mode process u * attempts to perform these operations on the device. u */ u static struct file_operations button_fops = { u owner:THIS_MODULE, u read:button_read, u }; u /* u * This structure is the misc device structure, which specifies the minor u * device number (158 in this case), the name of the device (for /proc/misc), u * and the address of the above file operations structure. u */
36 Author: D L Johnson Unix device drivers - armbutton code u static struct miscdevice button_misc_device = { u BUTTON_MINOR, u "armbutton", u &button_fops, u }; u /* u * This function is called to initialise the driver, either from misc.c at u * bootup if the driver is compiled into the kernel, or from init_module u * below at module insert time. It attempts to register the device node u * and the IRQ and fails with a warning message if either fails, though u * neither ever should because the device number and IRQ are unique to u * this driver. u */ u static int __init armbutton_init(void) u { u printk (KERN_INFO "ARM Button Driver Version %s (C) CSIR " u "David Johnson 2003.\n", VERSION); u if (misc_register (&button_misc_device)) { u printk (KERN_WARNING "armbutton: Couldn't register device 10, " u "%d.\n", BUTTON_MINOR); u return -EBUSY; u } u if (request_irq (IRQ_EXT0, button_handler, SA_INTERRUPT, u "armbutton", NULL)) { u printk (KERN_WARNING "armbutton: IRQ %d is not free.\n", u IRQ_PIOA); u misc_deregister (&button_misc_device); u return -EIO; u } u return 0; u }
37 Author: D L Johnson Unix device drivers - armbutton code u static void __exit armbutton_exit (void) u { u free_irq (IRQ_PIOA, NULL); u misc_deregister (&button_misc_device); u } u MODULE_AUTHOR("David Johnson"); u MODULE_LICENSE("GPL"); u EXPORT_NO_SYMBOLS; u module_init(armbutton_init); u module_exit(armbutton_exit);
38 Author: D L Johnson Assignment 5 u Create a device driver which controls any of the 4 LED’s on the Atmel EB40 board +Hint the EB40 board uses the following lines for its LEDs –PIOA_TI0A0 RED –PIOA_TIOA1 AMBER –PIOA_TI0B0 GREEN u You can use a ioctl method or the write method to set the LED’s