blog: nixos-kernel-hacking: finish the rest of the article
This commit is contained in:
@@ -101,7 +101,7 @@ this patch can alternately be represented as a [Device Tree Overlay] (DTO):
|
||||
// instruct the system to only apply this overlay
|
||||
// to PinePhone Pro, and not any other devices.
|
||||
/ {
|
||||
compatible = "pine64,pinephone-pro";
|
||||
compatible = "pine64,pinephone-pro";
|
||||
};
|
||||
|
||||
// address the parent node we want to patch,
|
||||
@@ -109,7 +109,7 @@ this patch can alternately be represented as a [Device Tree Overlay] (DTO):
|
||||
// this overrides `press-threshold-microvolt`
|
||||
// while leaving all other properties unchanged.
|
||||
&{/adc-keys/button-down} {
|
||||
press-threshold-microvolt = <400000>;
|
||||
press-threshold-microvolt = <400000>;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -155,15 +155,173 @@ then, we can ship new kernel modules by:
|
||||
|
||||
### Building a Kernel Module
|
||||
|
||||
TODO
|
||||
my kernel module has 3 files, which live in my nix repo inline:
|
||||
- [rk818_battery.c](https://git.uninsane.org/colin/nix-files/src/commit/4e008c34208143a489d824b288437201f7137ace/pkgs/linux-packages/rk818-charger/rk818_battery.c)
|
||||
- [rk818_battery.h](https://git.uninsane.org/colin/nix-files/src/commit/4e008c34208143a489d824b288437201f7137ace/pkgs/linux-packages/rk818-charger/rk818_battery.h)
|
||||
- [rk818_charger.c](https://git.uninsane.org/colin/nix-files/src/commit/4e008c34208143a489d824b288437201f7137ace/pkgs/linux-packages/rk818-charger/rk818_charger.c)
|
||||
|
||||
these are compiled into `rk818_battery.ko` and `rk818_charger.ko` by a Makefile:
|
||||
|
||||
```make
|
||||
obj-m := rk818_battery.o rk818_charger.o
|
||||
|
||||
all:
|
||||
$(MAKE) -C "$(KERNEL_DIR)" M="$(PWD)" modules
|
||||
install:
|
||||
install -Dm444 rk818_battery.ko $(INSTALL_MOD_PATH)/drivers/power/supply/rk818_battery.ko
|
||||
install -Dm444 rk818_charger.ko $(INSTALL_MOD_PATH)/drivers/power/supply/rk818_charger.ko
|
||||
```
|
||||
|
||||
this can be packaged for nix as so:
|
||||
|
||||
```nix
|
||||
# file: pkgs/linux-packages/rk818-charger/default.nix
|
||||
{
|
||||
buildPackages,
|
||||
kernel,
|
||||
lib,
|
||||
stdenv,
|
||||
}: stdenv.mkDerivation {
|
||||
pname = "rk818-charger";
|
||||
version = "0-unstable-2024-10-01";
|
||||
|
||||
src = ./.;
|
||||
|
||||
hardeningDisable = [ "pic" ];
|
||||
nativeBuildInputs = kernel.moduleBuildDependencies;
|
||||
|
||||
makeFlags = [
|
||||
"KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
|
||||
"INSTALL_MOD_PATH=$(out)/lib/modules/${kernel.modDirVersion}/kernel"
|
||||
# from pkgs/os-specific/linux/kernel/manual-config.nix:
|
||||
"O=$(buildRoot)"
|
||||
"CC=${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"
|
||||
"HOSTCC=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc"
|
||||
"HOSTLD=${buildPackages.stdenv.cc.bintools}/bin/${buildPackages.stdenv.cc.targetPrefix}ld"
|
||||
"ARCH=${stdenv.hostPlatform.linuxArch}"
|
||||
] ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
|
||||
"CROSS_COMPILE=${stdenv.cc.targetPrefix}"
|
||||
];
|
||||
|
||||
# NixOS kernel expects compressed kernel modules, so do that here.
|
||||
postInstall = ''
|
||||
find $out -name '*.ko' -exec xz {} \;
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
then add this package to the `linuxKernel` package set:
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
{
|
||||
nixpkgs.overlays = [(self: super: {
|
||||
linuxKernel = super.linuxKernel // {
|
||||
packagesFor = kernel:
|
||||
(
|
||||
super.linuxKernel.packagesFor kernel
|
||||
).extend (kFinal: kPrev: with kFinal; {
|
||||
rk818-charger = callPackage ./pkgs/linux-packages/rk818-charger { };
|
||||
});
|
||||
};
|
||||
})];
|
||||
}
|
||||
```
|
||||
|
||||
kernel modules must be built against the same kernel version
|
||||
that they'll be loaded by: this `linuxKernel` package set looks
|
||||
funny at first, but it exists to make that easier.
|
||||
|
||||
your kernel module can be built like this:
|
||||
- `nix-build -A linuxPackages_6_11.rk818-charger`
|
||||
- `nix-build -A linuxPackages_6_10.rk818-charger`
|
||||
|
||||
and so on, depending on which kernel you're running.
|
||||
|
||||
### Deploying a Kernel Module
|
||||
|
||||
TODO
|
||||
add the following to your NixOS config:
|
||||
|
||||
```nix
|
||||
{ config, ... }:
|
||||
{
|
||||
# this builds our modules against the specific kernel in use by the host
|
||||
# and makes them available under /run/current-system/kernel-modules to tools like `modprobe`
|
||||
boot.extraModulePackages = [
|
||||
config.boot.kernelPackages.rk818-charger
|
||||
];
|
||||
|
||||
# explicitly load the modules during stage-2 boot.
|
||||
# if they're needed earlier in the boot process, use `boot.initrd.kernelModules` instead.
|
||||
boot.kernelModules = [
|
||||
"rk818_battery"
|
||||
"rk818_charger"
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
now we've recreated the same behavior as if the kernel module had been shipped in-tree,
|
||||
but we still have to associate the driver with a specific device if we want it to do anything.
|
||||
|
||||
### Device Tree + Module Integration
|
||||
|
||||
TODO
|
||||
add the following Device Tree Overlay to `hardware.deviceTree.overlays`,
|
||||
as we did earlier with the battery DTO:
|
||||
|
||||
```dts
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
// apply the overlay only to PinePhone Pro; no other devices.
|
||||
/ {
|
||||
compatible = "pine64,pinephone-pro";
|
||||
};
|
||||
|
||||
&{/} {
|
||||
bat: battery {
|
||||
compatible = "simple-battery";
|
||||
voltage-min-design-microvolt = <3400000>;
|
||||
voltage-max-design-microvolt = <4350000>;
|
||||
};
|
||||
};
|
||||
|
||||
&rk818 {
|
||||
battery {
|
||||
// this line associates this device with the rk818-battery module
|
||||
// we just shipped
|
||||
compatible = "rockchip,rk818-battery";
|
||||
// constants were taken from the pine64-org kernel tree:
|
||||
ocv_table = <3400 3675 3689 3716 3740 3756 3768 3780
|
||||
3793 3807 3827 3853 3896 3937 3974 4007 4066
|
||||
4110 4161 4217 4308>;
|
||||
design_capacity = <2916>;
|
||||
design_qmax = <2708>;
|
||||
bat_res = <150>;
|
||||
max_input_current = <3000>;
|
||||
max_chrg_current = <2000>;
|
||||
max_chrg_voltage = <4350>;
|
||||
sleep_enter_current = <300>;
|
||||
sleep_exit_current = <300>;
|
||||
power_off_thresd = <3400>;
|
||||
zero_algorithm_vol = <3950>;
|
||||
fb_temperature = <105>;
|
||||
sample_res = <10>;
|
||||
max_soc_offset = <60>;
|
||||
energy_mode = <0>;
|
||||
monitor_sec = <5>;
|
||||
virtual_power = <0>;
|
||||
power_dc2otg = <0>;
|
||||
otg5v_suspend_enable = <1>;
|
||||
};
|
||||
|
||||
charger {
|
||||
// this line associates this device with the rk818-charger module
|
||||
// we just shipped
|
||||
compatible = "rockchip,rk818-charger";
|
||||
monitored-battery = <&bat>;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## Patching an Upstream Kernel Module
|
||||
|
||||
|
Reference in New Issue
Block a user