Skip to content

Commit a068722

Browse files
committed
the docker setup is perfect
1 parent 403d4a9 commit a068722

File tree

6 files changed

+131
-104
lines changed

6 files changed

+131
-104
lines changed

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ignore everything, since we get the repository files
2+
# with a volume.
3+
*
4+
.*

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# https://github.com/cirosantilli/linux-kernel-module-cheat#docker
2+
FROM ubuntu:18.04
3+
RUN apt update
4+
# Minimum requirements to run ./build --download-dependencies
5+
RUN apt-get install -y \
6+
git \
7+
python3 \
8+
python3-distutils \
9+
;
10+
CMD bash

README.adoc

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,9 @@ This is a good option if you are on a Linux host, but the native setup failed du
392392
For example, to do a <<qemu-buildroot-setup>> inside Docker, run:
393393

394394
....
395-
sudo apt-get install docker && \
395+
sudo apt-get install docker
396396
./run-docker create && \
397-
./run-docker start && \
398-
./run-docker sh ./build --download-dependencies && \
397+
./run-docker sh -- ./build --download-dependencies
399398
./run-docker sh
400399
....
401400

@@ -405,50 +404,63 @@ You are now left inside a shell in the Docker! From there, just run as usual:
405404
./run
406405
....
407406

407+
The host git top level directory is mounted inside the guest with a link:https://stackoverflow.com/questions/23439126/how-to-mount-a-host-directory-in-a-docker-container[Docker volume], which means for example that you can use your host's GUI text editor directly on the files. Just don't forget that if you nuke that directory on the guest, then it gets nuked on the host as well!
408+
408409
Command breakdown:
409410

410-
* `./run-docker create`: create the container.
411+
* `./run-docker create`: create the image and container.
411412
+
412413
Needed only the very first time you use Docker, or if you run `./run-docker DESTROY` to restart for scratch, or save some disk space.
413414
+
414-
The container name is `lkmc` and shows up in the list of all containers:
415+
The image and container name is `lkmc`. The container shows under:
415416
+
416417
....
417418
docker ps -a
418419
....
419-
* `./run-docker start`: start the container as daemon on the background.
420420
+
421-
Needed only after reboot, or if you run `./run-docker stop` to save CPU or memory resources.
421+
and the image shows under:
422422
+
423-
The container can now be seen on the list of running containers:
423+
....
424+
docker images
425+
....
426+
* `./run-docker sh`: open a shell on the container.
427+
+
428+
If it has not been started previously, start it. This can also be done explicitly with:
424429
+
425430
....
426-
docker ps
431+
./run-docker start
427432
....
428-
* `./run-docker sh`: open a shell on a previously started Docker daemon.
429433
+
430434
Quit the shell as usual with `Ctrl-D`
431435
+
432-
Can be called multiple times from different host terminals to open multiple shells.
433-
434-
The host git top level directory is mounted inside the guest with a link:https://stackoverflow.com/questions/23439126/how-to-mount-a-host-directory-in-a-docker-container[Docker volume], which means for example that you can use your host's GUI text editor directly on the files. Just don't forget that if you nuke that directory on the guest, then it gets nuked on the host as well!
436+
This can be called multiple times from different host terminals to open multiple shells.
437+
* `./run-docker stop`: stop the container.
438+
+
439+
This might save a bit of CPU and RAM once you stop working on this project, but it should not be a lot.
440+
* `./run-docker DESTROY`: delete the container and image.
441+
+
442+
This doesn't really clean the build, since we mount the guest's working directory on the host git top-level, so you basically just got rid of the `apt-get` installs.
443+
+
444+
To actually delete the Docker build, run on host:
445+
+
446+
....
447+
# sudo rm -rf out.docker
448+
....
435449

436-
In order to use functionality such as <<gdb>> from inside Docker, you need a second shell inside the container. You can either do that from another shell with:
450+
To use <<gdb>> from inside Docker, you need a second shell inside the container. You can either do that from another shell with:
437451

438452
....
439453
./run-docker sh
440454
....
441455

442456
or even better, by starting a <<tmux>> session inside the container. We install `tmux` by default in the container.
443457

