User-Space Debugging Simplifies Driver Development

Similar documents
Migrating Linux Device Drivers to a Microkernel POSIX RTOS: A Case Study. David Donohoe Senior Software Developer QNX Software Systems

QNX MOMENTICS ACCELERATE YOUR DEVELOPMENT WITH QNX MOMENTICS KNOCK WEEKS, EVEN MONTHS, OFF YOUR DEVELOPMENT SCHEDULE WITH THE

Exam Questions. Give an example network topology where GPSR cannot find a way from a source to a sink. Explain your answer.

ECEN 449 Microprocessor System Design. Hardware-Software Communication. Texas A&M University

Embedded Linux Architecture

Overview. POSIX signals. Generation of signals. Handling signals. Some predefined signals. Real-time Systems D0003E 3/3/2009

CSE 153 Design of Operating Systems Fall 18

Problem Set: Processes

Making the Switch to RapidIO

Problem Set: Processes

ECE 650 Systems Programming & Engineering. Spring 2018

PROJECT 2 - MEMORY ALLOCATOR Computer Systems Principles. October 1, 2010

Signal Example 1. Signal Example 2

Processes. Johan Montelius KTH

CSE 153 Design of Operating Systems

QNX Software Development Platform 6.6. Quickstart Guide

A process. the stack

Lecture 2: Architectural Support for OSes

Chapter 2: System Structures

Introduction to Operating Systems Prof. Chester Rebeiro Department of Computer Science and Engineering Indian Institute of Technology, Madras

ENGR 3950U / CSCI 3020U Midterm Exam SOLUTIONS, Fall 2012 SOLUTIONS

Chap.6 Limited Direct Execution. Dongkun Shin, SKKU

Objectives. Chapter 2: Operating-System Structures. 2.1 Operating System Services

The Kernel Abstraction

Shared Memory Memory mapped files

In-Field Debugging: Diagnosing Software Problems While Maintaining System Availability

Operating systems. Lecture 7

QNX Neutrino RTOS. Instant Device Activation. User s Guide. For QNX Neutrino SP1 or later. 2007, QNX Software Systems GmbH & Co. KG.

Chapter 2. Operating-System Structures

CSE 4/521 Introduction to Operating Systems

Other Interprocess communication (Chapter 2.3.8, Tanenbaum)

Introduction: Context Switch

An Introduction to QNX Transparent Distributed Processing

Processes and Threads

User Space Device Drivers Introduction and Implementation using VGAlib library

CSE 421: Introduction to Operating Systems

Introduction. Interprocess communication. Terminology. Shared Memory versus Message Passing

CS 390 Chapter 2 Homework Solutions

Processes COMPSCI 386

Start of Lecture on January 20, Chapter 3: Processes

CSci 4061 Introduction to Operating Systems. (Advanced Control Signals)

What Is A Process? Process States. Process Concept. Process Control Block (PCB) Process State Transition Diagram 9/6/2013. Process Fundamentals

Interprocess Communication

Chapter 2: Operating-System Structures

Signals. POSIX defines a variety of signal types, each for a particular

System Call. Preview. System Call. System Call. System Call 9/7/2018

Chapter 2 Operating-System Structures

CS24: INTRODUCTION TO COMPUTING SYSTEMS. Spring 2015 Lecture 23

CSE 120 Principles of Operating Systems

임베디드리눅스응용프로그래밍. Why use an Operating System? Typical ARM Cortex-A9 Boot Sequence. Linux SD card Images

Linux Operating System

CSCE 313 Introduction to Computer Systems. Instructor: Dezhen Song Spring 2015

Fall 2015 COMP Operating Systems. Lab #3

Operating Systems 2010/2011

Operating System Architecture. CS3026 Operating Systems Lecture 03

CS24: INTRODUCTION TO COMPUTING SYSTEMS. Spring 2018 Lecture 23

