about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/system/boot/kernel_config.nix
blob: a316782dfc578ca9bc83554dbbfc90cda406ba17 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{ lib, config, ... }:

with lib;
let
  findWinner = candidates: winner:
    any (x: x == winner) candidates;

  # winners is an ordered list where first item wins over 2nd etc
  mergeAnswer = winners: locs: defs:
    let
      values = map (x: x.value) defs;
      inter = intersectLists values winners;
      winner = head winners;
    in
    if defs == [] then abort "This case should never happen."
    else if winner == [] then abort "Give a valid list of winner"
    else if inter == [] then mergeOneOption locs defs
    else if findWinner values winner then
      winner
    else
      mergeAnswer (tail winners) locs defs;

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

  kernelItem = types.submodule {
    options = {
      tristate = mkOption {
        type = types.enum [ "y" "m" "n" null ] // {
          merge = mergeAnswer [ "y" "m" "n" ];
        };
        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 = ''
          Wether option should generate a failure when unused.
        '';
      };
    };
  };

  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 = literalExample '' with lib.kernel; {
        "9P_NET" = yes;
        USB = optional yes;
        MMC_BLOCK_MINORS = freeform "32";
      }'';
      description = ''
        Structured kernel configuration.
      '';
    };
  };

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