Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization - Kaiwan N. Billimoria - E-Book

Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization E-Book

Kaiwan N Billimoria

0,0
27,59 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization is an ideal companion guide to the Linux Kernel Programming book. This book provides a comprehensive introduction for those new to Linux device driver development and will have you up and running with writing misc class character device driver code (on the 5.4 LTS Linux kernel) in next to no time.
You'll begin by learning how to write a simple and complete misc class character driver before interfacing your driver with user-mode processes via procfs, sysfs, debugfs, netlink sockets, and ioctl. You'll then find out how to work with hardware I/O memory. The book covers working with hardware interrupts in depth and helps you understand interrupt request (IRQ) allocation, threaded IRQ handlers, tasklets, and softirqs. You'll also explore the practical usage of useful kernel mechanisms, setting up delays, timers, kernel threads, and workqueues. Finally, you'll discover how to deal with the complexity of kernel synchronization with locking technologies (mutexes, spinlocks, and atomic/refcount operators), including more advanced topics such as cache effects, a primer on lock-free techniques, deadlock avoidance (with lockdep), and kernel lock debugging techniques.
By the end of this Linux kernel book, you'll have learned the fundamentals of writing Linux character device driver code for real-world projects and products.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB
MOBI

Seitenzahl: 624

Veröffentlichungsjahr: 2021

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization

 

 

 

 

 

Create user-kernel interfaces, work with peripheral I/O, and handle hardware interrupts

 

 

 

 

 

 

 

 

 

Kaiwan N Billimoria

 

 

 

 

 

 

 

 

BIRMINGHAM - MUMBAI

Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization

Copyright © 2021 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

 

Group Product Manager: Wilson D'souzaPublishing Product Manager: Vijin BorichaContent Development Editor: Romy DiasSenior Editor: Rahul D'souzaTechnical Editor:Shruthi ShettyCopy Editor: Safis EditingProject Coordinator: Neil DmelloProofreader: Safis EditingIndexer:Pratik ShirodkarProduction Designer: Shankar Kalbhor

First published: March 2021

Production reference: 1190321

Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

ISBN 978-1-80107-951-8

www.packt.com

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
First, to my dear parents, Diana and Nadir "Nads", for showing me how to live a happy and productive life. To my dear wife, Dilshad (an accomplished financial advisor herself), and our amazing kids, Sheroy and Danesh – thanks for all your love and patience.
– Kaiwan N Billimoria
 

Packt.com

Subscribe to our online digital library for full access to over 7,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.

Why subscribe?

Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals

Improve your learning with Skill Plans built especially for you

Get a free eBook or video every month

Fully searchable for easy access to vital information

Copy and paste, print, and bookmark content

Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.

At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks. 

Contributors

About the author

Kaiwan N Billimoria taught himself BASIC programming on his dad's IBM PC back in 1983. He was programming in C and Assembly on DOS until he discovered the joys of Unix, and by around 1997, Linux!

Kaiwan has worked on many aspects of the Linux system programming stack, including Bash scripting, system programming in C, kernel internals, device drivers, and embedded Linux work. He has actively worked on several commercial/FOSS projects. His contributions include drivers to the mainline Linux OS and many smaller projects hosted on GitHub. His Linux passion feeds well into his passion for teaching these topics to engineers, which he has done for well over two decades now. He's also the author of Hands-On System Programming with Linux. It doesn't hurt that he is a recreational ultrarunner too.

Writing this book took a long while; I'd like to thank the team from Packt for their patience and skill! Carlton Borges, Romy Dias, Vijin Boricha, Rohit Rajkumar, Vivek Anantharaman, Nithin Varghese, Hemangi Lotlikar, and all the others. It was indeed a pleasure working with you.

 

I owe a debt of gratitude to the very able technical reviewers – Donald "Donnie" Tevault and Anil Kumar. They caught a lot of my mistakes and omissions and greatly helped make this book better.

About the reviewers

