Skip to content

Commit 713284a

Browse files
committed
buildroot: remove all default guest packages to make image tiny
1 parent 14a544a commit 713284a

File tree

4 files changed

+91
-56
lines changed

4 files changed

+91
-56
lines changed

README.adoc

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ see this: https://askubuntu.com/questions/496549/error-you-must-put-some-source-
9898

9999
It does not work if you just download the `.zip` from GitHub because we use link:.gitmodules[Git submodules], you must clone this repo. `./configure` then fetches only the required submodules for you.
100100

101-
After QEMU opens up, you can start playing with the kernel modules:
101+
QEMU opens up and you can start playing with the kernel modules inside the simulated system:
102102

103103
....
104104
insmod /hello.ko
@@ -216,12 +216,18 @@ and then rebuild the kernel modules and re-run to see it take effect:
216216

217217
Congratulations, you are now officially a kernel module hacker!
218218

219-
We use `./build-buildroot` here because kernel modules go into the root filesystem, and it is Buildroot that generates our root filesystem. The kernel modules are inside a Buildroot package.
219+
We use `./build-buildroot` because the kernel modules go inside the root filesystem, and it is Buildroot that generates and updates our root filesystem. The kernel modules are link:packages/kernel_modules[inside a Buildroot package].
220220

221-
`--kernel-modules` is required even if files were modified as explained at: <<rebuild-buildroot-packages>>.
221+
`--kernel-modules` is required for the rebuild even though files were modified as explained at: <<rebuild-buildroot-packages>>.
222222

223223
The reboot after rebuild is annoying. We don't have a perfect solution for it yet, but there are some ideas cooking at: <<gem5-restore-new-script>>.
224224

225+
Using <<KVM>> can speed boot up however if your host and guest have the same arch, e.g. on an `x86_64` host:
226+
227+
....
228+
./run --kvm
229+
....
230+
225231
Not satisfied with kernel modules? OK then, let's hack up the <<linux-kernel-entry-point,entry point of the>> Linux kernel itself.
226232

227233
Open the file:
@@ -1405,7 +1411,11 @@ The number of cores is modified as explained at: <<number-of-cores>>
14051411
`taskset` from the util-linux package sets the initial core affinity of a program:
14061412

14071413
....
1408-
taskset -c 1,1 /sched_getaffinity.out
1414+
./build-buildroot \
1415+
--buildroot-config 'BR2_PACKAGE_UTIL_LINUX=y' \
1416+
--buildroot-config 'BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y' \
1417+
;
1418+
./run --eval-busybox 'taskset -c 1,1 /sched_getaffinity.out'
14091419
....
14101420

14111421
output:
@@ -1710,7 +1720,13 @@ But TODO I don't think you can see where you are in the kernel source code and l
17101720

17111721
Step debug userland processes to understand how they are talking to the kernel.
17121722

1713-
Guest:
1723+
First build `gdbserver` into the root filesystem:
1724+
1725+
....
1726+
./build-buildroot --buildroot-config 'BR2_PACKAGE_GDB=y'
1727+
....
1728+
1729+
Then on guest:
17141730

