├── .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 | CachyOS logo 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 | --------------------------------------------------------------------------------