Donald A. Tevault, but you can call him Donnie, got involved with Linux way back in 2006 and has been working with it ever since. He holds the Linux Professional Institute Level 3 Security certification, and the GIAC Incident Handler certification. Donnie is a professional Linux trainer, and thanks to the magic of the internet, teaches Linux classes literally the world over from the comfort of his living room. He's also a Linux security researcher for an IoT security company.

 

Anil Kumar is a Linux BSP and firmware developer at Intel. He has over 12 years of software development experience across many verticals, including IoT, mobile chipsets, laptops/Chromebooks, media encoders, and transcoders. He has a master's degree in electronics design from the Indian Institute of Science and a bachelor's degree in electronics and communication from BMS College of Engineering, India. He is an electronics enthusiast and blogger and loves tinkering to create fun DIY projects.

Table of Contents

Title Page

Copyright and Credits

Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization

Dedication

About Packt

Why subscribe?

Contributors

About the author

About the reviewers

Preface

Who this book is for

What this book covers

To get the most out of this book

Download the example code files

Download the color images

Conventions used

Get in touch

Reviews

Section 1: Character Device Driver Basics

Writing a Simple misc Character Device Driver

Technical requirements

Getting started with writing a simple misc character device driver

Understanding the device basics

A quick note on the Linux Device Model

Writing the misc driver code – part 1

Understanding the connection between the process, the driver, and the kernel

Handling unsupported methods

Writing the misc driver code – part 2

Writing the misc driver code – part 3

Testing our simple misc driver

Copying data from kernel to user space and vice versa

Leveraging kernel APIs to perform the data transfer

A misc driver with a secret

Writing the 'secret' misc device driver's code

Our secret driver – the init code

Our secret driver – the read method

Our secret driver – the write method

Our secret driver – cleanup

Our secret driver – the user space test app

Issues and security concerns

Hacking the secret driver

Bad driver – buggy read()

Bad driver – buggy write() – a privesc!

User space test app modifications

Device driver modifications

Let's get root now

Summary

Questions

Further reading

User-Kernel Communication Pathways

Technical requirements

Approaches to communicating/interfacing a kernel driver with a user space C app

Interfacing via the proc filesystem (procfs)

Understanding the proc filesystem

Directories under /proc

The purpose behind the proc filesystem

procfs is off-bounds to driver authors

Using procfs to interface with the user space

Basic procfs APIs

The four procfs files we will create

Trying out the dynamic debug_level procfs control

Dynamically controlling debug_level via procfs

A few misc procfs APIs

Interfacing via the sys filesystem (sysfs)

Creating a sysfs (pseudo) file in code

Creating a simple platform device

Platform devices

Tying it all together – setting up the device attributes and creating the sysfs file

The code for implementing our sysfs file and its callbacks

The "one value per sysfs file" rule

Interfacing via the debug filesystem (debugfs)

Checking for the presence of debugfs

Looking up the debugfs API documentation

An interfacing example with debugfs

Creating and using the first debugfs file

Creating and using the second debugfs file

Helper debugfs APIs for working on numeric globals

Removing the debugfs pseudo file(s)

Seeing a kernel bug – an Oops!

Debugfs – actual users

Interfacing via netlink sockets

Advantages using sockets

Understanding what a netlink socket is

Writing the user space netlink socket application

Writing the kernel-space netlink socket code as a kernel module

Trying out our netlink interfacing project

Interfacing via the ioctl system call

Using ioctl in the user and kernel space

User space – using the ioctl system call

Kernel space – using the ioctl system call

ioctl as a debug interface

Comparing the interfacing methods – a table

Summary

Questions

Further reading

Working with Hardware I/O Memory

Technical requirements

Accessing hardware I/O memory from the kernel

Understanding the issue with direct access

The solution – mapping via I/O memory or I/O port

Asking the kernel's permission

Understanding and using memory-mapped I/O

Using the ioremap*() APIs

The newer breed – the devm_* managed APIs

Obtaining the device resources

All in one with the devm_ioremap_resource() API

Looking up the new mapping via /proc/iomem

MMIO – performing the actual I/O

Performing 1- to 8-byte reads and writes on MMIO memory regions

