summaryrefslogtreecommitdiffstats
path: root/nixos/modules/system/boot/kernel_config.nix
blob: a0065f73314d03babeb1473e3145b8318583e95c (plain)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
{ lib, config, ... }:

with lib;
let
  mergeFalseByDefault =
    locs: defs:
    if defs == [ ] then
      abort "This case should never happen."
    else if elem 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;
        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 == "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
  #       LOCALVERSION
  #
  # A line without a value means an empty string.
  #
  # 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
        optionalString (val != null)
          "${key}${optionalString item.optional "?"}${optionalString (val != "") " ${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
        LOCALVERSION
      '';
      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;
  };
}