Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Linux Device Driver Development Cookbook

You're reading from  Linux Device Driver Development Cookbook

Product type Book
Published in May 2019
Publisher Packt
ISBN-13 9781838558802
Pages 356 pages
Edition 1st Edition
Languages
Author (1):
Rodolfo Giometti Rodolfo Giometti
Profile icon Rodolfo Giometti

Table of Contents (14) Chapters

Preface Installing the Development System A Peek Inside the Kernel Working with Char Drivers Using the Device Tree Managing Interrupts and Concurrency Miscellaneous Kernel Internals Advanced Char Driver Operations Additional Information: Working with Char Drivers Additional Information: Using the Device Tree Additional Information: Managing Interrupts and Concurrency Additional Information: Miscellaneous Kernel Internals Additional Information: Advanced Char Driver Operations Other Books You May Enjoy

Doing native compiling on foreign hardware

Before ending this chapter, I'd like to introduce an interesting cross-platform system that's useful when we need several different OSes running on your development PC. This step is very useful when we need a complete OS to compile a device driver or an application but we do not have a target device to compile onto. We can use our host PC to compile code for a foreign hardware across different OS and OS release.

Getting ready

During my career, I worked with tons of different platforms and having one virtual machine for all of them is very complex and really system consuming (especially if we decide to run several of them at the same time!). That's why it can be interesting to have a lightweight system that can execute foreign code on your PC. Of course, this method cannot be used to test a device driver (we need real hardware for that), but we can use it to run a native compiler and/or native userspace code really quickly just in case our embedded platform is not working. Let's see what I'm talking about.

In the Setting up the target machine recipe, regarding the Debian OS installation, we used the chroot command to set up the root's password. This command worked thanks to QEMU; in fact, in the debian-stretch-arm64 directory, we have an ARM64 root filesystem, which can be executed on an x86_64 platform by using QEMU only. It's then clear that, in this manner, we should be able to execute whatever command we'd like and, of course, we will be able to execute the Bash shell as in the next recipe.

How to do it...

Now it's time to see how chroot works:

  1. Execute an ARM64 bash command by using our x86_64 host, as follows:
$ sudo chroot debian-stretch-arm64/ bash
bash: warning: setlocale: LC_ALL: cannot change locale (en_GB.UTF-8)
root@giometti-VirtualBox:/#
  1. Then, we can use each ARM64 command as we did on the ESPRESSObin; for example, to list files into the current directory; we can use the following:
# ls /
bin dev home media opt root sbin sys usr
boot etc lib mnt proc run srv tmp var
# cat /etc/hostname
espressobin

However, there are some traps; for instance, we completely miss the /proc and /sys directories and programs, which rely on them and will fail for sure:

# ls /{proc,sys}
/proc:

/sys:
# ps
Error: /proc must be mounted
To mount /proc at boot you need an /etc/fstab line like:
proc /proc proc defaults
In the meantime, run "mount proc /proc -t proc"

To resolve these problems, we can manually mount these missing directories before executing chroot, but this is quite annoying due to the fact that they are so many, so we can try using the schroot utility, which, in turn, can do all of these steps for us. Let's see how.

For detailed information regarding schroot, you can see its man pages with man schroot.

Installing and configuring schroot

This task is quite trivial in Ubuntu:

  1. First of all, we install the program in the usual way:
$ sudo apt install schroot
  1. Then, we have to configure it in order to correctly enter into our ARM64 system. To do so, let's copy the root filesystem created before into a dedicated directory (where we can also add any other distributions we wish to emulate with schroot):
$ sudo mkdir /srv/chroot/
$ sudo cp -a debian-stretch-arm64/ /srv/chroot/
  1. Then, we must create a proper configuration for our new system by adding a new file into the schroot configuration directory, as follows:
