├── .gitignore
├── .directory
├── LICENSE
├── README.md
└── cachy-kernel-deb
/.gitignore:
--------------------------------------------------------------------------------
1 | linux.tar.xz
2 | /linux-*
3 |
--------------------------------------------------------------------------------
/.directory:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Icon=folder-red
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2024, Nitrux Latinoamericana S.C.
4 | Some rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CachyOS Kernel Builder for Debian-based Distributions
2 |
3 |
4 |

5 |
6 |
CachyOS
7 |
CachyOS provides enhanced kernels that offer improved performance and other benefits.
8 |
9 |
10 |
11 | This repository contains a TUI utility for building the Linux Kernel with various optimizations from CachyOS tailored to your system's CPU architecture. It automates the configuration and creates distributable Debian packages with these modifications.
12 |
13 | # Features
14 |
15 | The utility provides the following:
16 |
17 | - Build a Linux Kernel using [patches from CachyOS](https://github.com/CachyOS/kernel-patches).
18 | - Advanced configuration options, including compilation optimizations.
19 | - Create distributable Debian packages.
20 |
21 | # Usage
22 |
23 | To use the utility, follow these steps:
24 |
25 | 1. Clone the repository to your local machine.
26 | 2. Make the utility executable with `chmod +x cachy-kernel-deb` and move the utility to a directory in the `$PATH`.
27 | 3. Run the utility with `cachy-kernel-deb` and follow the on-screen prompts to configure the kernel and build the packages.
28 |
29 | # Advanced Configuration
30 |
31 | The utility includes advanced configuration options for users who want to fine-tune their kernel:
32 |
33 | - **Linux Kernel Configuration**: Choose from different configurations for the Linux Kernel from CachyOS.
34 | - **CPU Scheduler**: Choose between various schedulers from CachyOS.
35 | - **Configure LLVM's Link Time Optimization (LTO)**: Select from Thin and Full LTO for better optimization.
36 | - **Configurable Tick Rate and Tick Types**: You can configure the kernel tick rate and types according to your system's needs.
37 | - **Configurable NR_CPUS**: Set the maximum number of CPUs/cores the kernel will support.
38 | - **Configurable Hugepages**: Enable Hugepages support or not.
39 | - **Configurable LRU**: Configure the Least Recently Used memory management mechanism.
40 | - **Configurable Preemption Type**: Kernel preemption types generally control how the Linux kernel handles tasks and interrupts, affecting system responsiveness and latency.
41 | - **Configurable Kernel Name**: Choose a name for your custom kernel.
42 | - **Additional Optimizations**: Optimizations target aspects of system performance and can provide benefits depending on the workload and system configuration.
43 | - **Use GCC -O3 Optimizations**: Aggressively optimizes compiled code for speed, possibly increasing binary size and compilation time.
44 | - **Enable Performance Governor**: This setting sets the CPU to run at maximum frequency, boosting performance but increasing power consumption and heat.
45 | - **Enable VMA Optimizations**: Enhances memory management efficiency, potentially improving application performance.
46 | - **Enable DAMON**: Monitors data access patterns to optimize memory usage and improve performance.
47 | - **Enable NUMA**: Optimizes memory allocation and access patterns on NUMA systems to reduce latency.
48 |
49 | # Contributing
50 |
51 | Contributions are welcome! If you have suggestions for improving the utility or adding new features, please open an issue or submit a pull request.
52 |
53 | # License
54 |
55 | The repository and its contents are licensed under BSD-3-Clause.
56 |
57 | # Issues
58 |
59 | If you find problems with the contents of this repository, please create an issue.
60 |
61 | ©2024 Laio O. Seman, Nitrux Latinoamericana S.C.
62 |
63 | ©2025 Nitrux Latinoamericana S.C.
64 |
--------------------------------------------------------------------------------
/cachy-kernel-deb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | #############################################################################################################################################################################
4 | # The license used for this file and its contents is: BSD-3-Clause #
5 | # #
6 | # Copyright <2024> > #
7 | # Copyright <2024-2025> > #
8 | # #
9 | # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: #
10 | # #
11 | # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. #
12 | # #
13 | # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer #
14 | # in the documentation and/or other materials provided with the distribution. #
15 | # #
16 | # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software #
17 | # without specific prior written permission. #
18 | # #
19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, #
20 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS #
21 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
22 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, #
23 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
24 | #############################################################################################################################################################################
25 |
26 |
27 | # -- Exit on errors.
28 |
29 | set -eu
30 |
31 |
32 | # -- Variables to set default options.
33 |
34 | _march="native"
35 |
36 | _selected_kernel_config="linux-cachyos"
37 |
38 | _cachyos_patch_selection=("0001-cachyos-base-all")
39 |
40 | _cpusched_selection="bore-cachy"
41 |
42 | _llvm_lto_selection="thin"
43 |
44 | _tick_rate="1000"
45 |
46 | _tick_type="nohz_full"
47 |
48 | _nr_cpus="32"
49 |
50 | _hugepage="always"
51 |
52 | _lru_config="standard"
53 |
54 | _preempt="preempt"
55 |
56 | _o3_optimization="yes"
57 | _performance_governor="enable"
58 | _vma="yes"
59 | _damon="yes"
60 | _numa="enable"
61 |
62 | _custom_extraversion="-custom-kernel"
63 |
64 | declare -A patch_map
65 |
66 |
67 | # -- Add colors for whiptail.
68 |
69 | export NEWT_COLORS='
70 | root=white,blue
71 | border=black,lightgray
72 | window=black,lightgray
73 | shadow=black,gray
74 | title=black,lightgray
75 | button=black,cyan
76 | actbutton=white,blue
77 | checkbox=black,lightgray
78 | actcheckbox=black,cyan
79 | entry=black,lightgray
80 | label=black,lightgray
81 | listbox=black,lightgray
82 | actlistbox=black,cyan
83 | textbox=black,lightgray
84 | acttextbox=black,cyan
85 | helpline=white,blue
86 | roottext=black,lightgray
87 | '
88 |
89 |
90 | # -- Functions.
91 |
92 | check_deps() {
93 | dependencies=(git libncurses-dev curl gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf llvm bc rsync whiptail jq pahole debhelper)
94 | # shellcheck source=/dev/null
95 | if [[ -f /etc/os-release ]]; then
96 | . /etc/os-release
97 | OS_ID="$ID"
98 | else
99 | OS_ID="unknown"
100 | fi
101 |
102 | for dep in "${dependencies[@]}"; do
103 | if ! dpkg -s "$dep" &>/dev/null; then
104 | sudo apt install -y "$dep"
105 | fi
106 | done
107 |
108 | if ! command -v bpftool &>/dev/null; then
109 | echo "Installing bpftool..."
110 | if [[ "$OS_ID" == "debian" ]]; then
111 | sudo apt install -y bpftool
112 | elif [[ "$OS_ID" == "ubuntu" ]]; then
113 | sudo apt install -y linux-tools-common
114 | else
115 | echo "Warning: Unsupported distribution ($OS_ID). Attempting to install bpftool directly..."
116 | sudo apt install -y bpftool || sudo apt install -y linux-tools-common
117 | fi
118 | fi
119 |
120 | sudo apt install -y "linux-headers-$(uname -r)" "linux-image-$(uname -r)"
121 | }
122 |
123 |
124 | check_gcc() {
125 | command -v gcc &>/dev/null || { echo "Error: GCC is not installed. Please install GCC and try again." >&2; exit 1; }
126 | }
127 |
128 |
129 | init_script() {
130 | clear
131 |
132 | check_gcc
133 |
134 | MARCH=$(gcc -Q -march=native --help=target | awk -F'=' '/^ -march=/ {print toupper($2); exit}' | xargs)
135 |
136 | case $MARCH in
137 | ZNVER1) MARCH="ZEN" ;;
138 | ZNVER2) MARCH="ZEN2" ;;
139 | ZNVER3) MARCH="ZEN3" ;;
140 | ZNVER4) MARCH="ZEN4" ;;
141 | ZNVER5) MARCH="ZEN5" ;;
142 | BDVER1) MARCH="BULLDOZER" ;;
143 | BDVER2) MARCH="PILEDRIVER" ;;
144 | BDVER3) MARCH="STEAMROLLER" ;;
145 | BDVER4) MARCH="EXCAVATOR" ;;
146 | BTVER1) MARCH="BOBCAT" ;;
147 | BTVER2) MARCH="JAGUAR" ;;
148 | AMDFAM10) MARCH="MK10" ;;
149 | K8-SSE3) MARCH="K8SSE3" ;;
150 | BONNELL) MARCH="ATOM" ;;
151 | GOLDMONT-PLUS) MARCH="GOLDMONTPLUS" ;;
152 | SKYLAKE-AVX512) MARCH="SKYLAKEX" ;;
153 | MIVYBRIDGE)
154 | scripts/config --disable CONFIG_AGP_AMD64
155 | scripts/config --disable CONFIG_MICROCODE_AMD
156 | MARCH="MIVYBRIDGE"
157 | ;;
158 | ICELAKE-CLIENT) MARCH="ICELAKE" ;;
159 | esac
160 |
161 | MARCH2="M${MARCH}"
162 |
163 | if ! whiptail --title "CPU Architecture" --yesno "Detected CPU (MARCH) : ${MARCH2}\nIs this correct?" 10 60; then
164 | MARCH2=$(whiptail --title "CPU Architecture" --inputbox "Enter CPU type (MARCH):" 10 60 "$MARCH2" 3>&1 1>&2 2>&3)
165 | fi
166 | }
167 |
168 |
169 | kernel_configuration() {
170 | local options=(
171 | "linux-cachyos" "Use BORE + Cachy Sauce configuration" OFF
172 | "linux-cachyos-bore" "Use BORE configuration" OFF
173 | )
174 |
175 | local num_items=$(( ${#options[@]} / 3 ))
176 |
177 | local i=0
178 | while [ $i -lt $num_items ]; do
179 | if [[ "${options[i]}" == "$_selected_kernel_config" ]]; then
180 | options[i+2]="ON"
181 | fi
182 | i=$((i + 3))
183 | done
184 |
185 | local selection
186 | if ! selection=$(whiptail --title "Kernel Configuration" --radiolist \
187 | "Select kernel configuration:" 20 78 $num_items \
188 | "${options[@]}" 3>&1 1>&2 2>&3); then
189 | echo "Kernel configuration canceled or failed."
190 | _selected_kernel_config="none"
191 | return 1
192 | fi
193 |
194 | if [[ -n "$selection" ]]; then
195 | selection="${selection//\"/}"
196 | _selected_kernel_config="$selection"
197 | echo "Selected configurations: $selection"
198 | else
199 | echo "No configurations selected, defaulting to none."
200 | _selected_kernel_config="none"
201 | fi
202 | }
203 |
204 |
205 | fetch_patch_list() {
206 | local patch_list
207 | local cachyos_patches_url="https://raw.githubusercontent.com/CachyOS/kernel-patches/refs/heads/master/${_major}.${_mid}/all/"
208 |
209 | patch_list=$(wget -qO- "https://api.github.com/repos/CachyOS/kernel-patches/contents/${_major}.${_mid}/all" | jq -r '.[].name')
210 |
211 | echo "Debug: Raw Patch List -> $patch_list"
212 |
213 | for patch_file in $patch_list; do
214 | patch_key="${patch_file%.patch}"
215 | patch_key=$(echo "$patch_key" | tr -d '\r')
216 | patch_map["$patch_key"]="$patch_file"
217 | done
218 |
219 | echo "Debug: patch_map contents ->"
220 | for key in "${!patch_map[@]}"; do
221 | echo " $key -> ${patch_map[$key]}"
222 | done
223 |
224 | echo "Debug: _cachyos_patch_selection contains: ${_cachyos_patch_selection[*]}"
225 |
226 | local options=()
227 | for patch_key in "${!patch_map[@]}"; do
228 | options+=("$patch_key" "Enable ${patch_key^} Patch" "OFF")
229 | done
230 |
231 | if [[ ${#options[@]} -eq 0 ]]; then
232 | echo "Error: No patches found!"
233 | exit 1
234 | fi
235 |
236 | local selection
237 | selection=$(whiptail --title "Configure Kernel Patches" --checklist \
238 | "Select the patches to apply (use space to select):" 20 78 14 \
239 | "${options[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
240 |
241 | if [[ -z "$selection" ]]; then
242 | echo "No patches selected."
243 | return
244 | fi
245 |
246 | IFS=' ' read -r -a _cachyos_patch_selection <<< "$selection"
247 |
248 | echo "Selected patches: ${_cachyos_patch_selection[*]}"
249 |
250 | for patch_key in "${_cachyos_patch_selection[@]}"; do
251 | patch_key=$(echo "$patch_key" | tr -d '\r')
252 |
253 | echo "Debug: Checking patch_map[$patch_key]"
254 |
255 | if [[ -n "${patch_map[$patch_key]:-}" ]]; then
256 | echo "Patch found: ${patch_map[$patch_key]}"
257 | else
258 | echo "Error: patch_map[$patch_key] is unassigned!"
259 | echo "Known keys: ${!patch_map[*]}"
260 | exit 1
261 | fi
262 | done
263 | }
264 |
265 |
266 | configure_kernel_patches() {
267 | echo "DEBUG: Entering configure_kernel_patches()"
268 |
269 | fetch_patch_list
270 |
271 | if [[ ${#patch_map[@]} -eq 0 ]]; then
272 | echo "ERROR: No patches found. Exiting."
273 | return 1
274 | fi
275 |
276 | if [[ ${#_cachyos_patch_selection[@]} -gt 0 ]]; then
277 | echo "DEBUG: Previous selection detected. Skipping menu."
278 | return 0
279 | fi
280 |
281 | local options=()
282 | for patch_key in "${!patch_map[@]}"; do
283 | options+=("$patch_key" "Enable ${patch_key^} Patch" "OFF")
284 | done
285 |
286 | echo "DEBUG: Before whiptail, _cachyos_patch_selection = ${_cachyos_patch_selection[*]}"
287 |
288 | local selection
289 | selection=$(whiptail --title "Configure Kernel Patches" --checklist \
290 | "Select the patches to apply (use space to select):" 20 78 14 \
291 | "${options[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
292 |
293 | if [[ -n "$selection" ]]; then
294 | IFS=' ' read -r -a _cachyos_patch_selection <<< "$selection"
295 | echo "DEBUG: Selected patches: ${_cachyos_patch_selection[*]}"
296 | else
297 | echo "DEBUG: No patches selected. Keeping previous selection: ${_cachyos_patch_selection[*]}"
298 | fi
299 |
300 | return 0
301 | }
302 |
303 |
304 | configure_cpusched() {
305 | local sched_bore_cachy_status
306 | local sched_bore_status
307 | local sched_prjc_cachy_status
308 | local none_status
309 |
310 | sched_bore_cachy_status=$( [ "$_cpusched_selection" = "bore-cachy" ] && echo "ON" || echo "OFF" )
311 | sched_bore_status=$( [ "$_cpusched_selection" = "bore" ] && echo "ON" || echo "OFF" )
312 | sched_prjc_cachy_status=$( [ "$_cpusched_selection" = "prjc-cachy" ] && echo "ON" || echo "OFF" )
313 | none_status=$( [ "$_cpusched_selection" = "none" ] && echo "ON" || echo "OFF" )
314 |
315 | _cpusched_selection=$(whiptail --title "CPU Scheduler Configuration" --radiolist \
316 | "Choose CPU Scheduler (use space to select):" 20 60 7 \
317 | "bore-cachy" "Use BORE+Cachy Sauce scheduler" "$sched_bore_cachy_status" \
318 | "bore" "Use BORE scheduler" "$sched_bore_status" \
319 | "prjc-cachy" "Use BMQ/PDS scheduler" "$sched_prjc_cachy_status" \
320 | "none" "Do not configure CPU scheduler" "$none_status" \
321 | 3>&1 1>&2 2>&3)
322 | }
323 |
324 |
325 | configure_llvm_lto() {
326 | local thin_status
327 | local full_status
328 | local none_status
329 |
330 | thin_status=$( [ "$_llvm_lto_selection" = "thin" ] && echo "ON" || echo "OFF" )
331 | full_status=$( [ "$_llvm_lto_selection" = "full" ] && echo "ON" || echo "OFF" )
332 | none_status=$( [ "$_llvm_lto_selection" = "none" ] && echo "ON" || echo "OFF" )
333 |
334 | _llvm_lto_selection=$(whiptail --title "LLVM LTO Configuration" --radiolist \
335 | "Choose LLVM LTO (use space to select):" 15 60 3 \
336 | "thin" "Use LLVM LTO Thin" "$thin_status" \
337 | "full" "Use LLVM LTO Full" "$full_status" \
338 | "none" "Do not configure LLVM LTO" "$none_status" \
339 | 3>&1 1>&2 2>&3)
340 | }
341 |
342 |
343 | configure_tick_rate() {
344 | local tick_rate_100
345 | local tick_rate_250
346 | local tick_rate_500
347 | local tick_rate_600
348 | local tick_rate_750
349 | local tick_rate_1000
350 |
351 | tick_rate_100=$( [ "$_tick_rate" = "100" ] && echo "ON" || echo "OFF" )
352 | tick_rate_250=$( [ "$_tick_rate" = "250" ] && echo "ON" || echo "OFF" )
353 | tick_rate_500=$( [ "$_tick_rate" = "500" ] && echo "ON" || echo "OFF" )
354 | tick_rate_600=$( [ "$_tick_rate" = "600" ] && echo "ON" || echo "OFF" )
355 | tick_rate_750=$( [ "$_tick_rate" = "750" ] && echo "ON" || echo "OFF" )
356 | tick_rate_1000=$( [ "$_tick_rate" = "1000" ] && echo "ON" || echo "OFF" )
357 |
358 | _tick_rate=$(whiptail --title "Tick Rate Configuration" --radiolist \
359 | "Choose Tick Rate (use space to select):" 15 60 6 \
360 | "100" "100 Hz" "$tick_rate_100" \
361 | "250" "250 Hz" "$tick_rate_250" \
362 | "500" "500 Hz" "$tick_rate_500" \
363 | "600" "600 Hz" "$tick_rate_600" \
364 | "750" "750 Hz" "$tick_rate_750" \
365 | "1000" "1000 Hz" "$tick_rate_1000" \
366 | 3>&1 1>&2 2>&3)
367 | }
368 |
369 |
370 | configure_tick_type() {
371 | local tick_type_periodic
372 | local tick_type_nohz_full
373 | local tick_type_nohz_idle
374 |
375 | tick_type_periodic=$( [ "$_tick_type" = "periodic" ] && echo "ON" || echo "OFF" )
376 | tick_type_nohz_full=$( [ "$_tick_type" = "nohz_full" ] && echo "ON" || echo "OFF" )
377 | tick_type_nohz_idle=$( [ "$_tick_type" = "nohz_idle" ] && echo "ON" || echo "OFF" )
378 |
379 | _tick_type=$(whiptail --title "Tick Type Configuration" --radiolist \
380 | "Choose Tick Type (use space to select):" 15 60 3 \
381 | "periodic" "Periodic tick" "$tick_type_periodic" \
382 | "nohz_full" "Full dynticks" "$tick_type_nohz_full" \
383 | "nohz_idle" "Idle dynticks" "$tick_type_nohz_idle" \
384 | 3>&1 1>&2 2>&3)
385 | }
386 |
387 |
388 | configure_nr_cpus() {
389 | _nr_cpus=$(whiptail --title "NR_CPUS Configuration" --inputbox "Enter NR_CPUS value:" 10 60 "$_nr_cpus" 3>&1 1>&2 2>&3)
390 | }
391 |
392 |
393 | configure_hugepages() {
394 | local hugepage_always
395 | local hugepage_madvise
396 | local hugepage_no
397 |
398 | hugepage_always=$( [ "$_hugepage" = "always" ] && echo "ON" || echo "OFF" )
399 | hugepage_madvise=$( [ "$_hugepage" = "madvise" ] && echo "ON" || echo "OFF" )
400 | hugepage_no=$( [ "$_hugepage" = "no" ] && echo "ON" || echo "OFF" )
401 |
402 | _hugepage=$(whiptail --title "Hugepages Configuration" --radiolist \
403 | "Choose Hugepages (use space to select):" 15 60 3 \
404 | "always" "Always use hugepages" "$hugepage_always" \
405 | "madvise" "Use hugepages with madvise" "$hugepage_madvise" \
406 | "no" "Do not configure Hugepages" "$hugepage_no" \
407 | 3>&1 1>&2 2>&3)
408 | }
409 |
410 |
411 | configure_lru() {
412 | local lru_standard
413 | local lru_stats
414 | local lru_none
415 |
416 | lru_standard=$( [ "$_lru_config" = "standard" ] && echo "ON" || echo "OFF" )
417 | lru_stats=$( [ "$_lru_config" = "stats" ] && echo "ON" || echo "OFF" )
418 | lru_none=$( [ "$_lru_config" = "none" ] && echo "ON" || echo "OFF" )
419 |
420 | _lru_config=$(whiptail --title "LRU Configuration" --radiolist \
421 | "Choose LRU (use space to select):" 15 60 3 \
422 | "standard" "Standard LRU" "$lru_standard" \
423 | "stats" "LRU with stats" "$lru_stats" \
424 | "none" "Do not configure LRU" "$lru_none" \
425 | 3>&1 1>&2 2>&3)
426 | }
427 |
428 |
429 | configure_preempt_type() {
430 | local preempt_voluntary
431 | local preempt_preempt
432 | local preempt_none
433 |
434 | preempt_voluntary=$( [ "$_preempt" = "voluntary" ] && echo "ON" || echo "OFF" )
435 | preempt_preempt=$( [ "$_preempt" = "preempt" ] && echo "ON" || echo "OFF" )
436 | preempt_none=$( [ "$_preempt" = "none" ] && echo "ON" || echo "OFF" )
437 |
438 | _preempt=$(whiptail --title "Preempt Type Configuration" --radiolist \
439 | "Choose Preempt Type (use space to select):" 15 60 4 \
440 | "voluntary" "Voluntary Preemption" "$preempt_voluntary" \
441 | "preempt" "Preemptible Kernel (Low-Latency Desktop)" "$preempt_preempt" \
442 | "none" "No Forced Preemption" "$preempt_none" \
443 | 3>&1 1>&2 2>&3)
444 |
445 | case "$_preempt" in
446 | voluntary)
447 | _preempt="voluntary"
448 | ;;
449 | preempt)
450 | _preempt="preempt"
451 | ;;
452 | none)
453 | _preempt="none"
454 | ;;
455 | esac
456 | }
457 |
458 |
459 | configure_system_optimizations() {
460 | local o3_status
461 | local performance_governor_status
462 | local vma_status
463 | local damon_status
464 | local numa_status
465 |
466 | o3_status=$([ "$_o3_optimization" = "yes" ] && echo "ON" || echo "OFF")
467 | performance_governor_status=$([ "$_performance_governor" = "enable" ] && echo "ON" || echo "OFF")
468 | vma_status=$([ "$_vma" = "yes" ] && echo "ON" || echo "OFF")
469 | damon_status=$([ "$_damon" = "yes" ] && echo "ON" || echo "OFF")
470 | numa_status=$([ "$_numa" = "enable" ] && echo "ON" || echo "OFF")
471 |
472 | local selection
473 | selection=$(whiptail --title "System Optimizations Configuration" --checklist \
474 | "Select optimizations to enable:" 20 78 8 \
475 | "GCC -O3 Optimizations" "" "$o3_status" \
476 | "Enable Performance Governor" "" "$performance_governor_status" \
477 | "Enable VMA Optimizations" "" "$vma_status" \
478 | "Enable DAMON" "" "$damon_status" \
479 | "Enable NUMA" "" "$numa_status" \
480 | 3>&1 1>&2 2>&3)
481 |
482 | _o3_optimization=$( echo "$selection" | grep -q "GCC -O3 Optimizations" && echo "yes" || echo "no" )
483 | _performance_governor=$( echo "$selection" | grep -q "Enable Performance Governor" && echo "enable" || echo "no" )
484 | _vma=$( echo "$selection" | grep -q "Enable VMA Optimizations" && echo "yes" || echo "no" )
485 | _damon=$( echo "$selection" | grep -q "Enable DAMON" && echo "yes" || echo "no" )
486 | _numa=$( echo "$selection" | grep -q "Enable NUMA" && echo "enable" || echo "disable" )
487 | }
488 |
489 |
490 | select_kernel_version() {
491 | local kernel_data
492 | kernel_data=$(curl -s https://www.kernel.org/releases.json)
493 |
494 | local kernel_versions
495 | kernel_versions=$(echo "$kernel_data" | jq -r '.releases[] | select(.moniker == "stable") | .version' | sort -Vr)
496 |
497 | if [[ -z "$kernel_versions" ]]; then
498 | echo "Failed to fetch kernel versions from kernel.org."
499 | exit 1
500 | fi
501 |
502 | local options=()
503 | while IFS= read -r version; do
504 | options+=("$version" "Kernel version $version" OFF)
505 | done <<< "$kernel_versions"
506 |
507 | local selection
508 | selection=$(whiptail --title "Kernel Version Selection" --radiolist \
509 | "Select the kernel version to download:" 20 78 10 \
510 | "${options[@]}" 3>&1 1>&2 2>&3)
511 |
512 | if [[ -n "$selection" ]]; then
513 | echo "Selected kernel version: $selection"
514 | _kernel_version="$selection"
515 | _kv_url="https://cdn.kernel.org/pub/linux/kernel/v${_kernel_version%%.*}.x/linux-${_kernel_version}.tar.xz"
516 | _kv_name="linux-${_kernel_version}"
517 | else
518 | echo "No kernel version selected. Using the latest version."
519 | _kv_url=$(echo "$kernel_data" | jq -r '.latest_stable.source')
520 | _kv_name=$(basename "$_kv_url" .tar.xz)
521 | _kernel_version="${_kv_name#linux-}"
522 | fi
523 |
524 | _major="${_kernel_version%%.*}"
525 | _mid="${_kernel_version#*.}"
526 | _mid="${_mid%%.*}"
527 |
528 | echo "Kernel version: $_kernel_version (Major: $_major, Mid: $_mid)"
529 |
530 | if [[ -d "$_kv_name" ]]; then
531 | echo "Removing existing kernel source directory: $_kv_name"
532 | rm -rf "$_kv_name"
533 | fi
534 |
535 | if [[ ! -f "${_kv_name}.tar.xz" ]]; then
536 | echo "Downloading kernel source: $_kv_url"
537 | wget -c "$_kv_url" -O "${_kv_name}.tar.xz" || {
538 | echo "Error: Failed to download kernel source."
539 | exit 1
540 | }
541 | else
542 | echo "Kernel source archive already exists: ${_kv_name}.tar.xz"
543 | fi
544 |
545 | echo "Extracting kernel source..."
546 | tar -xf "${_kv_name}.tar.xz" || {
547 | echo "Error: Failed to extract kernel source."
548 | exit 1
549 | }
550 |
551 | cd "$_kv_name" || {
552 | echo "Error: Failed to enter the kernel source directory $_kv_name."
553 | exit 1
554 | }
555 |
556 | echo "Kernel source setup complete."
557 | }
558 |
559 |
560 | apply_kernel_configuration() {
561 | echo "Starting kernel configuration process..."
562 |
563 | local _major
564 | local _mid
565 |
566 | _major="${_kernel_version%%.*}"
567 | _mid="${_kernel_version#*.}"
568 | _mid="${_mid%%.*}"
569 |
570 | local base_url="https://raw.githubusercontent.com/CachyOS/linux-cachyos/refs/heads/${_major}.${_mid}"
571 | local config_suffix="$_selected_kernel_config"
572 | local config_url="${base_url}/${config_suffix}/config"
573 |
574 | echo "Config URL: $config_url"
575 | if ! wget -c "$config_url" -O .config; then
576 | echo "Failed to download the kernel configuration."
577 | return 1
578 | fi
579 |
580 |
581 | # -- Apply CachyOS patches with auto-fix mechanism.
582 |
583 | if [[ ${#_cachyos_patch_selection[@]} -eq 0 ]]; then
584 | echo "Fetching patches..."
585 | fetch_patch_list
586 | else
587 | echo "Skipping patch selection, using previous selection: ${_cachyos_patch_selection[*]}"
588 | fi
589 |
590 | local cachyos_patches_url="https://raw.githubusercontent.com/CachyOS/kernel-patches/refs/heads/master/${_major}.${_mid}/all/"
591 |
592 | for patch_key in "${_cachyos_patch_selection[@]}"; do
593 | patch_file="${patch_map[$patch_key]}"
594 | if [[ ! -v patch_map[$patch_key] ]]; then
595 | echo "Unknown patch: $patch_key"
596 | continue
597 | fi
598 |
599 | echo "Applying patch: $patch_file"
600 | if ! wget -qO- "${cachyos_patches_url}${patch_file}" | patch -p1; then
601 | echo "Failed to apply patch: $patch_file"
602 | whiptail --title "Patch Application Error" --msgbox "Failed to apply the patch: $patch_file" 10 60
603 | return 1
604 | fi
605 |
606 | if [[ "$patch_key" == "0001-cachyos-base-all" ]]; then
607 | scripts/config -e CONFIG_CACHY
608 | fi
609 | done
610 |
611 |
612 | # -- Apply scheduler patches with auto-fix mechanism.
613 |
614 | local sched_patch_base_url="https://raw.githubusercontent.com/CachyOS/kernel-patches/refs/heads/master/${_major}.${_mid}/sched/"
615 | local patch_files=()
616 |
617 | case "$_cpusched_selection" in
618 | "bore-cachy") patch_files=("0001-bore-cachy.patch") ;;
619 | "bore") patch_files=("0001-bore.patch") ;;
620 | "prjc-cachy") patch_files=("0001-prjc-cachy.patch") ;;
621 | "none")
622 | echo "No CPU scheduler selected for patching."
623 | return 0
624 | ;;
625 | *)
626 | echo "Unknown CPU scheduler: $_cpusched_selection"
627 | return 1
628 | ;;
629 | esac
630 |
631 | for patch_file in "${patch_files[@]}"; do
632 | echo "Applying scheduler patch: $patch_file"
633 |
634 | wget -qO "$patch_file" "${sched_patch_base_url}${patch_file}"
635 |
636 | if ! patch -p1 < "$patch_file"; then
637 | echo "Failed to download and apply the patch: $patch_file"
638 | whiptail --title "Patch Application Error" --msgbox "Failed to download or apply the patch: $patch_file" 10 60
639 | return 1
640 | fi
641 | done
642 |
643 |
644 | # -- Apply the user selections to the kernel configuration.
645 |
646 | case "$_cpusched_selection" in
647 | bore-cachy)
648 | scripts/config -e SCHED_BORE -e SCHED_CLASS_EXT
649 | ;;
650 | bore )
651 | scripts/config -e SCHED_BORE
652 | ;;
653 | prjc-cachy)
654 | scripts/config -e SCHED_ALT -e SCHED_BMQ
655 | ;;
656 | esac
657 |
658 | case "$_preempt" in
659 | preempt)
660 | scripts/config -e PREEMPT_BUILD -d PREEMPT_NONE -d PREEMPT_VOLUNTARY -e PREEMPT -e PREEMPT_COUNT -e PREEMPTION -e PREEMPT_DYNAMIC
661 | ;;
662 | voluntary)
663 | scripts/config -e PREEMPT_BUILD -d PREEMPT_NONE -e PREEMPT_VOLUNTARY -d PREEMPT -e PREEMPT_COUNT -e PREEMPTION -d PREEMPT_DYNAMIC
664 | ;;
665 | server)
666 | scripts/config -e PREEMPT_NONE_BUILD -e PREEMPT_NONE -d PREEMPT_VOLUNTARY -d PREEMPT -d PREEMPTION -d PREEMPT_DYNAMIC
667 | ;;
668 | none)
669 | ;;
670 | esac
671 |
672 | case "$_llvm_lto_selection" in
673 | thin)
674 | scripts/config -e LTO_CLANG_THIN
675 | ;;
676 | full)
677 | scripts/config -e LTO_CLANG_FULL
678 | ;;
679 | none)
680 | scripts/config -d LTO_CLANG_THIN -d LTO_CLANG_FULL
681 | ;;
682 | esac
683 |
684 | case "$_tick_rate" in
685 | 100 | 250 | 300 | 500 | 600 | 750 | 1000)
686 | scripts/config -d HZ_100 -d HZ_250 -d HZ_300 -d HZ_500 -d HZ_600 -d HZ_750 -d HZ_1000
687 | scripts/config -e "HZ_${_tick_rate}" --set-val HZ "${_tick_rate}"
688 | ;;
689 | esac
690 |
691 | case "$_tick_type" in
692 | periodic)
693 | scripts/config -d NO_HZ_IDLE -d NO_HZ_FULL -d NO_HZ -d NO_HZ_COMMON -e HZ_PERIODIC
694 | ;;
695 | nohz_full)
696 | scripts/config -d HZ_PERIODIC -e NO_HZ_FULL -e NO_HZ -e NO_HZ_COMMON -e CONTEXT_TRACKING
697 | ;;
698 | nohz_idle)
699 | scripts/config -d HZ_PERIODIC -e NO_HZ_IDLE -e NO_HZ -e NO_HZ_COMMON
700 | ;;
701 | esac
702 |
703 | case "$_numa" in
704 | enable)
705 | scripts/config -e NUMA
706 | ;;
707 | disable)
708 | scripts/config -d NUMA
709 | ;;
710 | none)
711 | ;;
712 | esac
713 |
714 | case "$_hugepage" in
715 | always)
716 | scripts/config -d TRANSPARENT_HUGEPAGE_MADVISE -e TRANSPARENT_HUGEPAGE_ALWAYS
717 | ;;
718 | madvise)
719 | scripts/config -d TRANSPARENT_HUGEPAGE_ALWAYS -e TRANSPARENT_HUGEPAGE_MADVISE
720 | ;;
721 | no)
722 | ;;
723 | esac
724 |
725 | scripts/config --set-val NR_CPUS "$_nr_cpus"
726 |
727 | case "$_lru_config" in
728 | standard)
729 | scripts/config -e LRU_GEN -e LRU_GEN_ENABLED -d LRU_GEN_STATS
730 | ;;
731 | stats)
732 | scripts/config -e LRU_GEN -e LRU_GEN_ENABLED -e LRU_GEN_STATS
733 | ;;
734 | none)
735 | scripts/config -d LRU_GEN
736 | ;;
737 | esac
738 |
739 | if [[ "$_o3_optimization" == "yes" ]]; then
740 | scripts/config -d CC_OPTIMIZE_FOR_PERFORMANCE -e CC_OPTIMIZE_FOR_PERFORMANCE_O3
741 | fi
742 |
743 | if [[ "$_performance_governor" == "enable" ]]; then
744 | scripts/config -d CPU_FREQ_DEFAULT_GOV_SCHEDUTIL -e CPU_FREQ_DEFAULT_GOV_PERFORMANCE
745 | fi
746 |
747 | echo "----------------------------------"
748 | echo "| APPLYING AUTO-CPU-OPTIMIZATION |"
749 | echo "----------------------------------"
750 | echo "[*] DETECTED CPU (MARCH) : ${MARCH2}"
751 |
752 | _march=$MARCH2
753 |
754 | scripts/config --disable CONFIG_GENERIC_CPU
755 | scripts/config --enable CONFIG_"${_march^^}"
756 |
757 | _move_config_up="$(pwd)/.config"
758 |
759 | mv "$_move_config_up" ../
760 |
761 | echo "Kernel configuration successfully applied."
762 | cd -
763 | }
764 |
765 |
766 | customize_kernel_extraname() {
767 | local new_suffix
768 | new_suffix=$(whiptail --inputbox "Enter suffix for kernel version:" 10 60 3>&1 1>&2 2>&3)
769 |
770 | if [[ -n $new_suffix ]]; then
771 | if [[ -d "$_kv_name" ]]; then
772 | echo "Updating EXTRAVERSION in Makefile..."
773 | cd "$_kv_name" || {
774 | whiptail --title "Error" --msgbox "Failed to enter the kernel directory." 10 60
775 | return 1
776 | }
777 |
778 | if grep -q '^EXTRAVERSION =' Makefile; then
779 | echo "Current EXTRAVERSION: $(grep '^EXTRAVERSION =' Makefile)"
780 | if grep -q '^EXTRAVERSION = *$' Makefile; then
781 | sed -i "s/^EXTRAVERSION = *$/EXTRAVERSION = -${new_suffix}/" Makefile
782 | else
783 | sed -i "s/^EXTRAVERSION = .*/EXTRAVERSION = -${new_suffix}/" Makefile
784 | fi
785 | else
786 | echo "EXTRAVERSION not found in Makefile. Adding it..."
787 | echo "EXTRAVERSION = -${new_suffix}" >> Makefile
788 | fi
789 |
790 | echo "Updated EXTRAVERSION to: $(grep '^EXTRAVERSION =' Makefile)"
791 | echo "Kernel version updated to $(make kernelversion)."
792 |
793 | cd -
794 | else
795 | whiptail --title "Error" --msgbox "Directory '$_kv_name' does not exist." 10 60
796 | fi
797 | else
798 | echo "Operation canceled."
799 | fi
800 | }
801 |
802 |
803 | show_options() {
804 | local custom_extraversion
805 | custom_extraversion=$(grep -oP '^EXTRAVERSION = \K.*' "${_kv_name}/Makefile" || true)
806 |
807 | if [[ -z $custom_extraversion ]]; then
808 | custom_extraversion="$_custom_extraversion"
809 | fi
810 |
811 | custom_extraversion="${custom_extraversion#-}"
812 | local modified_kernel_version="${_kv_name}-${custom_extraversion}"
813 |
814 | local patch_list
815 | patch_list=$(wget -qO- "https://api.github.com/repos/CachyOS/kernel-patches/contents/${_major}.${_mid}/all" | jq -r '.[].name')
816 |
817 | declare -A patch_descriptions
818 | for patch_file in $patch_list; do
819 | patch_key="${patch_file%.patch}"
820 | patch_descriptions["$patch_key"]="Enable ${patch_key^} Patch"
821 | done
822 |
823 | local selected_patches
824 | if [[ ${#_cachyos_patch_selection[@]} -gt 0 ]]; then
825 | local patch_descriptions_list=()
826 | for patch_key in "${_cachyos_patch_selection[@]}"; do
827 | patch_descriptions_list+=("${patch_descriptions[$patch_key]}")
828 | done
829 | selected_patches=$(printf ", %s" "${patch_descriptions_list[@]}")
830 | selected_patches=${selected_patches:2}
831 | else
832 | selected_patches="None"
833 | fi
834 |
835 | whiptail --title "Configuration Summary" --scrolltext --msgbox "
836 | Kernel (latest from kernel.org): $_kv_name
837 |
838 | CPU Architecture: $_march
839 | Selected Config: $_selected_kernel_config
840 |
841 | Applied Patches: $selected_patches
842 |
843 | CPU Scheduler: $_cpusched_selection
844 | LLVM LTO: $_llvm_lto_selection
845 | Tick Rate: $_tick_rate
846 | Tick Type: $_tick_type
847 | NR_CPUS: $_nr_cpus
848 | Hugepages: $_hugepage
849 | LRU Config: $_lru_config
850 | Preempt Type: $_preempt
851 |
852 | O3 Optimization: $_o3_optimization
853 | Performance Governor: $_performance_governor
854 | VMA: $_vma
855 | DAMON: $_damon
856 | NUMA: $_numa
857 |
858 | Custom Kernel Name: $modified_kernel_version
859 | " 30 78
860 | }
861 |
862 |
863 | create_debian_packages() {
864 | echo "Compiling $_kv_name..."
865 |
866 | cd "$_kv_name" || { echo "Failed to enter the kernel directory."; return 1; }
867 |
868 | # -- WARNING: Below is a very ugly "hack." For some reason, executing the command make—j"$(nproc)" immediately causes the .config file to revert to the original, non-patched file.
869 | # -- ====== Thus, to work around this problem, I figured that we need to move the file out of the source directory after applying the patches, then copy it back, execute make again so that .config.old is created, and .config is reverted, and then terminate the process, but not right away; we have to wait.
870 | # -- ======= Then delete the generated .config.old and .config, wait a bit, move the patched .config back to the source directory, wait a bit, and compile the kernel.
871 |
872 | cp ../.config .
873 |
874 | make >/dev/null 2>&1 & _make_pid=$!
875 | sleep 3
876 | kill $_make_pid 2>/dev/null
877 |
878 | [ -e "$(pwd)/.config" ] && rm "$(pwd)/.config"
879 | [ -e "$(pwd)/.config.old" ] && rm "$(pwd)/.config.old"
880 |
881 | sleep 3
882 |
883 | mv ../.config .
884 |
885 | sleep 3
886 |
887 | # -- End of ugly "hack."
888 |
889 | echo "Creating Debian packages..."
890 |
891 | KDEB_NO_SOURCE_PACKAGE=1 NO_SOURCE=1 make -j"$(nproc)" bindeb-pkg
892 |
893 | echo "Packages succesfully built."
894 |
895 | cd -
896 | }
897 |
898 | # ====== START ======
899 |
900 | # -- Flag parsing.
901 |
902 | if [ "$#" -gt 0 ]; then
903 | case "$1" in
904 | --help | -h)
905 | echo "Usage: $0"
906 | echo "Compile a Linux kernel with CachyOS patches and package it into a .deb file for distribution."
907 | exit 0
908 | ;;
909 | esac
910 | fi
911 |
912 |
913 | # -- Run the check_deps function and store the result in dep_status.
914 |
915 | check_deps
916 |
917 |
918 | # -- Ask for user confirmation.
919 |
920 | whiptail --title "CachyOS Kernel Builder for Debian-based Distributions" --msgbox "Welcome to the CachyOS Kernel Builder for Debian-based Distributions\n\nLicensed under the BSD-3-Clause license — ©$(date +%Y) Nitrux Latinoamericana S.C." 10 88
921 | whiptail --title "Secure Boot Warning" --yesno "CachyOS Kernel Builder will generate unsigned kernels incompatible with Secure Boot.\nDo you want to continue?" 8 88
922 |
923 |
924 | # -- Prompt the user to select a kernel version.
925 |
926 | select_kernel_version
927 |
928 | echo "Downloading kernel: $_kv_url"
929 |
930 |
931 | # -- Run main function.
932 |
933 | init_script
934 |
935 |
936 | # -- Main menu.
937 |
938 | while true; do
939 | CHOICE=$(whiptail --title "Kernel Configuration Menu" --menu "Choose an option (use arrows and Enter to navigate)" 25 78 17 \
940 | "1" "Choose Kernel Configuration" \
941 | "2" "Configure Kernel Patches" \
942 | "3" "Configure CPU Scheduler" \
943 | "4" "Configure LLVM LTO" \
944 | "5" "Configure Tick Rate" \
945 | "6" "Configure Tick Type" \
946 | "7" "Configure NR_CPUS" \
947 | "8" "Configure Hugepages" \
948 | "9" "Configure LRU" \
949 | "10" "Configure Preempt Type" \
950 | "11" "Configure System Optimizations" \
951 | "12" "Apply Kernel Configuration and Patches" \
952 | "13" "Customize Kernel Name" \
953 | "14" "Show Current Configuration" \
954 | "15" "Create Debian Packages" \
955 | "16" "Exit" 3>&1 1>&2 2>&3)
956 |
957 | exitstatus=$?
958 | if [[ $exitstatus -ne 0 ]]; then
959 | break
960 | fi
961 |
962 | case $CHOICE in
963 | 1) kernel_configuration ;;
964 | 2) configure_kernel_patches ;;
965 | 3) configure_cpusched ;;
966 | 4) configure_llvm_lto ;;
967 | 5) configure_tick_rate ;;
968 | 6) configure_tick_type ;;
969 | 7) configure_nr_cpus ;;
970 | 8) configure_hugepages ;;
971 | 9) configure_lru ;;
972 | 10) configure_preempt_type ;;
973 | 11) configure_system_optimizations ;;
974 | 12) apply_kernel_configuration ;;
975 | 13) customize_kernel_extraname ;;
976 | 14) show_options ;;
977 | 15) create_debian_packages ;;
978 | 16) break ;;
979 | *) echo "Invalid Option" ;;
980 | esac
981 | done
982 |
983 | # ====== END ======
984 |
--------------------------------------------------------------------------------