444-
You can start a second shell and run a command in it at the same time with:
458+
You can also start a second shell and run a command in it at the same time with:
445459

446460
....
447-
./run-docker sh ./run-gdb start_kernel
461+
./run-docker sh -- ./run-gdb start_kernel
448462
....
449463

450-
Docker stops if and only if you quit the initial shell, you can quit this one without consequences.
451-
452464
To use <<qemu-graphic-mode>> from Docker, run:
453465

454466
....
@@ -462,21 +474,11 @@ sudo apt-get install vinagre
462474
./vnc
463475
....
464476

465-
When you do:
466-
467-
....
468-
./run-docker DESTROY
469-
....
470-
471-
you don't really destroy the build, since we mount the guest's working directory on the host git top-level, so you basically just get rid of the `apt-get` installs.
472-
473-
To actually delete the Docker build, run:
474-
475-
....
476-
# sudo rm -rf out.docker
477-
....
477+
TODO make files created inside Docker be owned by the current user in host instead of `root`:
478478

479-
TODO make files created inside Docker be owned by the current user in host instead of `root`: https://stackoverflow.com/questions/23544282/what-is-the-best-way-to-manage-permissions-for-docker-shared-volumes
479+
* https://stackoverflow.com/questions/33681396/how-do-i-write-to-a-volume-container-as-non-root-in-docker
480+
* https://stackoverflow.com/questions/23544282/what-is-the-best-way-to-manage-permissions-for-docker-shared-volumes
481+
* https://stackoverflow.com/questions/31779802/shared-volume-file-permissions-ownership-docker
480482

481483
[[prebuilt]]
482484
=== Prebuilt Buildroot setup
@@ -717,8 +719,8 @@ Our C bare-metal compiler is built with link:https://github.com/crosstool-ng/cro
717719
QEMU:
718720

719721
....
720-
./build --arch arm --download-dependencies qemu-baremetal
721-
./run --arch arm --baremetal interactive/prompt
722+
./build --arch aarch64 --download-dependencies qemu-baremetal
723+
./run --arch aarch64 --baremetal interactive/prompt
722724
....
723725

724726
You are now left inside QEMU running the tiny baremetal system link:baremetal/interactive/prompt.c[], which uses the UART to:
@@ -749,41 +751,41 @@ vim baremetal/interactive/prompt.c
749751
and run:
750752

751753
....
752-
./build-baremetal --arch arm
754+
./build-baremetal --arch aarch64
753755
....
754756

755757
`./build qemu-baremetal` had called link:build-baremetal[] for us previously, in addition to its requirements. `./build-baremetal` uses crosstool-NG, and so it must be preceded by link:build-crosstool-ng[], which `./build qemu-baremetal` also calls.
756758

757759
Every `.c` file inside link:baremetal/[] and `.S` file inside `baremetal/arch/<arch>/` generates a separate baremetal image. You can run a different image with commands such as:
758760

759761
....
760-
./run --arch arm --baremetal exit
761-
./run --arch arm --baremetal arch/arm/add
762+
./run --arch aarch64 --baremetal exit
763+
./run --arch aarch64 --baremetal arch/aarch64/add
762764
....
763765

764766
which will run respectively:
765767

766768
* link:baremetal/exit.c[]
767-
* link:baremetal/arch/arm/add.S[]
769+
* link:baremetal/arch/aarch64/add.S[]
768770

769771
Alternatively, for the sake of tab completion, we also accept relative paths inside `baremetal/`:
770772

771773
....
772-
./run --arch arm --baremetal baremetal/exit.c
773-
./run --arch arm --baremetal baremetal/arch/arm/add.S
774+
./run --arch aarch64 --baremetal baremetal/exit.c
775+
./run --arch aarch64 --baremetal baremetal/arch/aarch64/add.S
774776
....
775777

776778
Absolute paths however are used as is and must point to the actual executable:
777779

778780
....
779-
./run --arch arm --baremetal "$(./getvar --arch arm baremetal_build_dir)/exit.elf"
781+
./run --arch aarch64 --baremetal "$(./getvar --arch aarch64 baremetal_build_dir)/exit.elf"
780782
....
781783

782784
To use gem5 instead of QEMU do:
783785

