/
kernel-compiling-and-nfs-booting.tex
231 lines (170 loc) · 7.58 KB
/
kernel-compiling-and-nfs-booting.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
\subchapter{Kernel compiling and booting}{Objective: compile and boot
a kernel for your board, booting on a directory on your workstation
shared by NFS.}
After this lab, you will be able to:
\begin{itemize}
\item Cross-compile the Linux kernel for the ARM platform.
\item Boot this kernel on an NFS root filesystem, which is somewhere
on your development workstation\footnote{NFS root filesystems are
particularly useful to compile modules on your host, and make them
directly visible on the target. You no longer have to update the root
filesystem by hand and transfer it to the target (requiring a shutdown
and reboot).}.
\end{itemize}
\section{Lab implementation}
While developing a kernel module, the developer wants to change the
source code, compile and test the new kernel module very
frequently. While writing and compiling the kernel module is done on the
development workstation, the test of the kernel module usually has to
be done on the target, since it might interact with hardware specific
to the target.
However, flashing the root filesystem on the target for every test is
time-consuming and would use the flash chip needlessly.
Fortunately, it is possible to set up networking between the
development workstation and the target. Then, workstation files can be
accessed through the network by the target, using NFS.
\begin{center}
\includegraphics[width=\textwidth]{labs/kernel-compiling-and-nfs-booting/host-vs-target.pdf}
\end{center}
\section{Setup}
Go to the \code{$HOME/linux-kernel-labs/src/linux} directory.
Install packages needed for configuring, compiling and booting
the kernel for your board:
\begin{verbatim}
sudo apt install libssl-dev bison flex
\end{verbatim}
\section{Cross-compiling toolchain setup}
We are going to install a cross-compiling toolchain provided by Ubuntu:
\begin{verbatim}
sudo apt install gcc-arm-linux-gnueabi
\end{verbatim}
Now find out the path and name of the cross-compiler executable by looking at the contents of the package:
\begin{verbatim}
dpkg -L gcc-arm-linux-gnueabi
\end{verbatim}
\section{Kernel configuration}
Configure your kernel sources with the ready-made configuration for boards in
the OMAP2 and later family which the AM335x found in the BeagleBone
belongs to. Don't forget to set the \code{ARCH} and
\code{CROSS_COMPILE} definitions for the \code{arm} platform and to
use your cross-compiler.
Add the below options to support networking over USB device:
\begin{itemize}
\item \kconfigval{CONFIG_USB_GADGET}{y}
\item \kconfigval{CONFIG_USB_MUSB_HDRC}{y} {\em Driver for the USB OTG
controller}
\item \kconfigval{CONFIG_USB_MUSB_GADGET}{y} {\em Use the USB OTG controller
in device (gadget) mode}
\item \kconfigval{CONFIG_USB_MUSB_DSPS}{y}
\item Check the dependencies of \kconfig{CONFIG_AM335X_PHY_USB}
and find the way to set \kconfigval{CONFIG_AM335X_PHY_USB}{y}
\item Find the "USB Gadget precomposed configurations" menu
and set it to {\em static} instead of {\em module}
so that \kconfigval{CONFIG_USB_ETH}{y}
\end{itemize}
Make sure that this configuration has \kconfigval{CONFIG_ROOT_NFS}{y} (support
booting on an NFS exported root directory).
\section{Kernel compiling}
Compile your kernel and generate the Device Tree Binaries (DTBs)
(running 4 compile jobs in parallel):
\begin{verbatim}
make -j 8
\end{verbatim}
Now, copy the \code{zImage} and \code{am335x-boneblack.dtb}
or \code{am335x-boneblack-wireless.dtb} files
to the TFTP server home directory (as specified in \code{/etc/default/tftpd-hpa}).
\section{Setting up the NFS server}
Install the NFS server by installing the \code{nfs-kernel-server}
package. Once installed, edit the \code{/etc/exports} file as
\code{root} to add the following lines, assuming that the IP address
of your board will be \code{192.168.0.100}:
\scriptsize
\begin{verbatim}
/home/<user>/linux-kernel-labs/modules/nfsroot 192.168.0.100(rw,no_root_squash,no_subtree_check)
\end{verbatim}
\normalsize
Of course, replace \code{<user>} by your actual user name.
Make sure that the path and the options are on the same line.
Also make sure that there is no space between the IP address and the NFS
options, otherwise default options will be used for this IP address,
causing your root filesystem to be read-only.
Then, restart the NFS server:
\begin{verbatim}
sudo /etc/init.d/nfs-kernel-server restart
\end{verbatim}
If there is any error message, this usually means that there was a
syntax error in the \code{/etc/exports} file. Don't proceed until these
errors disappear.
\section{Boot the system}
First, boot the board to the U-Boot prompt. Before booting the kernel,
we need to tell it which console to use and that the root filesystem
should be mounted over NFS, by setting some kernel parameters.
Do this by setting U-boot's \code{bootargs} environment variable (all in
just one line):
\begin{verbatim}
setenv bootargs root=/dev/nfs rw ip=192.168.0.100:::::usb0 console=ttyS0,115200n8
g_ether.dev_addr=f8:dc:7a:00:00:02 g_ether.host_addr=f8:dc:7a:00:00:01
nfsroot=192.168.0.1:/home/<user>/linux-kernel-labs/modules/nfsroot,nfsvers=3,tcp
\end{verbatim}
Once again, replace \code{<user>} by your actual user name.
Now save this definition:
\begin{verbatim}
saveenv
\end{verbatim}
If you later want to make changes to this setting, you can type the
below command in U-boot:
\begin{verbatim}
editenv bootargs
\end{verbatim}
Now, download the kernel image through \code{tftp}:
\begin{verbatim}
tftp 0x81000000 zImage
\end{verbatim}
You'll also need to download the device tree blob:
\begin{verbatim}
tftp 0x82000000 <board>.dtb
\end{verbatim}
Now, boot your kernel:
\begin{verbatim}
bootz 0x81000000 - 0x82000000
\end{verbatim}
If everything goes right, you should reach a login prompt (user:
\code{root}, no password). Otherwise, check your setup and
ask your instructor for support if you are stuck.
If the kernel fails to mount the NFS filesystem, look carefully at the
error messages in the console. If this doesn't give any clue, you can
also have a look at the NFS server logs in \code{/var/log/syslog}.
\section{Checking the kernel version}
It's often a good idea to make sure you booted the right kernel.
By mistake, you could have booted a kernel previously stored in flash
(typically through a default boot command in U-Boot), or forgotten to
update the kernel image in the TFTP server home directory.
This could explain some unexpected behavior.
There are two ways of checking your kernel version:
\begin{itemize}
\item By looking at the first kernel messages
\item By running the \code{uname -a} command after booting Linux.
\end{itemize}
In both cases, you will not only know the kernel version, but also
the date when the kernel was compiled and the name of the user who
did it.
Similarly, you can also check the command line actually received by
the kernel, either by looking at the first boot messages, or once you
have reached a command line shell, by running \code{cat /proc/cmdline}.
\section{Automate the boot process}
To avoid typing the same U-boot commands over and over again each time
you power on or reset your board, you can use U-Boot's \code{bootcmd}
environment variable:
{\scriptsize
\begin{verbatim}
setenv bootcmd 'tftp 0x81000000 zImage; tftp 0x82000000 <board>.dtb; bootz 0x81000000 - 0x82000000'
saveenv
\end{verbatim}
}
Don't hesitate to change it according to your exact needs.
We could also copy the \code{zImage} file to the eMMC flash and avoid
downloading it over and over again. However, detailed bootloader
usage is outside of the scope of this course. See our
\href{https://bootlin.com/training/embedded-linux/}{Embedded
Linux system development course} and its on-line materials for
details.