Performing repeating I/O on MMIO memory regions

Setting and copying on MMIO memory regions

Understanding and using port-mapped I/O

PMIO – performing the actual I/O

A PIO example – the i8042

Looking up the port(s) via /proc/ioports

Port I/O – a few remaining points to note

Summary

Questions

Further reading

Handling Hardware Interrupts

Technical requirements

Hardware interrupts and how the kernel handles them

Allocating the hardware IRQ

Allocating your interrupt handler with request_irq()

Freeing the IRQ line

Setting interrupt flags

Understanding level- and edge-triggered interrupts – a brief note

Code view 1 – the IXGB network driver

Implementing the interrupt handler routine

Interrupt context guidelines – what to do and what not to do

Don't block – spotting possibly blocking code paths

Interrupt masking – the defaults and controlling it

Keep it fast

Writing the interrupt handler routine itself

Code view 2 – the i8042 driver's interrupt handler

Code view 3 – the IXGB network driver's interrupt handler

IRQ allocation – the modern way – the managed interrupt facility

Working with the threaded interrupts model

Employing the threaded interrupt model – the API

Employing the managed threaded interrupt model – the recommended way

Code view 4 – the STM32 F7 microcontroller's threaded interrupt handler

Internally implementing the threaded interrupt

Why use threaded interrupts?

Threaded interrupts – to really make it real time

Constraints when using a threaded handler

Working with either hardirq or threaded handlers

Enabling and disabling IRQs

The NMI

Viewing all allocated interrupt (IRQ) lines

Understanding and using top and bottom halves

Specifying and using a tasklet

Initializing the tasklet

Running the tasklet

Understanding the kernel softirq mechanism

Available softirqs and what they are for

Understanding how the kernel runs softirqs

Running tasklets

Employing the ksoftirqd kernel threads

Softirqs and concurrency

Hardirqs, tasklets, and threaded handlers – what to use when

Fully figuring out the context

Viewing the context – examples

How Linux prioritizes activities

A few remaining FAQs answered

Load balancing interrupts and IRQ affinity

Does the kernel maintain separate IRQ stacks?

Measuring metrics and latency

Measuring interrupts with [e]BPF

Measuring time servicing individual hardirqs

Measuring time servicing individual softirqs

Using Ftrace to get a handle on system latencies

Finding the interrupts disabled worst-case time latency with Ftrace

Other tools

Summary

Questions

Further reading

Working with Kernel Timers, Threads, and Workqueues

Technical requirements

Delaying for a given time in the kernel

Understanding how to use the *delay() atomic APIs

Understanding how to use the *sleep() blocking APIs

Taking timestamps within kernel code

Let's try it – how long do delays and sleeps really take?

The "sed" drivers – to demo kernel timers, kthreads, and workqueues

Setting up and using kernel timers

Using kernel timers

Our simple kernel timer module – code view 1

Our simple kernel timer module – code view 2

Our simple kernel timer module – running it

sed1 – implementing timeouts with our demo sed1 driver

Deliberately missing the bus

Creating and working with kernel threads

A simple demo – creating a kernel thread

Running the kthread_simple kernel thread demo

The sed2 driver – design and implementation

sed2 – the design

sed2 driver – code implementation

sed2 – trying it out

Querying and setting the scheduling policy/priority of a kernel thread

Using kernel workqueues

The bare minimum workqueue internals

Using the kernel-global workqueue

Initializing the kernel-global workqueue for your task – INIT_WORK()

Having your work task execute – schedule_work()

Variations of scheduling your work task

Cleaning up – canceling or flushing your work task

A quick summary of the workflow

Our simple work queue kernel module – code view

Our simple work queue kernel module – running it

The sed3 mini project – a very brief look

Summary

Questions

Further reading

Section 2: Delving Deeper

Kernel Synchronization - Part 1

Critical sections, exclusive execution, and atomicity

What is a critical section?

A classic case – the global i ++

Concepts – the lock

A summary of key points

Concurrency concerns within the Linux kernel

