This article is the 8th day of Linux Advent Calendar 2019 --Qiita.
In this article, I will show you how to check what kind of kernel your Linux Kernel is and what settings it is running on. The Linux Kernel is used for various purposes. Therefore, even if you say Linux Kernel in a nutshell, the operation is completely different depending on the system. We hope that knowing how to understand the current situation will help you to efficiently read the kernel code and find better settings.
Also, comments are welcome, so please feel free to contact us if you have any questions.
--What to write in this article --How to check the identity of the Linux Kernel --How to check the Linux Kernel settings
--What not to write in this article
--Settings for each process, each user, etc. (ʻulimit,
nice,
quotal, etc.) --User space settings (such as
sysconf and
pathconf`)
--Settings for the driver (parameters at the time of insmod, etc.)
--Explanation of each setting item
The following 6 items are introduced. Each item is independent, so please see from where you are interested.
Kernel Version
First, let's see which version of the kernel is used. By knowing the version, you can use it as a basis for investigating whether a specific function or modification is included.
You can get the running Kernel Version by running the ʻuname -r` command. Below are the results when using a plain Linux Kernel 5.3.10.
$ uname -r
5.3.10
Depending on your environment, running ʻuname -r` may have a lot of sticking behind the three numbers above. For example, the following is the execution result on Ubuntu 19.10.
$ uname -r
5.3.0-19-generic
In this case, it is a kernel modified for Ubuntu 19.10 based on the version 5.3.0
Linux kernel.
What kind of corrections have been made should be published somewhere.
For Ubuntu, source code package and diff /primary/+sourcefiles/linux/5.3.0-19.20/linux_5.3.0-19.20.diff.gz) is distributed.
The meaning of the string (19-generic
) after version is different for each distribution.
For Ubuntu, it is explained in here.
There are many other ways to check the version, and there is a detailed article in here, so please take a look. Also, the contents of the ʻuname` command are explained in detail in Linux Advent Calendar 2019 Day 1. Please take a look there as well.
CPU Architecture
Next, let's check which CPU the kernel was built for.
In the context of the Linux Kernel, "which CPU is for" is often expressed as Architecture or arch.
Architecture is used in many ways, but here it is the ISA (Instruction Set Architecture) of the CPU.
For example, x86_64
and ʻarm`.
There may not be many cases where you do not know the CPU Architecture when you are aware of the Kernel. However, in fact, there are times when a kernel for Architecture is working. Let's check it just in case.
or ʻarch
Commands for checking the CPU Architecture include ʻuname -m and ʻarch
.
Both of the two commands are provided in a package called coreutils
, and the implementation is common, so you can use whichever you like.
For PC (Ubuntu 18.04), it should be displayed as x86_64
.
$ uname -m
x86_64
When I try it on Raspberry Pi 3 Model B + (Raspbian), it says ʻarmv7l`.
$ uname -m
armv7l
In fact, the Raspberry Pi 3 Model B + is equipped with a 64-bit ARM CPU called Cortex-A53. If so, I think that the kernel for 64bit is working, but in that case it should be displayed as ʻaarch64`. In other words, in Raspbian, the kernel built for 32bit is running in 32bit compatibility mode. (I guess, probably because it is shared with 32-bit CPU models such as RasPi 2 and RasPi zero)
Now that I have confirmed the CPU Architecture, the processing of the CPU Architecture I am using this time Let's see where it is located in the Kernel source code.
Looking at the Kernel source code, under the ʻarch / `directory You can see that there is a directory for each CPU Architecture.
$ ls -F arch/
Kconfig arm/ csky/ ia64/ mips/ openrisc/ riscv/ sparc/ x86/
alpha/ arm64/ h8300/ m68k/ nds32/ parisc/ s390/ um/ xtensa/
arc/ c6x/ hexagon/ microblaze/ nios2/ powerpc/ sh/ unicore32/
The directory name is a slight replacement of the result of the ʻuname -mcommand introduced earlier. The replacement is done in a Makefile called
scripts / subarch.include. For example, when building a kernel for
x86_64, the
x86 / directory is used. Similarly, for Raspbian's ʻarmv7l
, the ʻarm /` directory is used.
scripts/subarch.include
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-e s/riscv.*/riscv/)
Kernel Build Config
Next is Kernel Build Config.
Depending on the person, it may be more appropriate to say a compile switch or # ifdef
.
When we simply say Kernel Config, we often refer to this.
As mentioned earlier, the Linux kernel is used for a wide range of purposes, but if you create a universal kernel that can do anything, the image size will grow unnecessarily. Therefore, we save size by excluding unused features from compilation.
Since the debug function is often turned off / on with the kernel build config, you can also know what kind of debug function can be used.
/boot/config-X.Y.Z
Depending on the Linux distribution, it is left under / boot
with the kernel image.
For example, in Ubuntu 19.10, it is stored in a file called /boot/config-5.3.0-19-generic
.
There are equivalent files on CentOS 8 and Debian 10.
$ head /boot/config-$(uname -r)
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 5.3.0-19-generic Kernel Configuration
#
#
# Compiler: gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
#
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=90201
/proc/config.gz
For kernels with CONFIG_IKCONFIG_PROC
enabled
You can check the Kernel Build Config in /proc/config.gz
.
Unfortunately, there is not much usable environment. However, it is a more reliable confirmation method because it will be taught by the running kernel. Let's use it positively in an environment where it can be used.
For example, the Linux Kernel used on Android often works with this method.
The following is the result when confirmed with the Android 10 Emulator.
(Note that you are using the zcat
command as it is gzipped)
The /proc/config.gz
was also enabled on the Samsung Galaxy Note8 (Android 9).
$ zcat /proc/config.gz | head
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 4.14.112 Kernel Configuration
#
CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
It is defined in a file called Kconfig
included in the Kernel source code.
Dependencies and explanations of each item are also described there.
Also, if you execute make xconfig
, you can see the list while looking at the explanation of each setting item, so it is recommended.
You can also search with Ctrl-f
.
Here are just a few of the most frequently used items.
CONFIG_IKCONFIG_PROC
Allows you to get the Kernel Build Config via /proc/config.gz
.
It is easy to understand if you enable Kernel Build Config first when you play around with it.
CONFIG_DEBUG_INFO
It will now generate a kernel image with debug symbols.
Required when doing Kernel debugging using gdb
.
CONFIG_FTRACE
Enables a function called Ftrace for analyzing the behavior of the Kernel.
Introducing Ftrace to Linux-Qiita explains in detail.
CONFIG_KPROBE
Enable Kprobe, a mechanism for applying binary patches to a running Kernel.
You also need it to use SystemTap, a tool that makes Kprobe a little easier to use.
To change the Kernel Build Config, you need to rebuild the Kernel.
The general change method is to edit the current .config
obtained by the above method with make menuconfig
or make xconfig
and rebuild the Kernel.
However, .config
is a build-generated file and should be excluded from source code control.
Once you have created the desired .config
with make menuconfig
, commit the defconfig
output with make saved efconfig
.
make savedefconfig
will output the minimum config to regenerate the current .config
.
For example, if you commit defconfig
to ʻarch / x86 / configs / mytest_defconfig, then you can use
make mytest_defconfigto generate the edited
.config` for all development members. I can do it.
$ make savedefconfig
$ mv defconfig arch/x86/configs/mytest_defconfig
$ mv .config .config.back
$ make mytest_defconfig
#
# configuration written to .config
#
$ diff .config .config.back
Command-line Parameters
Next, I will introduce Command-line Parameters. Command-line Parameters are options specified as arguments when starting the Kernel. Therefore, it is generally specified by the bootloader.
The Kernel Version, CPU architecture, and Kernel Build Config introduced so far were all decided at the time of kernel compilation. On the other hand, what we will introduce from here is a mechanism to change the operation without changing the Kernel itself.
/ proc / cmdline
You can check the Command-line Parameters in / proc / cmdline
.
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.3.7+ root=UUID=71b4dc0a-e498-41f4-9cd2-a81e8c03cda8 ro quiet splash vt.handoff=1
dmesg
Since it is also output to dmesg
, you can check it even if only the log remains.
$ dmesg | grep "Kernel command line"
[ 0.104775] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-5.3.7+ root=UUID=71b4dc0a-e498-41f4-9cd2-a81e8c03cda8 ro quiet splash vt.handoff=1
There is Documentation for the setting items of Command-line Parameters.
Although it is a very small part, I will introduce some for reference. There are many others, so be sure to read the documentation as well.
loglevel
You can change the level of kernel log output to the console.
It is often changed at the time of defect analysis immediately after startup.
log_buf_len
You can change the ring buffer size of the kernel log.
When the log flows, you can see the log by increasing the size.
The default value can be changed with CONFIG_LOG_CPU_MAX_BUF_SHIFT
, but if you want to increase it temporarily, use this.
mem
You can specify the memory size used by the kernel.
Use this when simulating a low memory situation or when the memory map is suspicious.
ftrace
The function called Ftrace for analyzing the operation of the Kernel is enabled immediately after startup.
It is used to analyze the behavior of the kernel immediately after startup.
sysctl
The following sysctl
is a mechanism to change the Kernel Parameter during execution.
You can change it at any time, not just at startup like Command-line parameters.
sysctl
You can check the current values of all parameters by running sysctl -a
.
You need root privileges to see some parameters.
$ sudo sysctl -a | head
abi.vsyscall32 = 1
debug.exception-trace = 1
debug.kprobes-optimization = 1
dev.cdrom.autoclose = 1
dev.cdrom.autoeject = 0
dev.cdrom.check_media = 0
dev.cdrom.debug = 0
dev.cdrom.info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17
dev.cdrom.info =
dev.cdrom.info = drive name:
/ proc / sys /
All parameters that can be set with sysctl
are published as files under / proc / sys
.
You can check the paramter value by reading this file, and you can change it by writing.
In fact, the sysctl
command is also internally checked and changed via / proc / sys
.
$ find /proc/sys -type f | head | xargs -I@ sh -c 'echo "@ = $(cat @ | head -1)"'
/proc/sys/abi/vsyscall32 = 1
/proc/sys/debug/exception-trace = 1
/proc/sys/debug/kprobes-optimization = 1
/proc/sys/dev/cdrom/autoclose = 1
/proc/sys/dev/cdrom/autoeject = 0
/proc/sys/dev/cdrom/check_media = 0
/proc/sys/dev/cdrom/debug = 0
/proc/sys/dev/cdrom/info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17
/proc/sys/dev/cdrom/lock = 1
/proc/sys/dev/hpet/max-user-freq = 64
If you want to know in advance whether it is a parameter that can be changed or if you need root privileges,
You can check it by looking at the permissions of the files under / proc / sys
.
Looking at the following, fs.file-max
is writable,
You can see that fs.file-nr
is not writable.
You can also see that you need root privileges to modify fs.file-max
.
$ ls -l /proc/sys/fs/file-*
-rw-r--r--1 root root 0 December 6 14:01 /proc/sys/fs/file-max
-r--r--r--1 root root 0 December 6 14:01 /proc/sys/fs/file-nr
There is also a Documentation for items that can be set with sysctl
.
This is also a very small part, but I will introduce what kind of items there are for reference.
fs.file-max
You can check and change the number of files that can be opened on the entire system.
fs.file-nr
You can see how many files are currently open and how many files can be opened system-wide.
As mentioned earlier, it is read-only.
For example, if it was 15840 0 3231322
,
The number of files currently open is 15840
, and the number of files that can be opened system-wide is 3231322
.
The 0
in the middle is always 0, only left for compatibility, so don't worry.
It is used to check if fd leak has occurred as a system.
fs.nr_open
The number of files that can be opened per process.
However, in reality, it is often more stringent with the ʻulimit set for each process. The limits set by ʻulimit
can be found in / proc / $ {PID} / limits
.
kernel.print-fatal-signals
Setting this value to 1 leaves the process name and register value in the kernel log when the process terminates abnormally.
kernel.core_pattern
You can set how to leave a Coredump when a process terminates abnormally.
In addition to renaming Coredump files, you can also redirect to a specific program.
Linux Effective Coredump --Qiita explains in detail.
vm.drop_caches
Frees the kernel cache when you write a value.
The only change in this item is that the read value has no meaning and the process runs when it is written.
Following the movement when writing to Linux drop_caches --Qiita explains in detail.
The file permissions for this item are read-write, but it should really be write-only.
Basically, the sysctl
settings are only saved in the kernel's global variables and will be forgotten when the system is rebooted.
The mechanism for setting it persistently depends on the distribution, but many distributions load /etc/sysctl.conf
as the default value at startup.
This is achieved by running sysctl --system
from the init script at system startup.
For Android, write to / proc / sys
directly from the initrc script that describes the startup process.
/init.rc
on early-init
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
sysctl
Device Tree
Finally, let's check the Device Tree.
Device Tree is hardware configuration information. It is often used in embedded systems that use ARM CPUs.
In embedded systems, the memory address and interrupt number of the device differ from system to system.
Embedding them in the device driver source code makes them hard to read and maintain.
Therefore, it is common to write these hardware configuration information in a Device Tree Source (.dts
file) that is independent of the source code.
If you look at the ranking of the number of .dts
files by arch in 5.3.10
, arm is by far the best.
Next is powerpc.
It seems that Device Tree was originally developed for powerpc, so that's probably why.
$ find arch/ -name *.dts | cut -d '/' -f 2 | uniq -c | sort -n -r
1176 arm
265 arm64
200 powerpc
50 mips
17 arc
7 xtensa
5 c6x
3 h8300
2 openrisc
2 nios2
1 x86
1 sh
1 riscv
1 nds32
1 microblaze
Then, what is happening in the PC world? It seems that UEFI BIOS receives hardware information according to the ACPI standard, but I'm not sure. sorry.
/ sys / firmware / fdt
For systems that use Device Tree
There is a Device Tree converted to FDT format in / sys / firmware / fdt
.
FDT is an abbreviation for Flattend Device Tree and is also called DTB (Device Tree Blob).
You can convert FDT to a .dts
file with the command dtc
(Device Tree Compiler).
For embedded systems, it is also possible to transfer / sys / firmware / fdt
to a PC and then convert it to .dts
on the PC.
Under / proc / device-tree
, there is also a Device Tree expanded to the file system, but I think / sys / firmware / fdt
is more convenient because it is easier to handle.
The following is the confirmation result of Device Tree on Raspberry Pi 3 ModelB + (Raspbian).
$ sudo dtc /sys/firmware/fdt 2> /dev/null | head
/dts-v1/;
/memreserve/ 0x0000000000000000 0x0000000000001000;
/ {
memreserve = < 0x3b400000 0x4c00000 >;
serial-number = "00000000c97f6276";
compatible = "raspberrypi,3-model-b\0brcm,bcm2837";
model = "Raspberry Pi 3 Model B Rev 1.2";
interrupt-parent = < 0x01 >;
#address-cells = < 0x01 >;
The Device Tree specifications are available here [https://www.devicetree.org/specifications/).
However, what the actual settings written in the Device Tree mean depends largely on the target hardware specifications and device driver specifications. There are quite a few cases where it is used unexpectedly, so when you look at the Device Tree, check the implementation that uses that value as much as possible.
Thank you for reading to the end.
The settings can directly change the behavior of the Kernel, so I think it is a very good starting point for Kernel code reading.
You can find the related implementation as soon as you grep
with the setting item name, and above all, it is easy to change the setting value and see the operation.
I would be very happy if this article was helpful to anyone.
Recommended Posts