17151731
....
17161732
/gdbserver.sh /myinsmod.out /hello.ko
@@ -2341,10 +2357,17 @@ Files that contain device trees have the `.dtb` extension when compiled, and `.d
23412357

23422358
You can convert between those formats with:
23432359

2360+
....
2361+
"$(./getvar host_dir)"/bin/dtc -I dtb -O dts -o a.dts a.dtb
2362+
"$(./getvar host_dir)"/bin/dtc -I dts -O dtb -o a.dtb a.dts
2363+
....
2364+
2365+
Buildroot builds the tool due to `BR2_PACKAGE_HOST_DTC=y`.
2366+
2367+
On Ubuntu 18.04, the package is named:
2368+
23442369
....
23452370
sudo apt-get install device-tree-compiler
2346-
dtc -I dtb -O dts -o a.dts a.dtb
2347-
dtc -I dts -O dtb -o a.dtb a.dts
23482371
....
23492372

23502373
See also: https://stackoverflow.com/questions/14000736/tool-to-visualize-the-device-tree-file-dtb-used-by-the-linux-kernel/39931834#39931834
@@ -2405,13 +2428,25 @@ then `dtc a.dts` gives:
24052428
};
24062429
....
24072430

2408-
=== Get device tree from running kernel
2431+
=== Get device tree from a running kernel
24092432

24102433
https://unix.stackexchange.com/questions/265890/is-it-possible-to-get-the-information-for-a-device-tree-using-sys-of-a-running/330926#330926
24112434

24122435
This is specially interesting because QEMU and gem5 are capable of generating DTBs that match the selected machine depending on dynamic command line parameters for some types of machines.
24132436

2414-
QEMU's `-M virt` for example, which we use by default for `aarch64`, boots just fine without the `-dtb` option:
2437+
So observing the device tree from the guest allows to easily see what the emulator has generated.
2438+
2439+
Compile the `dtc` tool into the root filesystem:
2440+
2441+
....
2442+
./build-buildroot \
2443+
--arch aarch64 \
2444+
--buildroot-config 'BR2_PACKAGE_DTC=y' \
2445+
--buildroot-config 'BR2_PACKAGE_DTC_PROGRAMS=y' \
2446+
;
2447+
....
2448+
2449+
`-M virt` for example, which we use by default for `aarch64`, boots just fine without the `-dtb` option:
24152450

24162451
....
24172452
./run --arch aarch64
@@ -5514,6 +5549,14 @@ Each `enable` under the `events/` tree enables a certain set of functions, the h
55145549

55155550
TODO: can you get function arguments? https://stackoverflow.com/questions/27608752/does-ftrace-allow-capture-of-system-call-arguments-to-the-linux-kernel-or-only
55165551

5552+
===== trace-cmd
5553+
5554+
TODO example:
5555+
5556+
....
5557+
./build-buildroot --buildroot-config 'BR2_PACKAGE_TRACE_CMD=y'
5558+
....
5559+
55175560
==== Kprobes
55185561

55195562
kprobes is an instrumentation mechanism that injects arbitrary code at a given address in a trap instruction, much like GDB. Oh, the good old kernel. :-)
@@ -7843,7 +7886,13 @@ OK, this is why we used gem5 in the first place, performance measurements!
78437886

78447887
Let's see how many cycles https://en.wikipedia.org/wiki/Dhrystone[Dhrystone], which Buildroot provides, takes for a few different input parameters.
78457888

7846-
A flexible setup is demonstrated at:
7889+
First build Dhrystone into the root filesystem:
7890+
7891+
....
7892+
./build-buildroot --buildroot-config 'BR2_PACKAGE_DHRYSTONE=y'
7893+
....
7894+
7895+
Then, a flexible setup is demonstrated at:
78477896

78487897
....
78497898
./gem5-bench-dhrystone
@@ -9219,20 +9268,11 @@ First, see if you can't get away without actually adding a new package, for exam
92199268
* if you have a standalone C file with no dependencies besides the C standard library to be compiled with GCC, just add a new file under link:packages/kernel_modules/user[] and you are done
92209269
* if you have a dependency on a library, first check if Buildroot doesn't have a package for it already with `ls buildroot/package`. If yes, just enable that package as explained at: <<custom-buildroot-configs>>
92219270

9222-
If none of those methods are flexible enough for you, create a new package as follows:
9271+
If none of those methods are flexible enough for you, you can just fork or hack up link:packages/sample_package[] the sample package to do what you want.
92239272

9224-
* use link:packages/sample_package[] as a starting point
9225-
* fork this repository, and modify that package to do what you want
9226-
* read the comments on that package to get an idea of how to start
9227-
* check the main manual for more complicated things: https://buildroot.org/downloads/manual/manual.html
9228-
* don't forget to rebuild with:
9229-
+
9230-
....
9231-
./build-buildroot -- sample_package-reconfigure
9232-
./run --eval-busybox '/sample_package.out'
9233-
....
9234-
+
9235-
if you make any changes to that package after the initial build: <<rebuild-buildroot-packages>>
9273+
For how to use that package, see: <<packages-directory>>.
9274+
9275+
Then iterate trying to do what you want and reading the manual until it works: https://buildroot.org/downloads/manual/manual.html
92369276

92379277
=== BR2_TARGET_ROOTFS_EXT2_SIZE
92389278

@@ -9490,7 +9530,9 @@ xdg-open graph-size.pdf
94909530

94919531
Our philosophy is:
94929532

9493-
* keep the root filesystem as tiny as possible to make prebuilts small. It is easy to add new packages once you have the toolchain.
9533+
* keep the root filesystem as tiny as possible to make <<prebuilt>> small: only add BusyBox to have a small interactive system.
9534+
+
9535+
It is easy to add new packages once you have the toolchain, and if you don't there are infinitely many packages to cover and we can't cover them all.
94949536
* enable every feature possible on the toolchain (GCC, Binutils), because changes imply Buildroot rebuilds
94959537
* runtime is sacred. Faster systems are:
94969538
+
@@ -10041,10 +10083,20 @@ Every directory inside it is a Buildroot package.
1004110083
Those packages get automatically added to Buildroot's `BR2_EXTERNAL`, so all you need to do is to turn them on during build, e.g.:
1004210084

1004310085
....
10044-
./build-buildroot --buildroot-config BR2_SAMPLE_PACKAGE=y
10086+
./build-buildroot --buildroot-config 'BR2_SAMPLE_PACKAGE=y'
10087+
....
10088+
10089+
or force a rebuild after the first one with:
10090+
10091+
....
10092+
./build-buildroot --buildroot-config 'BR2_SAMPLE_PACKAGE=y' -- sample_package-reconfigure
1004510093
....
1004610094

10047-
If you want to add something to the root filesystem, possibly involving cross-compilation, then packages are the way to go.
10095+
then test it out with:
10096+
10097+
....
10098+
./run --eval-busybox '/sample_package.out'
10099+
....
1004810100

1004910101
In particular, our kernel modules are stored inside a Buildroot package: link:packages/kernel_modules[].
1005010102

build-buildroot

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ defaults = {
2222
'kernel_config_fragment': [],
2323
'kernel_custom_config_file': None,
2424
'kernel_modules': False,
25+
'no_kernel_modules': False,
2526
'linux_reconfigure': False,
2627
'no_all': False,
2728
'nproc': None,
@@ -33,6 +34,7 @@ defaults = {
3334
def get_argparse():
3435
parser = common.get_argparse(argparse_args={'description':'Run Linux on an emulator'})
3536
common.add_build_arguments(parser)
37+
kernel_module_group = parser.add_mutually_exclusive_group()
3638
parser.add_argument(
3739
'-B', '--buildroot-config', default=defaults['buildroot_config'], action='append',
3840
help='''Add a single Buildroot config to the current build.
@@ -79,9 +81,9 @@ Pass multiple times to use multiple fragment files.'''
7981
help='''Ignore all default kernel configurations and use this file instead.
8082
Still uses options explicitly passed with `-C` and `-c` on top of it.'''
8183
)
82-
parser.add_argument(
84+
kernel_module_group.add_argument(
8385
'-k', '--kernel-modules', default=defaults['kernel_modules'], action='store_true',
84-
help='Reconfigure and rebuild the kernel modules'
86+
help='Reconfigure and rebuild the kernel modules package'
8587
)
8688
parser.add_argument(
8789
'-l', '--linux-reconfigure', default=defaults['linux_reconfigure'], action='store_true',
@@ -94,6 +96,10 @@ https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-
9496
help='''Don't build the all target which normally gets build by default.
9597
That target builds the root filesystem and all its dependencies.'''
9698
)
99+
kernel_module_group.add_argument(
100+
'--no-kernel-modules', default=defaults['kernel_modules'], action='store_true',
101+
help="Don't build the kernel modules package"
102+
)
97103
parser.add_argument(
98104
'--skip-configure', default=defaults['skip_configure'], action='store_true',
99105
help='''Skip the Buildroot configuration. Saves a few seconds,
@@ -180,6 +186,8 @@ def main(args, extra_args=None):
180186
'BR2_ROOTFS_USERS_TABLES="{}"'.format(
181187
path_relative_to_buildroot(os.path.join(common.root_dir, 'user_table'))),
182188
])
189+
if not args.no_kernel_modules:
190+
buildroot_configs.append('BR2_PACKAGE_KERNEL_MODULES=y')
183191
if args.gem5:
184192
buildroot_configs.append('BR2_PACKAGE_GEM5=y')
185193
if args.initramfs:

buildroot_config/default

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,11 @@ BR2_PACKAGE_HOST_GDB_PYTHON=y
2929
BR2_PACKAGE_HOST_GDB_SIM=y
3030
BR2_PACKAGE_HOST_GDB_TUI=y
3131

32-
# Custom packages
33-
# Keepding those in because we control them fully
34-
# and know for sure that are small.
35-
BR2_PACKAGE_KERNEL_MODULES=y
36-
BR2_SAMPLE_PACKAGE=y
32+
# DTC.
33+
BR2_PACKAGE_HOST_DTC=y
3734

3835
# We were tempted to do this to disable S40network neatly,
3936
# but that package also creates extra configuration files
4037
# such as /etc/network/interfaces which we need. So we just
4138
# remove the init.d file for now.
4239
#BR2_PACKAGE_IFUPDOWN_SCRIPTS=n
43-
44-
# misc packages
45-
BR2_PACKAGE_DHRYSTONE=y
46-
BR2_PACKAGE_FILE=y
47-
BR2_PACKAGE_PCIUTILS=y
48-
BR2_PACKAGE_STRACE=y
49-
50-
# lscpu: TODO not installing?
51-
BR2_PACKAGE_UTIL_LINUX=y
52-
BR2_PACKAGE_UTIL_LINUX_BINARIES=y
53-
# taskset
54-
BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y
55-
56-
# gdbserver
57-
BR2_PACKAGE_GDB=y
58-
59-
# ftrace
60-
BR2_PACKAGE_TRACE_CMD=y
61-
62-
# DTC
63-
BR2_PACKAGE_DTC=y
64-
BR2_PACKAGE_DTC_PROGRAMS=y
65-
BR2_PACKAGE_HOST_DTC=y

release

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import subprocess
66
import common
77
zip_img = imp.load_source('zip_img', os.path.join(common.root_dir, 'zip-img'))
88

9+
subprocess.check_call([os.path.join(common.root_dir, 'test')])
910
subprocess.check_call([os.path.join(common.root_dir, 'build-all')])
1011
zip_img.main()
1112
tag = 'sha-{}'.format(common.sha)

0 commit comments

Comments
 (0)