$ sudo bash -c 'cat > /etc/schroot/chroot.d/debian-stretch-arm64 <<__EOF__
[debian-stretch-arm64]
description=Debian Stretch (arm64)
directory=/srv/chroot/debian-stretch-arm64
users=giometti
#groups=sbuild
#root-groups=root
#aliases=unstable,default
type=directory
profile=desktop
personality=linux
preserve-environment=true
__EOF__'
Note that the directory parameter is set to the path holding our ARM64 system and users is set to giometti, which is my username (this is a comma-separated list of users that are allowed access to the chroot environment—see man schroot.conf).

Looking at the preceding settings, we see that the profile parameter is set to desktop; this means that it will be taking into account all files in the /etc/schroot/desktop/ directory. In particular, the fstab file holds all mount points we'd like to be mounted into our system. So, we should verify that it holds at least the following lines:

# <filesystem> <mount point> <type> <options> <dump> <pass>
/proc /proc none rw,bind 0 0
/sys /sys none rw,bind 0 0
/dev /dev none rw,bind 0 0
/dev/pts /dev/pts none rw,bind 0 0
/home /home none rw,bind 0 0
/tmp /tmp none rw,bind 0 0
/opt /opt none rw,bind 0 0
/srv /srv none rw,bind 0 0
tmpfs /dev/shm tmpfs defaults 0 0
  1. Now, we have to restart the schroot service, as follows:
$ sudo systemctl restart schroot
Note that you can also restart using the old-fashioned way:
$ sudo /etc/init.d/schroot restart
  1. Now we can list all available environments by asking them to schroot, as follows:
$ schroot -l
chroot:debian-stretch-arm64
  1. OK, everything is in place and we can enter into the emulated ARM64 system:
$ schroot -c debian-stretch-arm64
bash: warning: setlocale: LC_ALL: cannot change locale (en_GB.UTF-8)
Since we haven't installed any locale support, the preceding warning is quite obvious and it should be safely ignored.
  1. Now, to verify we're really executing ARM64 code, let's try some commands. For example, we can ask for some system information with the uname command:
$ uname -a
Linux giometti-VirtualBox 4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018 aarch64 GNU/Linux

As we can see, the system says that its platform is aarch64, which is ARM64. Then, we can try to execute our helloworld program that was cross-compiled before; since, after chroot, the current directory is not changed (and our home directory is still the same), we can simply go back where we did the compilation and then execute the program as usual:

$ cd ~/Projects/ldddc/github/chapter_1/
$ file helloworld
helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=c0d6e9ab89057e8f9101f51ad517a253e5fc4f10, not stripped
$ ./helloworld
Hello World!

The program still executes as when we were on an ARM64 system. Great!

Configuring the emulated OS

What we just saw about schroot is nothing if we do not configure our new system to do native compilation, and to do so, we can use every Debian tool we use on our host PC:

  1. To install a complete compiling environment, we can issue the following command once inside the schroot environment:
$ sudo apt install gcc make \
bison flex ncurses-dev libssl-dev
Note that sudo will ask your usual password, that is, the password you currently use to log in to your host PC.
You might not get a password request from sudo with the following error message:
sudo: no tty present and no askpass program specified
You can try executing the preceding sudo command again, adding to it the -S option argument.
It could be possible that the apt command will notify you that some packages cannot be authenticated. Just ignore this warning and continue installation, answering yes by pressing the Y key.

If everything works well, we should now be able to execute every compiling command we used before. For instance, we can try to recompile the helloworld program again but natively (we should remove the current executable in order; make will try to recompile it again):

$ rm helloworld
$ make CFLAGS="-Wall -O2" helloworld
cc -Wall -O2 helloworld.c -o helloworld
$ file helloworld
helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=1393450a08fb9eea22babfb9296ce848bb806c21, not stripped
$ ./helloworld
Hello World!
Note that networking support is fully functional so we're now working on an emulated ARM64 environment on our hosts PC as we were on the ESPRESSObin.

See also

You have been reading a chapter from
Linux Device Driver Development Cookbook
Published in: May 2019 Publisher: Packt ISBN-13: 9781838558802
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}