Multicore SMP systems and data races

Preemptible kernels, blocking I/O, and data races

Hardware interrupts and data races

Locking guidelines and deadlocks

Mutex or spinlock? Which to use when

Determining which lock to use – in theory

Determining which lock to use – in practice

Using the mutex lock

Initializing the mutex lock

Correctly using the mutex lock

Mutex lock and unlock APIs and their usage

Mutex lock – via [un]interruptible sleep?

Mutex locking – an example driver

The mutex lock – a few remaining points

Mutex lock API variants

The mutex trylock variant

The mutex interruptible and killable variants

The mutex io variant

The semaphore and the mutex

Priority inversion and the RT-mutex

Internal design

Using the spinlock

Spinlock – simple usage

Spinlock – an example driver

Test – sleep in an atomic context

Testing on a 5.4 debug kernel

Testing on a 5.4 non-debug distro kernel

Locking and interrupts

Using spinlocks – a quick summary

Summary

Questions

Further reading

Kernel Synchronization - Part 2

Using the atomic_t and refcount_t interfaces

The newer refcount_t versus older atomic_t interfaces

The simpler atomic_t and refcount_t interfaces

Examples of using refcount_t within the kernel code base

64-bit atomic integer operators

Using the RMW atomic operators

RMW atomic operations – operating on device registers

Using the RMW bitwise operators

Using bitwise atomic operators – an example

Efficiently searching a bitmask

Using the reader-writer spinlock

Reader-writer spinlock interfaces

A word of caution

The reader-writer semaphore

Cache effects and false sharing

Lock-free programming with per-CPU variables

Per-CPU variables

Working with per-CPU

Allocating, initialization, and freeing per-CPU variables

Performing I/O (reads and writes) on per-CPU variables

Per-CPU – an example kernel module

Per-CPU usage within the kernel

Lock debugging within the kernel

Configuring a debug kernel for lock debugging

The lock validator lockdep – catching locking issues early

Examples – catching deadlock bugs with lockdep

Example 1 – catching a self deadlock bug with lockdep

Fixing it

Example 2 – catching an AB-BA deadlock with lockdep

lockdep – annotations and issues

lockdep annotations

lockdep issues

Lock statistics

Viewing lock stats

Memory barriers – an introduction

An example of using memory barriers in a device driver

Summary

Questions

Further reading

Other Books You May Enjoy

Leave a review - let other readers know what you think

Preface

This book has been written with a view to helping you learn the fundamentals of Linux character device driver development in a practical, hands-on fashion, along with the necessary theoretical background to give you a well-rounded view of this vast and interesting topic area. To do the topics justice, that book's scope is deliberately kept limited to (mostly) learning how to write misc class character device drivers on the Linux OS. This way, you will be able to deeply imbibe the fundamental and necessary driver author skills to then be able to tackle different kinds of Linux driver projects with relative ease.

The focus is on hands-on driver development via the powerful Loadable Kernel Module (LKM) framework; the majority of kernel driver development is done in this manner. The focus is kept on working hands-on with driver code, understanding at a sufficiently deep level the internals wherever required, and keeping security in mind.

A recommendation we can't make strongly enough: to really learn and understand the details well, it's really best that you first read and understand this book's companion, Linux Kernel Programming. It covers various key areas – building the kernel from source, writing kernel modules via the LKM framework, kernel internals including kernel architecture, the memory system, memory alloc/dealloc APIs, CPU scheduling, and more. The combination of the two books will give you a sure and deep edge.

This book wastes no time – the first chapter has you learning the details of the Linux driver framework and how to write a simple yet complete misc class character device driver. Next, you learn how to do something very necessary: efficiently interfacing your driver with user space processes using various technologies (some of which help as debug/diagnostic aids as well!). Understanding, and working with, hardware (peripheral chip) I/O memory is then covered. Detailed coverage of handling hardware interrupts follows. This includes learning and using several modern driver techniques – using threaded IRQs, leveraging resource-managed APIs for drivers, I/O resource allocation, and so on. It covers what top/bottom halves are, working with tasklets and softirqs, and measuring interrupt latencies. Kernel mechanisms you will typically work with – using kernel timers, setting up delays, creating and managing kernel threads and workqueues – are covered next.

