mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 11:11:35 +01:00
This commit is contained in:
417
index.html
417
index.html
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Asciidoctor 2.0.11">
|
||||
<meta name="description" content="The perfect emulation setup to study and develop the <<linux-kernel>> v5.9.2, kernel modules, <<qemu-buildroot-setup,QEMU>>, <<gem5-buildroot-setup,gem5>> and x86_64, ARMv7 and ARMv8 <<userland-assembly,userland>> and <<baremetal-setup,baremetal>> assembly, <<c,ANSI C>>, <<cpp,C++>> and <<posix,POSIX>>. <<gdb>> and <<kgdb>> just work. Powered by <<about-the-qemu-buildroot-setup,Buildroot>> and <<about-the-baremetal-setup,crosstool-NG>>. Highly automated. Thoroughly documented. Automated <<test-this-repo,tests>>. "Tested" in an Ubuntu 20.04 host.">
|
||||
<meta name="description" content="The perfect emulation setup to study and develop the <<linux-kernel>> v5.9.2, kernel modules, <<qemu-buildroot-setup,QEMU>>, <<gem5-buildroot-setup,gem5>> and x86_64, ARMv7 and ARMv8 <<userland-assembly,userland>> and <<baremetal-setup,baremetal>> assembly, <<c,ANSI C>>, <<cpp,C++>> and <<posix,POSIX>>. EVERYTHING is built from source. <<gdb>> and <<kgdb>> just work. Powered by <<about-the-qemu-buildroot-setup,Buildroot>> and <<about-the-baremetal-setup,crosstool-NG>>. Highly automated. Thoroughly documented. Automated <<test-this-repo,tests>>. "Tested" in an Ubuntu 20.04 host.">
|
||||
<title>Linux Kernel Module Cheat</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
|
||||
<style>
|
||||
@@ -458,13 +458,37 @@ pre{ white-space:pre }
|
||||
<p><a href="https://zenodo.org/badge/latestdoi/64534859"><span class="image"><img src="https://zenodo.org/badge/64534859.svg" alt="64534859"></span></a></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The perfect emulation setup to study and develop the <a href="#linux-kernel">Linux kernel</a> v5.9.2, kernel modules, <a href="#qemu-buildroot-setup">QEMU</a>, <a href="#gem5-buildroot-setup">gem5</a> and x86_64, ARMv7 and ARMv8 <a href="#userland-assembly">userland</a> and <a href="#baremetal-setup">baremetal</a> assembly, <a href="#c">ANSI C</a>, <a href="#cpp">C++</a> and <a href="#posix">POSIX</a>. <a href="#gdb">GDB step debug</a> and <a href="#kgdb">KGDB</a> just work. Powered by <a href="#about-the-qemu-buildroot-setup">Buildroot</a> and <a href="#about-the-baremetal-setup">crosstool-NG</a>. Highly automated. Thoroughly documented. Automated <a href="#test-this-repo">tests</a>. "Tested" in an Ubuntu 20.04 host.</p>
|
||||
<p>The perfect emulation setup to study and develop the <a href="#linux-kernel">Linux kernel</a> v5.9.2, kernel modules, <a href="#qemu-buildroot-setup">QEMU</a>, <a href="#gem5-buildroot-setup">gem5</a> and x86_64, ARMv7 and ARMv8 <a href="#userland-assembly">userland</a> and <a href="#baremetal-setup">baremetal</a> assembly, <a href="#c">ANSI C</a>, <a href="#cpp">C++</a> and <a href="#posix">POSIX</a>. EVERYTHING is built from source. <a href="#gdb">GDB step debug</a> and <a href="#kgdb">KGDB</a> just work. Powered by <a href="#about-the-qemu-buildroot-setup">Buildroot</a> and <a href="#about-the-baremetal-setup">crosstool-NG</a>. Highly automated. Thoroughly documented. Automated <a href="#test-this-repo">tests</a>. "Tested" in an Ubuntu 20.04 host.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://twitter.com/dakami/status/1344853681749934080">Dan Kaminski-approved</a>™ <a href="https://en.wikipedia.org/wiki/Dan_Kaminsky">RIP</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>TL;DR: <a href="#qemu-buildroot-setup-getting-started">Section 2.2.1, “QEMU Buildroot setup getting started”</a></p>
|
||||
<p>TL;DR: <a href="#qemu-buildroot-setup-getting-started">Section 2.2.1, “QEMU Buildroot setup getting started”</a> tested on Ubuntu 24.04:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>git clone https://github.com/cirosantilli/linux-kernel-module-cheat
|
||||
cd linux-kernel-module-cheat
|
||||
sudo apt install docker
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./run-docker create
|
||||
./run-docker sh</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This leaves you inside a Docker shell. Then inside Docker:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./build --download-dependencies qemu-buildroot
|
||||
./run</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>and you are now in a Linux userland shell running on QEMU with everything built fully from source.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The source code for this page is located at: <a href="https://github.com/cirosantilli/linux-kernel-module-cheat" class="bare">https://github.com/cirosantilli/linux-kernel-module-cheat</a>. Due to <a href="https://github.com/isaacs/github/issues/1610">a GitHub limitation</a>, this README is too long and not fully rendered on github.com, so either use:</p>
|
||||
@@ -943,7 +967,15 @@ pre{ white-space:pre }
|
||||
</li>
|
||||
<li><a href="#pseudo-files">17.8. Pseudo files</a>
|
||||
<ul class="sectlevel3">
|
||||
<li><a href="#file-operations">17.8.1. File operations</a></li>
|
||||
<li><a href="#file-operations">17.8.1. File operations</a>
|
||||
<ul class="sectlevel4">
|
||||
<li><a href="#fops">17.8.1.1. fops.c</a>
|
||||
<ul class="sectlevel5">
|
||||
<li><a href="#memfile">17.8.1.1.1. memfile.c</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#seq-file">17.8.2. seq_file</a>
|
||||
<ul class="sectlevel4">
|
||||
<li><a href="#seq-file-single-open">17.8.2.1. seq_file single_open</a></li>
|
||||
@@ -1062,6 +1094,7 @@ pre{ white-space:pre }
|
||||
<li><a href="#kernel-modules">17.22. Kernel modules</a>
|
||||
<ul class="sectlevel3">
|
||||
<li><a href="#dump-regs">17.22.1. dump_regs</a></li>
|
||||
<li><a href="#scull">17.22.2. scull</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -2148,9 +2181,7 @@ pre{ white-space:pre }
|
||||
<li><a href="#p51-benchmarks">35.3.1.1. P51 benchmarks</a></li>
|
||||
<li><a href="#intel-core-i7-7820hq-cpu">35.3.1.2. Intel Core i7-7820HQ CPU</a></li>
|
||||
<li><a href="#samsung-m471a2k43bb1-crc-16gb-dram">35.3.1.3. Samsung M471A2K43BB1-CRC 16GB DRAM</a></li>
|
||||
<li><a href="#samsung-mzvlb512hajq-000l7-512gb-ssd">35.3.1.4. Samsung MZVLB512HAJQ-000L7 512GB SSD</a></li>
|
||||
<li><a href="#seagate-st1000lm035-1rk1-1tb-hard-disk">35.3.1.5. Seagate ST1000LM035-1RK1 1TB hard disk</a></li>
|
||||
<li><a href="#nvidia-quadro-m1200-4gb-gddr5-gpu">35.3.1.6. NVIDIA Quadro M1200 4GB GDDR5 GPU</a></li>
|
||||
<li><a href="#nvidia-quadro-m1200-4gb-gddr5-gpu">35.3.1.4. NVIDIA Quadro M1200 4GB GDDR5 GPU</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -2261,7 +2292,11 @@ pre{ white-space:pre }
|
||||
<li><a href="#simultaneous-runs">38.12. Simultaneous runs</a></li>
|
||||
<li><a href="#build-variants">38.13. Build variants</a>
|
||||
<ul class="sectlevel3">
|
||||
<li><a href="#linux-kernel-build-variants">38.13.1. Linux kernel build variants</a></li>
|
||||
<li><a href="#linux-kernel-build-variants">38.13.1. Linux kernel build variants</a>
|
||||
<ul class="sectlevel4">
|
||||
<li><a href="#linux-worktree">38.13.1.1. Linux worktree</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#qemu-build-variants">38.13.2. QEMU build variants</a></li>
|
||||
<li><a href="#gem5-build-variants">38.13.3. gem5 build variants</a>
|
||||
<ul class="sectlevel4">
|
||||
@@ -2363,7 +2398,9 @@ pre{ white-space:pre }
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./run --china > index.html
|
||||
firefox index.html</pre>
|
||||
</div>
|
||||
@@ -2503,6 +2540,8 @@ firefox index.html</pre>
|
||||
<div class="content">
|
||||
<pre>git clone https://github.com/cirosantilli/linux-kernel-module-cheat
|
||||
cd linux-kernel-module-cheat
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --download-dependencies qemu-buildroot
|
||||
./run</pre>
|
||||
@@ -2590,7 +2629,9 @@ hello2 cleanup</pre>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --arch aarch64 --download-dependencies qemu-buildroot
|
||||
./run --arch aarch64</pre>
|
||||
</div>
|
||||
@@ -2784,6 +2825,17 @@ hello /root/.profile
|
||||
<p>and the new <code>pr_info</code> message should now show on the terminal at the end of the boot.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>If you are simultaneously developing the test script and the kernel module, some smart test scripts should take the kernel module as first argument so you can directly run:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>/mnt/9p/rootfs_overlay/lkmc/scull.sh /mnt/9p/out_rootfs_overlay/lkmc/scull.ko</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>and it will pick up both the test script and the kernel module from host.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This works because we have a <a href="#9p">9P</a> mount there setup by default, which mounts the host directory that contains the build outputs on the guest:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
@@ -2798,7 +2850,7 @@ hello /root/.profile
|
||||
<p>Such failures are however unlikely, and you should be fine if you don’t see anything weird happening.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The safe way, is to fist <a href="#rebuild-buildroot-while-running">quit QEMU</a>, rebuild the modules, put them in the root filesystem, and then reboot:</p>
|
||||
<p>The safe way is to fist <a href="#rebuild-buildroot-while-running">quit QEMU</a>, rebuild the modules put them somewhere QEMU can see and then reboot. So you could either place it in the root filesystem:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
@@ -2808,7 +2860,16 @@ hello /root/.profile
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>./build-buildroot</code> is required after <code>./build-modules</code> because it re-generates the root filesystem with the modules that we compiled at <code>./build-modules</code>.</p>
|
||||
<p>where <code>./build-buildroot</code> is required after <code>./build-modules</code> because it re-generates the root filesystem with the modules that we compiled at <code>./build-modules</code>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Alternatively, for a slightly faster turnaround just leave it on 9p and use it from there:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./build-modules
|
||||
./run --eval-after 'insmod /mnt/9p/out_rootfs_overlay/lkmc/hello.ko'</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can see that <code>./build</code> does that as well, by running:</p>
|
||||
@@ -3287,7 +3348,9 @@ j = 0</pre>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --download-dependencies gem5-buildroot
|
||||
./run --emulator gem5</pre>
|
||||
</div>
|
||||
@@ -3386,6 +3449,8 @@ j = 0</pre>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>sudo apt-get install docker
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./run-docker create && \
|
||||
./run-docker sh -- ./build --download-dependencies qemu-buildroot
|
||||
@@ -3633,7 +3698,9 @@ unzip lkmc-*.zip
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --download-dependencies qemu
|
||||
./run</pre>
|
||||
</div>
|
||||
@@ -3961,6 +4028,8 @@ cd userland
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>cd linux-kernel-module-cheat
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --download-dependencies userland-host</pre>
|
||||
</div>
|
||||
@@ -4217,7 +4286,9 @@ cd userland
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --arch aarch64 --download-dependencies qemu-baremetal
|
||||
./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c</pre>
|
||||
</div>
|
||||
@@ -4330,7 +4401,9 @@ error: simulation error detected by parsing logs</pre>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
<pre>python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup
|
||||
./build --download-dependencies gem5-baremetal
|
||||
./run --arch aarch64 --baremetal userland/c/hello.c --emulator gem5</pre>
|
||||
</div>
|
||||
@@ -4438,12 +4511,21 @@ xdg-open README.html</pre>
|
||||
<p>For development, you will want to do a more controlled build with extra error checking as follows.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>For the initial build do:</p>
|
||||
<p>TODO: get this working seamlessly on Docker. For now some quick instructions for host building. For the initial build, first install RVM and Ruby as per <a href="https://www.rvm.io/rvm/install" class="bare">https://www.rvm.io/rvm/install</a>:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./setup
|
||||
./build --download-dependencies docs</pre>
|
||||
<pre>\curl -sSL https://get.rvm.io | bash
|
||||
rvm install 3.2.3</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The TODO Docker instructions which are not yet working should look simply something like this:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./run-docker
|
||||
./build --download-dependencies doc</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
@@ -8048,6 +8130,8 @@ cat f
|
||||
<pre>sudo apt-get install git
|
||||
git clone https://github.com/cirosantilli/linux-kernel-module-cheat
|
||||
cd linux-kernel-module-cheat
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
./setup -y</pre>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10371,7 +10455,7 @@ cat index.html</pre>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>requires <code>sudo</code> on the host to mount</p>
|
||||
<p>doesn’t require <code>sudo</code> on the host to mount</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>we could share a guest directory to the host, but this would require running a server on the guest, which adds <a href="#resource-tradeoff-guidelines">simulation overhead</a></p>
|
||||
@@ -13498,13 +13582,28 @@ echo $?</pre>
|
||||
<div class="sect3">
|
||||
<h4 id="file-operations"><a class="anchor" href="#file-operations"></a><a class="link" href="#file-operations">17.8.1. File operations</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>File operations are the main method of userland driver communication.</p>
|
||||
<p>File operations are the main method of userland driver communication that uses common file system calls such as read and write.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>struct file_operations</code> determines what the kernel will do on filesystem system calls of <a href="#pseudo-filesystems">Pseudo filesystems</a>.</p>
|
||||
<p>Through <code>struct file_operations</code> drivers tell the kernel what it should do on filesystem system calls of <a href="#pseudo-filesystems">Pseudo filesystems</a>.</p>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="fops"><a class="anchor" href="#fops"></a><a class="link" href="#fops">17.8.1.1. fops.c</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>This example illustrates the most basic system calls: <code>open</code>, <code>read</code>, <code>write</code>, <code>close</code> and <code>lseek</code>.</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/fops.c">kernel_modules/fops.c</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/fops.sh">rootfs_overlay/lkmc/fops.sh</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This example illustrates the most basic system calls: <code>open</code>, <code>read</code>, <code>write</code>, <code>close</code> and <code>lseek</code>:</p>
|
||||
<p>In it we create a debugfs special file that behaves like a regular file, except that it is stored in memory for as long as the kernel module is loaded, and it has a fixed lengh of 4 bytes. Any longer <code>write</code> attempt gets simply truncated up at the end:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
@@ -13521,19 +13620,6 @@ echo $?</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Sources:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/fops.c">kernel_modules/fops.c</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/fops.sh">rootfs_overlay/lkmc/fops.sh</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Then give this a try:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
@@ -13547,6 +13633,34 @@ echo $?</pre>
|
||||
<div class="paragraph">
|
||||
<p>No, there no official documentation: <a href="https://stackoverflow.com/questions/15213932/what-are-the-struct-file-operations-arguments" class="bare">https://stackoverflow.com/questions/15213932/what-are-the-struct-file-operations-arguments</a></p>
|
||||
</div>
|
||||
<div class="sect5">
|
||||
<h6 id="memfile"><a class="anchor" href="#memfile"></a><a class="link" href="#memfile">17.8.1.1.1. memfile.c</a></h6>
|
||||
<div class="paragraph">
|
||||
<p>This example behaves the same as <a href="#fops">fops.c</a>, except that the in-memory virtual file has unlimited size. In the kernel module we have therefore to so a bit of memory management and somehow increase the size of the buffer as needed.</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/memfile.c">kernel_modules/memfile.c</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/memfile.sh">rootfs_overlay/lkmc/memfile.sh</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>TODO: this example builds but oopses with out of memory on our currently default kernel v5.9.2 when doing the big allocation at:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>dd if=/dev/zero of="$f" bs=1k count=1M</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>It works however on kernel 6.8.12, we’re not sure why. We do have a potential krealloc vs kvrealloc on version check which is a very likely reason for the issue, but it has not been investigated.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="seq-file"><a class="anchor" href="#seq-file"></a><a class="link" href="#seq-file">17.8.2. seq_file</a></h4>
|
||||
@@ -13616,7 +13730,7 @@ echo $?</pre>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./seq_file.sh
|
||||
<pre>./seq_file_single_open.sh
|
||||
echo $?</pre>
|
||||
</div>
|
||||
</div>
|
||||
@@ -17065,6 +17179,120 @@ ps</pre>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="scull"><a class="anchor" href="#scull"></a><a class="link" href="#scull">17.22.2. scull</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>This kernel module is a port of scull example from LDD3. It was tested on LKMC e1834763088b8a7532b5fae800039de880471f2d + 1 with Linux kernel 6.8.12.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>"Scull" is an acronym for "Simple Character Utility for Loading Localities". This expansion is mostly meaningless however, but there you are.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Source code:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/scull.c">kernel_modules/scull.c</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/scull.sh">rootfs_overlay/lkmc/scull.sh</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Create the devices and test them:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>scull.sh</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>scull creates several character devices.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The most "basic" one is <code>/dev/scull0</code>, which acts a bit as an in-memory file, except that it has weird quantizations applied to it so that you can’t append as normal and it doesn’t really look like a regular file. What it actually is more like is an object pool.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The original scull interface is very weird and would erase all data on write-only <code>O_WRONLY</code>, but not on read/write <code>O_RDWR</code>, which doesn’t make much sense:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>int scull_open(struct inode *inode, struct file *filp) {
|
||||
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
|
||||
scull_trim(dev); /* ignore errors */</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>We have modified that to the much more reasonable:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre> if ((filp->f_flags & O_TRUNC)) {</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The old weird truncation condition makes the code hard to test as there is no way to write to two different blocks like it and keep them both in memory, unless you are able to find a CLI tool that supports <code>O_RDWR</code> or you write a C program to test things.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>With our new inferface, we can differentiate clear all vs don’t clear all in the usual manner, e.g. this clears:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>echo asdf > /dev/scull0</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>but this doesn’t:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>echo asdf >> /dev/scull0</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The examples from our test should make its weird behavior clearer e.g.:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre># Append starts writing from the start of the 4k block, not like the usual semantic.
|
||||
printf asdf > "$f"
|
||||
printf qw >> "$f"
|
||||
[ "$(cat "$f")" = qwdf ]
|
||||
|
||||
# Overwrite first clears everything, then writes to start of 4k block.
|
||||
printf asdf > /dev/${module}0
|
||||
printf qw > /dev/${module}0
|
||||
[ "$(cat "$f")" = qw ]
|
||||
|
||||
# Read from the middle
|
||||
printf asdf > /dev/${module}0
|
||||
[ "$(dd if="$f" bs=1 count=2 skip=2 status=none)" = df ]
|
||||
|
||||
# Write to the middle
|
||||
printf asdf > /dev/${module}0
|
||||
printf we | dd of="$f" bs=1 seek=1 conv=notrunc status=none
|
||||
[ "$(cat "$f")" = aqwf ]</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>It is also worth noting that the implementation of scull is meant to be "readable" but not optimal:</p>
|
||||
</div>
|
||||
<div class="quoteblock">
|
||||
<blockquote>
|
||||
<div class="paragraph">
|
||||
<p>kmalloc is not the most efficient way to allocate large areas of memory (see Chapter 8), so the implementation chosen for scull is not a particularly smart one. The source code for a smart implementation would be more difficult to read, and the aim of this section is to show read and write, not memory management. That’s why the code just uses kmalloc and kfree without resorting to allocation of whole pages, although that approach would be more efficient.</p>
|
||||
</div>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Another shortcoming of the example is that it uses mutexes, where rwsem would be the clearly superior choice.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This module was derived from <a href="https://github.com/martinezjavier/ldd3/tree/30f801cd0157e8dfb41193f471dc00d8ca10239f/scull" class="bare">https://github.com/martinezjavier/ldd3/tree/30f801cd0157e8dfb41193f471dc00d8ca10239f/scull</a> which had already ported it to much more recent kernel versions for us. Ideally we should just use that repo as a submodule, but we were lazy to setup the buildroot properly for now, and decided to dump it all into a single file to start with.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18443,6 +18671,17 @@ reverse-next</pre>
|
||||
<div class="sect2">
|
||||
<h3 id="tracing"><a class="anchor" href="#tracing"></a><a class="link" href="#tracing">23.9. Tracing</a></h3>
|
||||
<div class="paragraph">
|
||||
<p>The tracing described in this section requires rebuilding QEMU with:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./build-qemu --extra-config-args=--enable-trace-backends=simple</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Ideally we would like to use this build option by default, but unfortunately starting on some QEMU version this started generating <code>trace-<pid></code> files for every run which is far too annoying when you don’t want traces, and we don’t know how to turn it off at runtime or make the files be created in some other directory.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>QEMU can log several different events.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
@@ -42761,7 +43000,7 @@ tail -n+1 ../linux-kernel-module-cheat-regression/*/gem5-bench-build-*.txt</pre>
|
||||
<div class="quoteblock">
|
||||
<blockquote>
|
||||
<div class="paragraph">
|
||||
<p>Lenovo ThinkPad P51 laptop with CPU: <a href="#intel-core-i7-7820hq-cpu">Intel Core i7-7820HQ</a> (4 cores / 8 threads, 2.90 GHz base, 8 MB cache), DRAM: 2x <a href="#samsung-m471a2k43bb1-crc-16gb-dram">Samsung M471A2K43BB1-CRC</a> (2x 16GiB, 2400 Mbps), SSD: <a href="#samsung-mzvlb512hajq-000l7-512gb-ssd">Samsung MZVLB512HAJQ-000L7</a> (512GB, 3,000 MB/s).</p>
|
||||
<p>Lenovo ThinkPad P51 laptop with CPU: <a href="#intel-core-i7-7820hq-cpu">Intel Core i7-7820HQ</a> (4 cores / 8 threads, 2.90 GHz base, 8 MB cache), DRAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB, 2400 Mbps), SSD: Samsung MZVLB512HAJQ-000L7 (512GB, 3,000 MB/s).</p>
|
||||
</div>
|
||||
</blockquote>
|
||||
</div>
|
||||
@@ -42771,7 +43010,7 @@ tail -n+1 ../linux-kernel-module-cheat-regression/*/gem5-bench-build-*.txt</pre>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>Hard disk: <a href="#seagate-st1000lm035-1rk1-1tb-hard-disk">Seagate ST1000LM035-1RK1 1TB hard disk</a></p>
|
||||
<p>Hard disk: Seagate ST1000LM035-1RK1 1TB hard disk</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>GPU: <a href="#nvidia-quadro-m1200-4gb-gddr5-gpu">NVIDIA Quadro M1200 4GB GDDR5 GPU</a></p>
|
||||
@@ -42952,56 +43191,7 @@ LEVEL4_CACHE_LINESIZE 0</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="samsung-mzvlb512hajq-000l7-512gb-ssd"><a class="anchor" href="#samsung-mzvlb512hajq-000l7-512gb-ssd"></a><a class="link" href="#samsung-mzvlb512hajq-000l7-512gb-ssd">35.3.1.4. Samsung MZVLB512HAJQ-000L7 512GB SSD</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>PCIe TLC OPAL2.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://www.samsung.com/semiconductor/ssd/client-ssd/MZVLB512HAJQ/" class="bare">https://www.samsung.com/semiconductor/ssd/client-ssd/MZVLB512HAJQ/</a> (<a href="http://web.archive.org/web/20181224225400/https://www.samsung.com/semiconductor/ssd/client-ssd/MZVLB512HAJQ/">archive</a>).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://www.samsung.com/semiconductor/global.semi/file/resource/2018/05/PM981_M.2_SSD_Datasheet_v1.3_for_General.pdf" class="bare">https://www.samsung.com/semiconductor/global.semi/file/resource/2018/05/PM981_M.2_SSD_Datasheet_v1.3_for_General.pdf</a> | <a href="http://web.archive.org/web/20181224225410/https://www.samsung.com/semiconductor/global.semi/file/resource/2018/05/PM981_M.2_SSD_Datasheet_v1.3_for_General.pdf" class="bare">http://web.archive.org/web/20181224225410/https://www.samsung.com/semiconductor/global.semi/file/resource/2018/05/PM981_M.2_SSD_Datasheet_v1.3_for_General.pdf</a></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>sudo hdparm -Tt /dev/nvme0n1p5</code> on Ubuntu 20.04:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre> Timing cached reads: 29812 MB in 1.99 seconds = 15007.00 MB/sec
|
||||
HDIO_DRIVE_CMD(identify) failed: Inappropriate ioctl for device
|
||||
Timing buffered disk reads: 6328 MB in 3.00 seconds = 2109.00 MB/sec</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Nominal maximum sequential read speed: 3,000 MB/s</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="seagate-st1000lm035-1rk1-1tb-hard-disk"><a class="anchor" href="#seagate-st1000lm035-1rk1-1tb-hard-disk"></a><a class="link" href="#seagate-st1000lm035-1rk1-1tb-hard-disk">35.3.1.5. Seagate ST1000LM035-1RK1 1TB hard disk</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>1TB.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://www.disctech.com/Seagate-ST1000LM035-1TB-SATA-Hard-Drive" class="bare">https://www.disctech.com/Seagate-ST1000LM035-1TB-SATA-Hard-Drive</a> 80 USD | <a href="http://web.archive.org/web/20181224201408/https://www.disctech.com/Seagate-ST1000LM035-1TB-SATA-Hard-Drive" class="bare">http://web.archive.org/web/20181224201408/https://www.disctech.com/Seagate-ST1000LM035-1TB-SATA-Hard-Drive</a></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><a href="https://www.seagate.com/www-content/datasheets/pdfs/mobile-hddDS1861-2-1603-en_US.pdf" class="bare">https://www.seagate.com/www-content/datasheets/pdfs/mobile-hddDS1861-2-1603-en_US.pdf</a> | <a href="http://web.archive.org/web/20181225095438/https://www.seagate.com/www-content/datasheets/pdfs/mobile-hddDS1861-2-1603-en_US.pdf" class="bare">http://web.archive.org/web/20181225095438/https://www.seagate.com/www-content/datasheets/pdfs/mobile-hddDS1861-2-1603-en_US.pdf</a></p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p><code>sudo hdparm -Tt /dev/sda3</code> on Ubuntu 20.04:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre> Timing cached reads: 29594 MB in 1.99 seconds = 14893.89 MB/sec
|
||||
Timing buffered disk reads: 386 MB in 3.01 seconds = 128.07 MB/sec</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Nominal maximum speed: 140MB/s</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="nvidia-quadro-m1200-4gb-gddr5-gpu"><a class="anchor" href="#nvidia-quadro-m1200-4gb-gddr5-gpu"></a><a class="link" href="#nvidia-quadro-m1200-4gb-gddr5-gpu">35.3.1.6. NVIDIA Quadro M1200 4GB GDDR5 GPU</a></h5>
|
||||
<h5 id="nvidia-quadro-m1200-4gb-gddr5-gpu"><a class="anchor" href="#nvidia-quadro-m1200-4gb-gddr5-gpu"></a><a class="link" href="#nvidia-quadro-m1200-4gb-gddr5-gpu">35.3.1.4. NVIDIA Quadro M1200 4GB GDDR5 GPU</a></h5>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -44973,6 +45163,44 @@ git -C "$(./getvar linux_source_dir)" checkout -
|
||||
<div class="paragraph">
|
||||
<p>To run both kernels simultaneously, one on each QEMU instance, see: <a href="#simultaneous-runs">Section 38.12, “Simultaneous runs”</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>You can also build <a href="#kernel-modules">Kernel modules</a> against a specific prebuilt kernel with:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./build-modules --linux-build-id v4.16</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This will then allow you to insmod the kernel modules on your newly built kernel.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Note that for this build to work the Linux kernel must remain checked out at the same version as it was built from, because the build dir which modules build against via the <code>M=</code> argument points to the absolute path of the Linux kernel source from which the headers are taken. For this reason, if you are going to be building kernel modules against a specific kernel version, it is a good idea to use a <a href="#linux-worktree">Linux worktree</a> to ensure that the source for a build is always there.</p>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="linux-worktree"><a class="anchor" href="#linux-worktree"></a><a class="link" href="#linux-worktree">38.13.1.1. Linux worktree</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>If you are working with multiple Linux versions at once, it can be helpful to have their source code checked out all the time, in particular if you are going to be <a href="#gdb">GDB step debugging</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>We have some automation for that. Suppose that you are also interested in the kernel v6.14.4. Then you could do:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>git -C submodules/linux worktree add ../../data/wt/linux/v6.14.4
|
||||
git -C data/wt/linux/v6.14.4 reset --hard v6.14.4</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Then you can use a specific source for a specific <a href="#linux-kernel-build-variants">Linux kernel build variants</a> with:</p>
|
||||
</div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre>./build-linux --linux-worktree v6.14.4 --linux-build-id v6.14.4
|
||||
./run --linux-build-id v6.14.4</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="qemu-build-variants"><a class="anchor" href="#qemu-build-variants"></a><a class="link" href="#qemu-build-variants">38.13.2. QEMU build variants</a></h4>
|
||||
@@ -46568,6 +46796,9 @@ git push --follow-tags
|
||||
<li>
|
||||
<p><a href="https://eli.thegreenplace.net" class="bare">https://eli.thegreenplace.net</a> and the accompanying code: <a href="https://github.com/eliben/code-for-blog" class="bare">https://github.com/eliben/code-for-blog</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="https://github.com/sysprog21/lkmpg" class="bare">https://github.com/sysprog21/lkmpg</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
@@ -46622,7 +46853,6 @@ git push --follow-tags
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
<!-- Google Analytics, AKA selling my soul to Google for some backlinks. -->
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
@@ -46630,5 +46860,12 @@ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
ga('create', 'UA-47867706-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-DEE2HEJW9X"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-DEE2HEJW9X');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user