Architectural Support for Operating Systems. Jinkyu Jeong ( Computer Systems Laboratory Sungkyunkwan University

Chapter 8: I/O functions & socket options

Operating systems. Lecture 9

CS 326: Operating Systems. Process Execution. Lecture 5

Chapter 2: Operating-System Structures

Chapter 13: I/O Systems

Real Time Operating Systems and Middleware

Chapter 2: Operating-System Structures

Input / Output. Kevin Webb Swarthmore College April 12, 2018

OS Design Approaches. Roadmap. OS Design Approaches. Tevfik Koşar. Operating System Design and Implementation

Fastboot Techniques for the x86 Architecture. Ben Biron QNX Software Systems

Operating Systems. Operating System Structure. Lecture 2 Michael O Boyle

QNX Neutrino RTOS. Adaptive Partitioning. User s Guide. For QNX Neutrino , QNX Software Systems GmbH & Co. KG.

Chapter 2: Operating-System Structures

Chapter 2: Operating-System Structures. Operating System Concepts 9 th Edition

CSCI 4061: Virtual Memory

Processes, Context Switching, and Scheduling. Kevin Webb Swarthmore College January 30, 2018

Programming with MPI

CSE 120 Principles of Operating Systems

Chapter 13: I/O Systems

CSCE-313 Introduction to Computer Systems

Memory management. Single process. Multiple processes. How to: All memory assigned to the process Addresses defined at compile time

Programming with MPI

CHAPTER 2: SYSTEM STRUCTURES. By I-Chen Lin Textbook: Operating System Concepts 9th Ed.

QNX SDK for Apps and Media 1.0. Multimedia Architecture Guide

QNX CAR Platform for Infotainment 2.1. QNX CAR Multimedia Architecture Guide

File Systems: Consistency Issues

CSC Operating Systems Fall Lecture - II OS Structures. Tevfik Ko!ar. Louisiana State University. August 27 th, 2009.

POSIX Shared Memory. Linux/UNIX IPC Programming. Outline. Michael Kerrisk, man7.org c 2017 November 2017

CS240: Programming in C

EECS 3221 Operating System Fundamentals

EECS 3221 Operating System Fundamentals

Notice: This set of slides is based on the notes by Professor Perrone of Bucknell and the textbook authors Silberschatz, Galvin, and Gagne

Announcements. Computer System Organization. Roadmap. Major OS Components. Processes. Tevfik Ko!ar. CSC Operating Systems Fall 2009

QNX Momentics Development Suite

CSCE Introduction to Computer Systems Spring 2019

CSE398: Network Systems Design

Chapter 2: Operating-System Structures. Operating System Concepts Essentials 8 th Edition

ELEC 377 Operating Systems. Week 1 Class 2

PROCESS MANAGEMENT. Operating Systems 2015 Spring by Euiseong Seo

Workshop on Inter Process Communication Solutions

Chapter 2: Operating-System

Preliminary. QNX Momentics Development Suite. Power Management Toolkit. User s Guide. For QNX Neutrino , QNX Software Systems Ltd.

Often, more information is required when designing system call Information varies according to OS and types of system call

Transcription:

QNX Software Systems Ltd. 175 Terence Matthews Crescent Ottawa, Ontario, Canada, K2M 1W8 Voice: 1 800 676-0566 +1 613 591-0931 Email: info@qnx.com Web: www.qnx.com User-Space Debugging Simplifies Driver Development Chris McKillop QNX Software Systems Ltd. cdm@qnx.com Introduction The traditional approach to driver development, in which every driver is written and debugged as part of the OS kernel, can seriously hamper the progress of an embedded project. For instance, a single programming error in any kernel-space driver can crash the target system. As a result, driver developers often waste time rebuilding and rebooting the target instead of actually testing and debugging software. To complicate matters, most embedded systems lack the non-volatile storage needed to save a kernel core dump between reboots. This makes postmortem debugging which would help locate the source of the system failure nearly impossible. As a further problem, kernel debuggers typically halt the entire system while the developer inspects the code or data of the driver being debugged. Because everything must run in lockstep with the debugger, the developer can easily miss bugs that would occur in a live system, where events happen asynchronously. Debugging Drivers in User Space Page 1

Fortunately, not all OSs rely on in-kernel drivers. The QNX Neutrino microkernel OS, for instance, treats every driver as a standard, user-space application. So, if any driver fails, the OS can cleanly terminate the driver and reclaim all the resources it was using; there s no need to rebuild and reboot. Better yet, drivers can be debugged with the same, standard process-level debuggers used to debug regular applications. There s no need to learn separate kernel-debug tools and no need to halt the entire system while a driver is being debugged. All other software processes continue to run normally. Kernel-space Development User-space Development Edit Edit Compile Compile Rebuild Kernel Source-level Debug Reboot System Low-level Debug When a kernel-space driver fails, the developer typically has to rebuild and reboot the entire target. But when a user-space driver fails, the developer can simply recompile and download the new driver. Even if your OS doesn t directly support user-space drivers, it will probably let you develop and debug significant parts of a driver in user space. You can then move the finished driver into the kernel to gain access to system services that don t have userspace interfaces. But whether your driver ultimately runs in kernel space or user space, it must still do the following: manipulate hardware registers access specific memory locations handle interrupts interact with other parts of the system Debugging Drivers in User Space Page 2

Since these attributes aren t normally associated with processes running in user space, you ll need to take several steps to ensure that the user-space driver operates correctly... Step 1: Gain Basic Privileges First, your user-space driver must gain appropriate privileges from the operating environment. On a UNIX/POSIX system, the driver will need to run as root (UID 0) and may also need to invoke a system-specific call to gain whatever additional permissions that drivers require. For example, in the QNX Neutrino RTOS, a driver will call ThreadCtrl(), which gives the driver full I/O and interrupt privileges. On Linux, an equivalent function is iopl(). Step 2: Gain Access to the Device At this point, the driver has the rights to access hardware and, on some CPU platforms, can start using instructions to access I/O ports or specific addresses in physical memory. In the latter case, the driver must ask the operating environment to set up a mapping between the required physical-address region and the driver s virtual address space. This is required since, as a user-space process, the driver runs in virtual memory. It may also be necessary to disable caching in this physical-address region to ensure that the driver reads and writes directly to the device. If you re working with a POSIX-compliant operating system, you can use a standard call, mmap(), to map address spaces. (Many non-posix systems provide an equivalent call.) Most developers with a UNIX background are familiar with mmap() as a way to map a file on disk into the address space of a process. But it can also map known, physical addresses into a process s address space, although the manner in which mmap() is used to do this isn t part of the POSIX standard. Nonetheless, most POSIX systems follow common conventions, including support for a special device, /dev/mem, which represents the entire physical-address space of the machine. A driver can open /dem/mem in the same way as a file, and then invoke mmap() to bring the desired section of physical-address space into the driver s virtual address space. The following example shows code that will map in the text-mode address space of a standard VGA card on a standard x86 PC: Mapping a VGA text buffer #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> Debugging Drivers in User Space Page 3

/* VGA Text Mode Segment Details */ #define MY_MAP_ADDR (0xb0000) #define MY_MAP_SIZE (1024*64) int main( void ) { int fd; void *ptr; fd = open( "/dev/mem", O_RDWR ); if( fd == -1 ) ptr = mmap( 0, MY_MAP_SIZE, PROT_READ PROT_WRITE, MAP_SHARED, fd, MY_MAP_ADDR ); if( ptr == MAP_FAILED ) /* Do something to the frame buffer */ } munmap( ptr, MY_MAP_SIZE ); close( fd ); return EXIT_SUCCESS; Step 3: Handle Interrupts If your device driver doesn t have to deal with interrupts, you can write a productionquality driver in user space regardless of your operating system. Graphics drivers, for instance, can be easily be done from user-space the XFree86 project represents a good example. Nonetheless, most drivers must support interrupts. Problem is, most OSs don t provide any facilities to propagate interrupt events from kernel space into user space. In such cases, your user-space driver will simplify initial development and debugging, but the final version will have to run in the kernel to avoid the overhead of user-space interrupt simulation. User-space interrupt handling, when supported, is very specific to the operating system. For example, QNX Neutrino provides APIs (InterruptAttach, InterruptAttachEvent) for different interrupt-handling modes. Because there s no standard method, let s look instead at how to simulate user-space interrupts on a system that doesn t support them. This will let you debug the driver in user space, even if it must ultimately run as part of the kernel. Debugging Drivers in User Space Page 4

Interrupt handlers are simply callback functions that are invoked asynchronously from the rest of the operating environment when the hardware being driven needs to be serviced or completes an operation. (This process is a very similar to how signal handlers are used by user-space applications to handle asynchronous events.) Since the real interrupt can t be asserted in the driver itself, the driver must poll the hardware to detect events that would normally cause an interrupt to occur. You can do this by setting up a signal handler and creating a timer. When the timer times out, the signal handler will be invoked. Within the signal handler, the hardware will be polled to see if a real interrupt has occurred or if the conditions that would cause a real interrupt have been met. Good starting values for polling will range from 10 to 100 milliseconds. This is just an estimate, however: if you set the frequency too high the system will become overloaded, and if you set it too low you could miss events and not get realistic performance numbers out of your driver. The following code example shows how to set up this simulation on a POSIX system. Simulating an interrupt by polling #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <stdio.h> #include <time.h> static int PollCount = 0; void interrupt_handler( int signo ) { /* Poll hardware and check for interrupt. Process if found. */ printf( "Polling Hardware: %d\n", PollCount++ ); } int main( void ) { int ret; timer_t timerid; struct sigevent sigev; struct itimerspec itime; /* Install the virtual interrupt handler */ signal( SIGUSR1, interrupt_handler ); /* Create the timer, and have it raise SIGUSR1 when it expires */ memset( &sigev, 0, sizeof( sigev ) ); sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGUSR1; ret = timer_create( CLOCK_REALTIME, &sigev, &timerid ); if( ret < 0 ) Debugging Drivers in User Space Page 5

/* Set the timer's timeout value, 100ms */ memset( &itime, 0, sizeof( itime ) ); itime.it_value.tv_sec = 0; itime.it_value.tv_nsec = 100000000; memcpy( &itime.it_interval, &itime.it_value, sizeof( itime.it_value ) ); ret = timer_settime( timerid, 0, &itime, NULL ); if( ret < 0 ) /* Normally would be blocking for requests, simulate by simply blocking */ while( 1 ) sleep( 10 ); } return EXIT_SUCCESS; Step 4: Handle System Interactions When writing kernel-space drivers, you have to ask the kernel to handle a special device file on the driver s behalf; this file is normally found under /dev. When I/O operations occur on the special file, generally via ioctl()calls, the kernel will route the data and requests to the driver and from the driver to the application. In OSs such as QNX Neutrino, where user-space drivers are the norm, the OS will provide an equivalent mechanism to route messages to and from the driver process. But in OSs where userspace drivers aren t the norm, the user-space driver must rely on an existing form of interprocess communication (IPC) provided by the operating system and wrap a custom API on the transport. For instance, the driver could use sockets (TCP or UNIX), SystemV IPC, named pipes (FIFOs), or shared memory. The first method, sockets, offers two notable benefits: easy-to-use bidirectional communication and a standard, cross-platform API. Although the exact details of writing a client-server socket application extend beyond the scope of this article, the basic flow is simple: 1) When the user-space driver starts, it creates a socket, binds that socket to a known address, and then waits for requests to service; 2) When an application needs to interact with the driver, it simply opens a connection to the driver s socket and begins to pass data back and forth over the connection. You can achieve the same results using POSIX or SystemV message queues or, for that matter, any other form of IPC provided by the operating environment. Debugging Drivers in User Space Page 6