The remaining two chapters of this book delve into a relatively complex yet critical-to-understand topic for the modern pro-level driver or kernel developer: understanding and working with kernel synchronization.

The book uses the latest, at the time of writing, 5.4 Long Term Support (LTS) Linux kernel. It's a kernel that will be maintained (both bug and security fixes) from November 2019 right through December 2025! This is a key point, ensuring that this book's content remains current and valid for years to come!

We very much believe in a hands-on empirical approach: over 20 kernel modules (besides a few user apps and shell scripts) on this book's GitHub repository make the learning come alive, making it fun, interesting, and useful.

We really hope you learn from and enjoy this book. Happy reading!

Who this book is for

This book is primarily for Linux programmers beginning to find their way with device driver development. Linux device driver developers looking to overcome frequent and common kernel/driver development issues, as well as understanding and learning to perform common driver tasks – the modern Linux Device Model (LDM) framework, user-kernel interfaces, performing peripheral I/O, handling hardware interrupts, dealing with concurrency, and more – will benefit from this book. A basic understanding of Linux kernel internals (and common APIs), kernel module development, and C programming is required.

 

What this book covers

Chapter 1, Writing a Simple misc Character Device Driver, first goes through the very basics – what a driver is supposed to do, the device namespace, the sysfs, and basic tenets of the LDM. We then delve into the details of writing a simple character device driver; along the way, you will learn about the framework – in effect, the internal implementation of the "if it's not a process, it's a file" philosophy/architecture! You'll learn how to implement a misc class character device driver with various methods; several code examples help harden the concepts. Basic copying of data between the user-kernel space and vice versa is covered. Also covered are key security concerns and how to address them (in this context); a "bad" driver giving rise to a privilege escalation issue is actually demonstrated!

Chapter 2, User-Kernel Communication Pathways, covers how to communicate between the kernel and the user space, which is critical to you, as a kernel module/driver author. Here, you'll learn about various communication interfaces, or pathways. This is an important aspect of writing kernel/driver code. Several techniques are employed: communication via traditional procfs, the better way for drivers via sysfs, and several others, via debugfs, netlink sockets, and the ioctl(2) system call.

Chapter 3, Working with Hardware I/O Memory, covers a key aspect of driver writing – the issue with (and the solution to) accessing hardware memory (mapped memory I/O) from a peripheral device or chip. We cover using the common memory-mapped I/O (MMIO) technique as well as the (typically on x86) port I/O (PIO) techniques for hardware I/O memory access and manipulation. Several examples from existing kernel drivers are shown as well.

Chapter 4, Handling Hardware Interrupts, shows how to handle and work with hardware interrupts in great detail. We start with a brief on how the kernel works with hardware interrupts, then move on to how you're expected to "allocate" an IRQ line (covering modern resource-managed APIs), and how to correctly implement the interrupt handler routine. The modern approach of using threaded handlers (and the why of it), the Non-Maskable Interrupt (NMI), and more, are then covered. The reasons for and using both "top half" and "bottom half" interrupt mechanisms (hardirq, tasklet, and softirqs) in code, as well as key information regarding the dos and don'ts of hardware interrupt handling are covered. Measuring interrupt latencies with the modern [e]BPF toolset, as well as with Ftrace, concludes this key chapter.

Chapter 5, Working with Kernel Timers, Threads, and Workqueues, covers how to use some useful (and often employed by drivers) kernel mechanisms – delays, timers, kernel threads, and workqueues. They come in handy in many real-world situations. How to perform both blocking and non-blocking delays (as the situation warrants), setting up and using kernel timers, creating and working with kernel threads, and understanding and using kernel workqueues are all covered here. Several example modules, including three versions of a simple encrypt decrypt (sed) example driver, serve to illustrate the concepts learned in code.

