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
|
// instruct the system to only apply this overlay
|
||||||
// to PinePhone Pro, and not any other devices.
|
// to PinePhone Pro, and not any other devices.
|
||||||
/ {
|
/ {
|
||||||
compatible = "pine64,pinephone-pro";
|
compatible = "pine64,pinephone-pro";
|
||||||
};
|
};
|
||||||
|
|
||||||
// address the parent node we want to patch,
|
// 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`
|
// this overrides `press-threshold-microvolt`
|
||||||
// while leaving all other properties unchanged.
|
// while leaving all other properties unchanged.
|
||||||
&{/adc-keys/button-down} {
|
&{/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
|
### 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
|
### 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
|
### 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
|
## Patching an Upstream Kernel Module
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user