From 819ef42ea418dc9351716f259fb36945627c3bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Sun, 2 Jun 2019 00:00:01 +0000 Subject: [PATCH] kernel modules: hack up quick floating point example --- README.adoc | 64 ++++++++++++++++++++++++++++++++++++++++- build-modules | 16 +++++++---- kernel_modules/Makefile | 5 ++++ kernel_modules/float.c | 31 ++++++++++++++++++++ path_properties.py | 16 +++++++---- 5 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 kernel_modules/float.c diff --git a/README.adoc b/README.adoc index da2e94f..6a904f7 100644 --- a/README.adoc +++ b/README.adoc @@ -5537,7 +5537,23 @@ This likely comes from the ifdef split at `init/main.c`: ==== Kernel module parameters -The Linux kernel allows passing module parameters at insertion time <>: +The Linux kernel allows passing module parameters at insertion time <>. + +The `insmod` tool exposes that as: + +.... +insmod params.ko i=3 j=4 +.... + +Parameters are declared in the module as: + +.... +static u32 i = 0; +module_param(i, int, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(i, "my favorite int"); +.... + +Automated test: .... ./params.sh @@ -5890,6 +5906,52 @@ Source: link:kernel_modules/init_module.c[] TODO why were `module_init` and `module_exit` created? https://stackoverflow.com/questions/3218320/what-is-the-difference-between-module-init-and-init-module-in-a-linux-kernel-mod +==== Floating point in kernel modules + +It is generally hard / impossible to use floating point operations in the kernel. TODO understand details. + +A quick (x86-only for now because lazy) example is shown at: link:kernel_modules/float.c[] + +Usage: + +.... +insmod float.ko myfloat=1 enable_fpu=1 +.... + +We have to call: `kernel_fpu_begin()` before starting FPU operations, and `kernel_fpu_end()` when we are done. This particular example however did not blow up without it at lkmc 7f917af66b17373505f6c21d75af9331d624b3a9 + 1: + +.... +insmod float.ko myfloat=1 enable_fpu=0 +.... + +The v5.1 documentation under link:https://github.com/cirosantilli/linux/blob/v5.1/arch/x86/include/asm/fpu/api.h#L15[arch/x86/include/asm/fpu/api.h] reads: + +.... + * Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It + * disables preemption so be careful if you intend to use it for long periods + * of time. +.... + +The example sets in the link:kernel_modules/Makefile[]: + +.... +CFLAGS_REMOVE_float.o += -mno-sse -mno-sse2 +.... + +to avoid: + +.... +error: SSE register return with SSE disabled +.... + +We found those flags with `./build-modules --verbose`. + +Bibliography: + +* https://stackoverflow.com/questions/13886338/use-of-floating-point-in-the-linux-kernel +* https://stackoverflow.com/questions/15883947/why-am-i-able-to-perform-floating-point-operations-inside-a-linux-kernel-module/47056242 +* https://stackoverflow.com/questions/1556142/sse-register-return-with-sse-disabled + === Kernel panic and oops To test out kernel panics and oops in controlled circumstances, try out the modules: diff --git a/build-modules b/build-modules index bef0bfb..18401aa 100755 --- a/build-modules +++ b/build-modules @@ -8,6 +8,7 @@ import shutil import common from shell_helpers import LF +import path_properties class Main(common.BuildCliFunction): def __init__(self): @@ -32,13 +33,15 @@ Build the Linux kernel modules against the host kernel. Place the modules on a separate magic directory from non --host builds. ''', ) + self._add_argument('--force-rebuild') self.add_argument( 'kernel-modules', default=[], - help='Which kernel modules to build. Default: build all', + help='''\ +Which kernel modules to build. Default: build all. +Can be either the path to the C file, or its basename without extension.''', nargs='*', ) - self._add_argument('--force-rebuild') def build(self): build_dir = self.get_build_dir() @@ -63,11 +66,14 @@ Place the modules on a separate magic directory from non --host builds. ) all_kernel_modules = [] for basename in os.listdir(self.env['kernel_modules_source_dir']): - src = os.path.join(self.env['kernel_modules_source_dir'], basename) - if os.path.isfile(src): + abspath = os.path.join(self.env['kernel_modules_source_dir'], basename) + if os.path.isfile(abspath): noext, ext = os.path.splitext(basename) if ext == self.env['c_ext']: - all_kernel_modules.append(noext) + relpath = abspath[len(self.env['root_dir']) + 1:] + my_path_properties = path_properties.get(relpath) + if my_path_properties.should_be_built(self.env): + all_kernel_modules.append(noext) if self.env['kernel_modules'] == []: kernel_modules = all_kernel_modules else: diff --git a/kernel_modules/Makefile b/kernel_modules/Makefile index 7f5d60a..803fd99 100644 --- a/kernel_modules/Makefile +++ b/kernel_modules/Makefile @@ -13,6 +13,11 @@ ccflags-y := \ -Wno-declaration-after-statement \ $(CCFLAGS) +ifeq ($(ARCH),x86) + # https://github.com/cirosantilli/linux-kernel-module-cheat#floating-point-in-kernel-modules + CFLAGS_REMOVE_float.o += -mno-sse -mno-sse2 +endif + .PHONY: all all: diff --git a/kernel_modules/float.c b/kernel_modules/float.c new file mode 100644 index 0000000..6ecf805 --- /dev/null +++ b/kernel_modules/float.c @@ -0,0 +1,31 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#floating-point-in-kernel-modules */ + +#include +#include +#include /* kernel_fpu_begin, kernel_fpu_end */ + +/* float params are not supported, so we just go with int. */ +static int myfloat = 1; +static int enable_fpu = 1; +module_param(myfloat, int, S_IRUSR | S_IWUSR); +module_param(enable_fpu, int, S_IRUSR | S_IWUSR); + +static int myinit(void) +{ + if (enable_fpu) { + kernel_fpu_begin(); + } + if ((float)myfloat + 1.5f == 2.5f) { + pr_info("magic value\n"); + } + if (enable_fpu) { + kernel_fpu_end(); + } + return 0; +} + +static void myexit(void) {} + +module_init(myinit) +module_exit(myexit) +MODULE_LICENSE("GPL"); diff --git a/path_properties.py b/path_properties.py index 4dad4a0..c9d32c1 100644 --- a/path_properties.py +++ b/path_properties.py @@ -128,18 +128,18 @@ class PathProperties: self['allowed_archs'] is None or env['arch'] in self['allowed_archs'] ) and - ( + not ( ( env['mode'] == 'userland' and ( - self['userland'] and - ext in env['build_in_exts'] + not self['userland'] or + not ext in env['build_in_exts'] ) ) or ( env['mode'] == 'baremetal' and ( - self['baremetal'] and - ext in env['baremetal_build_in_exts'] + not self['baremetal'] or + not ext in env['baremetal_build_in_exts'] ) ) ) and @@ -311,6 +311,12 @@ path_properties_tuples = ( 'getchar.c': {'interactive': True}, } ), + 'kernel_modules': ( + {}, + { + 'float.c': {'allowed_archs': 'x86_64'} + }, + ), 'lkmc.c': { 'baremetal': True, 'userland': True,