summary refs log tree commit diff
path: root/nixos/modules/system/boot/kernel_config.nix
blob: 495fe74bc21ee910eb85cc3bf659596ae18d79db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
{ lib, config, ... }:

with lib;
let
  mergeFalseByDefault = locs: defs:
    if defs == [] then abort "This case should never happen."
    else if any (x: x == false) (getValues defs) then false
    else true;

  kernelItem = types.submodule {
    options = {
      tristate = mkOption {
        type = types.enum [ "y" "m" "n" null ];
        default = null;
        internal = true;
        visible = true;
        description = ''
          Use this field for tristate kernel options expecting a "y" or "m" or "n".
        '';
      };

      freeform = mkOption {
        type = types.nullOr types.str // {
          merge = mergeEqualOption;
        };
        default = null;
        example = ''MMC_BLOCK_MINORS.freeform = "32";'';
        description = ''
          Freeform description of a kernel configuration item value.
        '';
      };

      optional = mkOption {
        type = types.bool // { merge = mergeFalseByDefault; };
        default = false;
        description = ''
          Whether option should generate a failure when unused.
          Upon merging values, mandatory wins over optional.
        '';
      };
    };
  };

  mkValue = with lib; val:
  let
    isNumber = c: elem c ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"];

  in
    if (val == "") then "\"\""
    else if val == "y" || val == "m" || val == "n" then val
    else if all isNumber (stringToCharacters val) then val
    else if substring 0 2 val == "0x" then val
    else val; # FIXME: fix quoting one day


  # generate nix intermediate kernel config file of the form
  #
  #       VIRTIO_MMIO m
  #       VIRTIO_BLK y
  #       VIRTIO_CONSOLE n
  #       NET_9P_VIRTIO? y
  #
  # Borrowed from copumpkin https://github.com/NixOS/nixpkgs/pull/12158
  # returns a string, expr should be an attribute set
  # Use mkValuePreprocess to preprocess option values, aka mark 'modules' as 'yes' or vice-versa
  # use the identity if you don't want to override the configured values
  generateNixKConf = exprs:
  let
    mkConfigLine = key: item:
      let
        val = if item.freeform != null then item.freeform else item.tristate;
      in
        if val == null
          then ""
          else if (item.optional)
            then "${key}? ${mkValue val}\n"
            else "${key} ${mkValue val}\n";

    mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
  in mkConf exprs;

in
{

  options = {

    intermediateNixConfig = mkOption {
      readOnly = true;
      type = types.lines;
      example = ''
        USB? y
        DEBUG n
      '';
      description = ''
        The result of converting the structured kernel configuration in settings
        to an intermediate string that can be parsed by generate-config.pl to
        answer the kernel `make defconfig`.
      '';
    };

    settings = mkOption {
      type = types.attrsOf kernelItem;
      example = literalExpression '' with lib.kernel; {
        "9P_NET" = yes;
        USB = option yes;
        MMC_BLOCK_MINORS = freeform "32";
      }'';
      description = ''
        Structured kernel configuration.
      '';
    };
  };

  config = {
    intermediateNixConfig = generateNixKConf config.settings;
  };
}