784786
....
785787
./build --download-dependencies gem5-baremetal
786-
./run --arch arm --baremetal interactive/prompt --gem5
788+
./run --arch aarch64 --baremetal interactive/prompt --gem5
787789
....
788790

789791
and then <<qemu-buildroot-setup,as usual>> open a shell with:
@@ -813,15 +815,15 @@ The reason for that is that on baremetal we don't parse the <<device-tree,device
813815
`gem5` also supports the `RealViewPBX` machine, which represents an older hardware compared to the default `VExpress_GEM5_V1`:
814816

815817
....
816-
./build-baremetal --arch arm --gem5 --machine RealViewPBX
817-
./run --arch arm --baremetal interactive/prompt --gem5 --machine RealViewPBX
818+
./build-baremetal --arch aarch64 --gem5 --machine RealViewPBX
819+
./run --arch aarch64 --baremetal interactive/prompt --gem5 --machine RealViewPBX
818820
....
819821

820822
This generates yet new separate images with new magic constants:
821823

822824
....
823-
echo "$(./getvar --arch arm --baremetal interactive/prompt --gem5 --machine VExpress_GEM5_V1 image)"
824-
echo "$(./getvar --arch arm --baremetal interactive/prompt --gem5 --machine RealViewPBX image)"
825+
echo "$(./getvar --arch aarch64 --baremetal interactive/prompt --gem5 --machine VExpress_GEM5_V1 image)"
826+
echo "$(./getvar --arch aarch64 --baremetal interactive/prompt --gem5 --machine RealViewPBX image)"
825827
....
826828

827829
But just stick to newer and better `VExpress_GEM5_V1` unless you have a good reason to use `RealViewPBX`.

build

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ def run_cmd(cmd, arch):
5757
buildroot_component = Component(
5858
lambda arch: run_cmd(['build-buildroot'], arch),
5959
submodules = {'buildroot'},
60+
# https://buildroot.org/downloads/manual/manual.html#requirement
61+
apt_get_pkgs={
62+
'bash',
63+
'bc',
64+
'binutils',
65+
'build-essential',
66+
'bzip2',
67+
'cpio',
68+
'g++',
69+
'gcc',
70+
'graphviz',
71+
'gzip',
72+
'make',
73+
'patch',
74+
'perl',
75+
'python-matplotlib',
76+
'python3',
77+
'rsync',
78+
'sed',
79+
'tar',
80+
'unzip',
81+
},
6082
)
6183

