The new course starts soon but now you can read the first tutorial on our blog.
Rafael Santiago de Souza Netto
This course is intended for C programmers who want to learn the basics of device driver development. The course will cover:
- Character devices.
- How to add new system calls to your OS.
- Basic notions about network drivers.
The course consists of seven modules. As part of the course final exam, you will write a character device able to implement a fully functional ARC4 encryptor.
You should know …
- UNIX, BSD basic concepts.
- Networking Fundamentals (including protocols).
- C programming (basic/medium).
- How to use git and related code hosting services.
You will learn:
- Device drivers development concepts.
- Experience implementing device drivers in the BSD Oses using syscalls, char devices and network devices.
- Best practices for testing device driver/kernel-mode code.
Module 1: Introduction
Tutorial 1. Overview of C Programming and UNIX
Nowadays, UNIX stands more as a model for an operating system to follow rather than an operating system implementation. In the beginning, UNIX as a software was originally written at Bell Labs by two famous developers: Kenneth Thompson and Dennis Ritchie.
In 1963, Bell Labs and others companies joined to create a new operating system with the following requirements:
- Be multi-tasking
- Be capable of storing and sharing data and programs on a large scale
- Allow data sharing among users and groups
This project/system was called MULTICS. It was developed on a GE-645 but in 1969, MULTICS was still not a fully working operating system. Other companies have continued the MULTICS development but Bell Labs, not seeing much future in this project, decided to quit.
During that time, some developers within Bell Labs were frustrated with the decision to quit and, started developing a simpler MULTICS version themselves.
Actually, Kenneth Thompson was tired of trying to play ‘Space Travel’ in MULTICS. Space Travel was a simulation game he originally wrote for MULTICS. However, the operating system was not much able of well executing that game. Still in 1969, facing the MULTICS execution problems, Thompson decided to port Space Travel to another unused computer in his laboratory, a PDP-7. Having developed tons of workarounds to make possible the game execution, this porting effort quickly became an entire operating system, fully written in PDP-7 assembly.
In order to convince the company managers about how serious the project was, it was presented as a future text editor; later, it evolved to a general-purpose operating system, named UNIX.
Several technologies were developed as support for the UNIX project. The most important was the C programming language, developed by Dennis Ritchie.
C was developed as an evolution of Thompson’s B language. The UNIX was totally re-written in C and it was released as a commercial operating system. C allowed UNIX to be developed in a more portable way with regard to other computer architectures. The portability introduced by the C language was a seminal step in computing field as a whole.
The name ‘UNIX’ is just a pun on the name ‘MULTICS’.
The features and fruits of UNIX
The interesting thing about UNIX is that its source code was used in Operating System classes until the code was closed by AT&T. If you are interested in looking at the original UNIX source code developed by Thompson & Ritchie (UNIX V6), search for the book: “Lions’ commentary on UNIX 6th Edition – with source code” (ISBN 1-57398-013-7). The book was organized by professor John Lions as a study aid for his students. The book has the complete UNIX V6 code listing and sections where Lions discusses all system parts, explaining the code.
Around the world, many operating system developers have debuted in this field reading those notes from professor Lions.
When UNIX was closed and its source code could not be used in classes anymore, another college professor, Andrew Stuart Tanenbaum, decided to create the MINIX project. MINIX would become one of the first efforts of creating a UNIX-like operating system without the original source code from Bell Labs. Also, one of the most famous books about Operating Systems widely used in many Computer Science classes until today originated from the MINIX project. The MINIX development is still active. Currently, MINIX is licensed under BSD.
The first BSD versions were branches of the original UNIX. At present, any “BSD” system can be considered a derivative of the original UNIX ancestor.
Linux is another famous modern UNIX-like but its development started in 90’s, and it does not have any code from original UNIX.
User programs can be easily ported from UNIX-like to another. The sharing between all those UNIX-like systems is only possible because all of them follow an important document called Single Unix Specification (http://opengroup.org/unix). This document summarizes what an operating system must implement to be considered a UNIX-like.
The Single Unix Specification is composed of three documents: ANSI C, XPG4, and POSIX.
The ANSI C is about the standard for the C language implementation, including syntax, libraries and other features. The XPG4 is about standards for X server, the graphical UNIX interface. The POSIX document lists all system calls and signals that a UNIX-like must implement.
How internally a UNIX-like works does not matter for the Single Unix Specification, but how this UNIX-like externally reacts and replies is very important. It defines if the system can be considered a UNIX-like or not. Due to it, maybe POSIX could be considered the most important document in the whole standard.
The POSIX signals and system calls
The POSIX standard defines 31 signals. Those signals must be implemented by a UNIX-like. Table 1 lists more details about each of them. Signals are important because the system uses them to manage its processes. Processes are able to send and receive signals.
Table 1: The POSIX signals.
|2||SIGINT||Terminal interrupt signal|
|3||SIGQUIT||Terminal quit signal|
|6||SIGABRT||Process abort signal|
|–||SIGIOT||Process abort signal. (PDP-11)|
|9||SIGKILL||Kill (can not be ignored)|
|–||SIGFPE||Erroneous arithmetic operation|
|–||SIGUSR1||User-defined signal 1|
|–||SIGBUS||Access to an undefined portion of a memory object|
|–||SIGSEGV||Invalid memory reference|
|–||SIGUSR2||User-defined signal 2|
|–||SIGPIPE||Write on a pipe with no one to read it (broken-pipe)|
|15||SIGTERM||Termination signal (can be ignored)|
|–||SIGCHLD||Child process terminated, stopped, or continued|
|–||SIGCONT||Continue executing, if stopped|
|–||SIGSTOP||Stop executing (cannot be caught or ignored)|
|–||SIGTSTP||Terminal stop signal|
|–||SIGTTIN||Background process attempting read|
|–||SIGTTOU||Background process attempting write|
Opposing to the standard signals, there are several system calls. Some of them are related to the file system (open, read, and write), time utilities (gettimeoftheday), networking (send, recv, accept), etc.
As you should see, some system call names are used also to name functions inside the standard C library. These C library functions are directly related to those system calls but the standard C library only implements the user side of them. Being those C functions only tiny windows to the true system calls.
A brief overview of C language
C is a powerful procedural language created by Dennis Ritchie at Bell Labs to simplify the UNIX development. One of the most impressing concepts introduced by C language was the notion of portability.
Functionalities like the unary operator “sizeof” and the C pre-processor made the process of porting software easier than before.
Although at first glance it was developed as support technology for the UNIX project, the use of C has gone beyond the UNIX frontiers and C has been proved to be a well succeed programming language. Even nowadays, despite the advent of more modern and “friendly” programming languages, there are still tons of legacy and new software being maintained and developed in C.
The compilation process of a C program can be divided into 3 main phases: Pre-processing, Compiling and Linking.
The pre-processing phase is performed by the C pre-processor software. This program handles all defined macro stuff and the compiler directives.
The compiling phase is managed by the C compiler itself. It parses the source codes seeking to verify all data. Aborting when some lexical or syntax error are found.
The linking is done by the linker program. This software will properly generate the executable code.
The C language is surprisingly powerful and compact. The basic data types include int, long, short, char, float and double. It is also possible to use these types with unsigned values. In this case, the type name must be prefixed by the reserved word “unsigned”. It is also possible to use some extensions of some types such as “long long”, etc.
User-defined types are also allowed, in this case, the reserved word “typedef” is used for doing it.
One of the most powerful features in C language is pointers. Pointers, as the name suggest, instead of directly storing data, they indirect to the data: it does store a memory address where some data is in.
The memory management is all up to the developer. For beginners, it makes C a little bit hard. Anyway, programming in C is valuable for any student who really wants to know how their system works.
Since this course assumes C Programming skills as pre-requisite, more details about the core of the language will not be given.
Nonetheless, if you have problems with pointers, structs, how to implement classical data structures in C, basic flow control statements, ANSI C functions, function pointers, or a more advanced C macro usage, I would suggest you study more deeply on the C language before starting taking this course.