Using DDKs to Speed Driver Development An OS may provide additional facilities to simplify development of user-space drivers. The QNX Neutrino RTOS, for instance, supports off-the-shelf driver development kits (DDKs) for a variety of device types, including audio, character, disk, graphics, input, networking, parallel, printer, serial, and USB. The kits include detailed documentation, ready-to-customize source code, and a framework that implements all higher-level, device-independent code in libraries the only code you have to write is the hardwarespecific code for your device. The DDKs are available in the QNX Momentics development suite, which provides tightly integrated, graphical tools (e.g. debugger, profiler, memory analysis tool, system analysis tool) to help you debug and optimize driver code. For information on QNX Momentics, visit http://www.qnx.com/products/ps_momentics/ If you wish to target multiple processor families, QNX Neutrino also provides functions and macros that let you write processor-independent drivers and applications. In some cases, you simply need to specify a new processor target to generate binaries for a different processor you can even build code for multiple processor families simultaneously. QNX Neutrino supports a wide variety of processors, including ARM, MIPS, PowerPC, SH-4, StrongARM, XScale, and x86. Building Self-Healing Systems Writing drivers in user-space isn t difficult. In fact, it has many benefits, even if you can use the user-space version only for initial development. Nonetheless, if your OS allows fully functional user-space drivers to run in your final product, as QNX Neutrino does, you can achieve an additional benefit: much greater reliability. This reliability comes from the ease with which faulty drivers can be restarted automatically, without operator intervention and without system resets. Systems can, in effect, heal themselves of driver failures. For many embedded systems this isn t just a desirable feature; it s an essential requirement: telecommunication service providers, for example, now demand virtually 100% uptime, and surgeons can t reboot their medical monitoring equipment in the middle of an operation! Better yet, user-space drivers can be replaced dynamically with new versions, allowing a system to provide continuous service even while being upgraded with new functionality. 2002 QNX Software Systems Ltd. All rights reserved. QNX, Momentics, Neutrino, and Build a more reliable world are registered trademarks of QNX Software Systems Ltd. in certain jurisdictions. All other trademarks and trade names belong to their respective owners. Debugging Drivers in User Space Page 7