6284
name_to_component_map = {
@@ -86,6 +108,7 @@ name_to_component_map = {
86108
'bison',
87109
'docbook2x',
88110
'flex',
111+
'gawk',
89112
'gcc',
90113
'gperf',
91114
'help2man',
@@ -124,6 +147,13 @@ name_to_component_map = {
124147
'linux': Component(
125148
lambda arch: run_cmd(['build-linux'], arch),
126149
submodules_shallow={'linux'},
150+
apt_get_pkgs={
151+
'bison',
152+
'flex',
153+
# Without this started failing in kernel 4.15 with:
154+
# Makefile:932: *** "Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel". Stop.
155+
'libelf-dev',
156+
},
127157
),
128158
'modules': Component(
129159
lambda arch: run_cmd(['build-modules'], arch),
@@ -317,29 +347,13 @@ for component_name in components:
317347

318348
if args.download_dependencies:
319349
apt_get_pkgs = {
320-
# TODO: figure out what needs those exactly.
321-
'automake',
322-
'build-essential',
323-
'coreutils',
324-
'cpio',
325-
'libguestfs-tools',
326-
'moreutils', # ts
327-
'rsync',
328-
'unzip',
329-
'wget',
330-
331-
# Linux kernel build dependencies.
332-
'bison',
333-
'flex',
334-
# Without this started failing in kernel 4.15 with:
335-
# Makefile:932: *** "Cannot generate ORC metadata for CONFIG_UNWINDER_ORC=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel". Stop.
336-
'libelf-dev',
337-
338-
# Our misc stuff.
350+
# Core requirements for this repo.
339351
'git',
352+
'moreutils', # ts
340353
'python3-pip',
341354
'tmux',
342355
'vinagre',
356+
'wget',
343357

344358
# Userland.
345359
'gcc-aarch64-linux-gnu',

run

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ Pass an extra Linux kernel command line options, add a dash `-`
463463
separator, and place the options after the dash. Intended for custom
464464
options understood by our `init` scripts, most of which are prefixed
465465
by `lkmc_`.
466-
Example: `./run -f 'lkmc_eval="wget google.com" lkmc_lala=y'`
466+
Example: `./run --kernel-cli-after-dash 'lkmc_eval="wget google.com" lkmc_lala=y'`
467467
Mnenomic: `-f` comes after `-e`.
468468
'''
469469
)

run-docker

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,53 +10,50 @@ container_hostname = common.repo_short_id
1010
image_name = common.repo_short_id
1111
target_dir = '/root/{}'.format(common.repo_short_id)
1212
docker = ['sudo', 'docker']
13+
def create(args):
14+
common.run_cmd(docker + ['build', '-t', image_name, '.', common.Newline])
15+
# --privileged for KVM:
16+
# https://stackoverflow.com/questions/48422001/launching-qemu-kvm-from-inside-docker-container
17+
common.run_cmd(
18+
docker +
19+
[
20+
'create', common.Newline,
21+
'--hostname', container_hostname, common.Newline,
22+
'-i', common.Newline,
23+
'--name', container_name, common.Newline,
24+
'--net', 'host', common.Newline,
25+
'--privileged', common.Newline,
26+
'-t', common.Newline,
27+
'-w', target_dir, common.Newline,
28+
'-v', '{}:{}'.format(os.getcwd(), target_dir), common.Newline,
29+
image_name,
30+
]
31+
)
32+
def destroy(args):
33+
stop(args)
34+
common.run_cmd(docker + ['rm', container_name, common.Newline])
35+
common.run_cmd(docker + ['rmi', image_name, common.Newline])
1336
def sh(args):
37+
start(args)
1438
if args:
15-
sh_args = ['-c'] + args
39+
sh_args = args
1640
else:
17-
sh_args = []
41+
sh_args = ['bash']
1842
common.run_cmd(
19-
docker +
20-
[
21-
'exec',
22-
'-i',
23-
'-t',
24-
container_name,
25-
'bash',
26-
] +
43+
docker + ['exec', '-i', '-t', container_name] +
2744
sh_args +
2845
[common.Newline],
2946
)
47+
def start(args):
48+
common.run_cmd(docker + ['start', container_name, common.Newline])
49+
def stop(args):
50+
common.run_cmd(docker + ['stop', container_name, common.Newline])
3051
cmd_action_map = {
31-
'create': lambda args:
32-
# --privileged for KVM:
33-
# https://stackoverflow.com/questions/48422001/launching-qemu-kvm-from-inside-docker-container
34-
common.run_cmd(
35-
docker +
36-
[
37-
'create', common.Newline,
38-
'--hostname', container_hostname, common.Newline,
39-
'-i', common.Newline,
40-
'--name', container_name, common.Newline,
41-
'--net', 'host', common.Newline,
42-
'--privileged', common.Newline,
43-
'-t', common.Newline,
44-
'-w', target_dir, common.Newline,
45-
'-v', '{}:{}'.format(os.getcwd(), target_dir), common.Newline,
46-
'ubuntu:18.04', common.Newline,
47-
'bash', common.Newline,
48-
]
49-
),
50-
'start': lambda args:
51-
common.run_cmd(docker + [ 'start', container_name, common.Newline])
52-
,
53-
'stop': lambda args:
54-
common.run_cmd(docker + ['stop', container_name, common.Newline])
55-
,
52+
'create': lambda args: create(args),
53+
'DESTROY': lambda args: destroy(args),
5654
'sh': lambda args: sh(args),
57-
'DESTROY': lambda args:
58-
common.run_cmd(docker + [ 'rm', container_name, common.Newline])
59-
,
55+
'start': lambda args: start(args),
56+
'stop': lambda args: stop(args),
6057
}
6158
parser = argparse.ArgumentParser()
6259
parser.add_argument('cmd', choices=cmd_action_map)

0 commit comments

Comments
 (0)