Chapter 6, Kernel Synchronization – Part 1, first covers the key concepts regarding critical sections, atomicity, what a lock conceptually achieves, and, very importantly, the why of all this. We then cover concurrency concerns when working within the Linux kernel; this moves us naturally on to important locking guidelines, what deadlock means, and key approaches to preventing deadlock. Two of the most popular kernel locking technologies – the mutex lock and the spinlock – are then discussed in depth, along with several (driver) code examples.

Chapter 7, Kernel Synchronization – Part 2, continues the journey on kernel synchronization. Here, you'll learn about key locking optimizations – using lightweight atomic and (the more recent) refcount operators to safely operate on integers, using RMW bit operators to safely perform bit ops, and using the reader-writer spinlock over the regular one. Inherent risks, such as cache "false sharing," are discussed as well. An overview of lock-free programming techniques (with an emphasis on per-CPU variables and their usage, along with examples) is then covered. A critical topic, lock debugging techniques, including the usage of the kernel's powerful lockdep lock validator, is then covered. The chapter is rounded off with a brief look at memory barriers (along with an existing kernel network driver's usage of memory barriers).

We again stress that this book is for kernel programmers who are new to writing device drivers; several Linux driver topics are beyond this book's scope and are not covered. This includes other types of device drivers (besides character), working with the device tree, and so on. Packt offers other valuable guides to help you gain traction on these topic areas. This book would be an excellent start.

To get the most out of this book

To get the most out of this book, we expect you to have knowledge and experience of the following:

Know your way around a Linux system, on the command line (the shell).

The C programming language.

Know how to write simple kernel modules via the

Loadable Kernel Module

(

LKM

) framework

Understand (at least the basics) of key Linux kernel internals concepts: kernel architecture, memory management (plus common dynamic memory alloc/de-alloc APIs), and CPU scheduling.

It's not mandatory, but experience with Linux kernel programming concepts and technologies will help 

greatly

.

Ideally, we highly recommend reading this book's companion, Linux Kernel Programming, first.

The details on hardware and software requirements for this book, as well as their installation, are shown here:

Chapter number

Software required (with version)

Free /

proprietary

Download links to the software

Hardware specifications

OS required

All chapters

A recent Linux distribution; we use Ubuntu 18.04 LTS (as well as Fedora 31 / Ubuntu 20.04 LTS); any of these will be suitable. Recommend you install the Linux OS as a virtual machine (VM), using Oracle VirtualBox 6.x (or later) as the hypervisor

Free (open source)

Ubuntu (desktop): https://ubuntu.com/download/desktop

Oracle VirtualBox: https://www.virtualbox.org/wiki/Downloads

Required: a modern relatively powerful PC or laptop equipped with 4 GB RAM (minimally; the more the better), 25 GB free disk space, and a good internet connection.

Optional: we also use the Raspberry Pi 3B+ as a test bed.

Linux VM on a Windows host -OR-  Linux as a stand-alone OS

Detailed installation steps (software-wise):

Install Linux as a

VM

on a host Windows system; follow one of these tutorials:

Install Linux Inside Windows Using VirtualBox, Abhishek Prakash (It's FOSS!, August 2019)

https://itsfoss.com/install-linux-in-virtualbox/

Alternately, here's another tutorial to help you do the same: 

Install Ubuntu on Oracle VirtualBox

 

https://brb.nci.nih.gov/seqtools/installUbuntu.html

Install the required software packages on the Linux VM:

Log in to your Linux guest VM and first run the following commands within a Terminal window (on a shell):

sudo apt update

sudo apt install gcc make perl

Install the Oracle VirtualBox Guest Additions now. Reference:

 

How to Install VirtualBox Guest Additions in Ubuntu

https://www.tecmint.com/install-virtualbox-guest-additions-in-ubuntu/

(This step only applies if you are running Ubuntu as a VM using Oracle VirtualBox as the hypervisor app.)

To install the packages, take the following steps:

Within the Ubuntu VM, first run the 

sudo apt update

command

Now, run the

sudo apt install git fakeroot build-essential tar ncurses-dev tar xz-utils libssl-dev bc stress python3-distutils libelf-dev linux-headers-$(uname -r) bison flex libncurses5-dev util-linux net-tools linux-tools-$(uname -r) exuberant-ctags cscope sysfsutils curl perf-tools-unstable gnuplot rt-tests indent tree pstree smem hwloc bpfcc-tools sparse flawfinder cppcheck tuna hexdump trace-cmd virt-what

command in a single line.

Useful resources:

The Linux kernel official online documentation:

 

https://www.kernel.org/doc/html/latest/

.

The Linux Driver Verification (LDV) project, particularly the 

Online Linux Driver Verification Service

 

page: 

http://linuxtesting.org/ldv/online?action=rules

.

SEALS - Simple Embedded ARM Linux System: 

https://github.com/kaiwan/seals/

.

Every chapter of this book has a very useful 

Further reading 

section as well, detailing more resources.

Detailed instructions, as well as additional useful projects, installing a cross-toolchain for ARM, and more, are described in

 

Chapter 1, Kernel Workspace Setup

of this book's companion guide, 

Linux Kernel Programming, Kaiwan N Billimoria, Packt Publishing.

We have tested all the code in this book (it has its own GitHub repository as well) on these platforms:

x86_64 Ubuntu 18.04 LTS guest OS (running on Oracle VirtualBox 6.1)

x86_64 Ubuntu 20.04.1 LTS guest OS (running on Oracle VirtualBox 6.1)

x86_64 

Ubuntu 20.04.1 LTS native OS

ARM Raspberry Pi 3B+ (running both its distro kernel as well as our custom 5.4 kernel); 

lightly tested.

If you are using the digital version of this book, we advise you to type the code yourself or, better, access the code via the GitHub repository (link available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.

For this book, we'll log in as the user named llkd. I strongly recommend that you follow the empirical approach: not taking anyone's word on anything at all, but trying it out and experiencing it for yourself. Hence, this book gives you many hands-on experiments and kernel driver code examples that you can and must try out yourself; this will greatly aid you in making real progress and deeply learning and understanding various aspects of Linux driver/kernel development.

Download the example code files

You can download the example code files for this book from GitHub at  https://github.com/PacktPublishing/Linux-Kernel-Programming-Part-2. In case there's an update to the code, it will be updated on the existing GitHub repository.

We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

Download the color images

We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: http://www.packtpub.com/sites/default/files/downloads/9781801079518_ColorImages.pdf.

Conventions used

There are a number of text conventions used throughout this book.

CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "The ioremap() API returns a KVA of the void * type (since it's an address location)."

A block of code is set as follows:

static int __init miscdrv_init(void){ int ret; struct device *dev;

When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:

#define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__[...]

#include <linux/miscdevice.h>

#include <linux/fs.h> [...]

Any command-line input or output is written as follows:

pi@raspberrypi:~ $ sudo cat /proc/iomem

Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Select System info from the Administration panel."

Warnings or important notes appear like this.
Tips and tricks appear like this.

Get in touch

Feedback from our readers is always welcome.

General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].

Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.

Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.

If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

Reviews

Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!

For more information about Packt, please visit packt.com.

Section 1: Character Device Driver Basics

Here, we'll cover what a device driver is, namespaces, Linux Device Model (LDM) basics, and the character device driver framework. We'll implement simple misc drivers (leveraging the kernel's misc framework). We'll set up communication between the user and kernel spaces (via various interfaces, such as debugfs,  sysfs, netlink sockets, and ioctl). You will learn how to work with hardware I/O memory on a peripheral chip, as well as understanding and working with hardware interrupts. You'll also learn how to use kernel features such as kernel-level timers, create kernel threads, and use workqueues.

This section comprises the following chapters:

Chapter 1

,

Writing a Simple misc Character Device Driver

Chapter 2

User-Kernel Communication Pathways

Chapter 3

,

Working with Hardware I/O Memory

Chapter 4

,

Handling Hardware Interrupts

Chapter 5

,

Working with Kernel Timers, Threads, and Workqueues