mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
- Add 'make configure' target to Makefile alongside menuconfig, config, tui, nconfig - Implement Linux Kbuild dynamic source selection based on .config - Add compiler optimization level selection (-O2, -O3, -Os, -O0) in menuconfig.py - Support interactive curses navigation with save/exit/default hotkeys - Automatically generate .config and include/config/autoconf.h
424 lines
17 KiB
Python
Executable File
424 lines
17 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
SUB-OS Linux-Style Interactive Kconfig Menuconfig (TUI)
|
|
Provides a full curses-based terminal configuration UI matching Linux menuconfig.
|
|
Generates .config and include/config/autoconf.h.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import curses
|
|
|
|
CONFIG_FILE = ".config"
|
|
AUTOCONF_HEADER = "include/config/autoconf.h"
|
|
|
|
DEFAULTS = {
|
|
# Architecture
|
|
"CONFIG_ARCH": "x86_64",
|
|
"CONFIG_ARCH_X86_64": True,
|
|
"CONFIG_ARCH_AARCH64": False,
|
|
"CONFIG_ARCH_ARMV8I": False,
|
|
|
|
# General Setup
|
|
"CONFIG_SUBOS_HOSTNAME": "sub-os",
|
|
"CONFIG_SUBOS_VERSION": "0.2.0-lts",
|
|
"CONFIG_SMP": True,
|
|
"CONFIG_PREEMPT": True,
|
|
"CONFIG_OPTIMIZATION": "-O2",
|
|
|
|
# Memory Management
|
|
"CONFIG_MM_PMM": True,
|
|
"CONFIG_MM_SLAB": True,
|
|
"CONFIG_MM_VMA": True,
|
|
|
|
# Filesystems
|
|
"CONFIG_FS_VFS": True,
|
|
"CONFIG_FS_FAT32": True,
|
|
"CONFIG_FS_EXT2": True,
|
|
"CONFIG_FS_RAMFS": True,
|
|
"CONFIG_FS_DEVFS": True,
|
|
"CONFIG_FS_PROCFS": True,
|
|
"CONFIG_FS_SYSFS": True,
|
|
|
|
# Storage Drivers
|
|
"CONFIG_DRV_NVME": True,
|
|
"CONFIG_DRV_AHCI": True,
|
|
"CONFIG_DRV_ATA": True,
|
|
"CONFIG_DRV_VIRTIO_BLK": True,
|
|
"CONFIG_DRV_RAMDISK": True,
|
|
|
|
# Network Drivers & Stack
|
|
"CONFIG_NET_STACK": True,
|
|
"CONFIG_DRV_E1000": True,
|
|
"CONFIG_DRV_RTL8139": True,
|
|
"CONFIG_DRV_VIRTIO_NET": True,
|
|
"CONFIG_NET_HTTPD": True,
|
|
"CONFIG_NET_SSHD": True,
|
|
"CONFIG_NET_FILTER": True,
|
|
|
|
# Audio & Display
|
|
"CONFIG_DRV_SOUND_HDA": True,
|
|
"CONFIG_DRV_SOUND_AC97": True,
|
|
"CONFIG_DRV_BOCHS_VBE": True,
|
|
"CONFIG_DRV_CANVAS_2D": True,
|
|
|
|
# Bus, Sensors & Crypto
|
|
"CONFIG_DRV_USB_XHCI": True,
|
|
"CONFIG_DRV_HWMON": True,
|
|
"CONFIG_DRV_VIRTIO_RNG": True,
|
|
"CONFIG_DRV_PTY": True,
|
|
|
|
# Security & Advanced
|
|
"CONFIG_SECURITY_LSM": True,
|
|
"CONFIG_SECURITY_KEYRING": True,
|
|
"CONFIG_BPF_VM": True,
|
|
"CONFIG_IO_URING": True,
|
|
"CONFIG_USERLAND_LAZYBOX": True,
|
|
}
|
|
|
|
MENU_STRUCTURE = [
|
|
{
|
|
"title": "Target Architecture Selection",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_ARCH_X86_64", "label": "x86_64 (64-Bit AMD64/Intel x86-64)", "type": "radio", "group": "arch", "val": "x86_64"},
|
|
{"name": "CONFIG_ARCH_AARCH64", "label": "aarch64 (ARMv8-A 64-Bit Cortex/Neoverse)", "type": "radio", "group": "arch", "val": "aarch64"},
|
|
{"name": "CONFIG_ARCH_ARMV8I", "label": "armv8i (32-Bit ARM/AArch32 Profile)", "type": "radio", "group": "arch", "val": "armv8i"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Compiler Optimizations & Code Generation",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_OPT_O2", "label": "-O2 (Recommended: High Performance Optimization)", "type": "radio", "group": "opt", "val": "-O2"},
|
|
{"name": "CONFIG_OPT_O3", "label": "-O3 (Aggressive Vectorization & Loop Unrolling)", "type": "radio", "group": "opt", "val": "-O3"},
|
|
{"name": "CONFIG_OPT_OS", "label": "-Os (Optimize for Smallest Binary Footprint)", "type": "radio", "group": "opt", "val": "-Os"},
|
|
{"name": "CONFIG_OPT_O0", "label": "-O0 (Disable Optimizations for GDB Debugging)", "type": "radio", "group": "opt", "val": "-O0"},
|
|
]
|
|
},
|
|
{
|
|
"title": "General Kernel Setup",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_SMP", "label": "Symmetric Multi-Processing (SMP) Support", "type": "bool"},
|
|
{"name": "CONFIG_PREEMPT", "label": "Preemptive Kernel Scheduling Model", "type": "bool"},
|
|
{"name": "CONFIG_BPF_VM", "label": "In-Kernel eBPF Register Virtual Machine", "type": "bool"},
|
|
{"name": "CONFIG_IO_URING", "label": "High-Performance io_uring Ring Buffers", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Memory Management & Object Allocators",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_MM_PMM", "label": "Physical Page Frame Allocator (PMM)", "type": "bool"},
|
|
{"name": "CONFIG_MM_SLAB", "label": "High-Performance SLUB/SLAB Object Cache", "type": "bool"},
|
|
{"name": "CONFIG_MM_VMA", "label": "Virtual Memory Areas (VMA) & mmap Subsystem", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Virtual File Systems & Storage Drivers",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_FS_VFS", "label": "Virtual File System (VFS) Core Subsystem", "type": "bool"},
|
|
{"name": "CONFIG_FS_FAT32", "label": "FAT32 / VFAT File System Driver", "type": "bool"},
|
|
{"name": "CONFIG_FS_EXT2", "label": "Second Extended (EXT2) Linux File System", "type": "bool"},
|
|
{"name": "CONFIG_FS_SYSFS", "label": "Sysfs KObject Virtual Hierarchy (/sys)", "type": "bool"},
|
|
{"name": "CONFIG_DRV_NVME", "label": "NVM Express (NVMe PCIe SSD) Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_AHCI", "label": "AHCI SATA 6Gb/s SSD/HDD Controller Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_ATA", "label": "Legacy IDE/ATA Parallel Storage Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_VIRTIO_BLK", "label": "VirtIO Paravirtualized Block Storage (/dev/vda)", "type": "bool"},
|
|
{"name": "CONFIG_DRV_RAMDISK", "label": "In-Memory Virtual Ramdisk Storage (/dev/ram0)", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Network Subsystem & Hardware Adapters",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_NET_STACK", "label": "TCP/IP Network Stack (IPv4, UDP, TCP)", "type": "bool"},
|
|
{"name": "CONFIG_DRV_E1000", "label": "Intel 82540EM Gigabit Ethernet NIC Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_RTL8139", "label": "Realtek RTL8139 Fast Ethernet NIC Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_VIRTIO_NET", "label": "VirtIO 10-Gigabit Paravirtualized NIC", "type": "bool"},
|
|
{"name": "CONFIG_NET_FILTER", "label": "NetFilter Stateful Packet Firewall (iptables)", "type": "bool"},
|
|
{"name": "CONFIG_NET_HTTPD", "label": "In-Kernel Embedded HTTP REST Web Server", "type": "bool"},
|
|
{"name": "CONFIG_NET_SSHD", "label": "In-Kernel Secure Shell (SSH 2.0) Daemon", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Device Drivers & Multimedia",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_DRV_CANVAS_2D", "label": "2D TrueColor Rasterizer Canvas Graphics Engine", "type": "bool"},
|
|
{"name": "CONFIG_DRV_BOCHS_VBE", "label": "Bochs / VBE Dynamic Resolution Display Adapter", "type": "bool"},
|
|
{"name": "CONFIG_DRV_SOUND_HDA", "label": "Intel High Definition Audio (Azalia HDA) Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_SOUND_AC97", "label": "Analog Devices AC'97 Sound Codec Driver", "type": "bool"},
|
|
{"name": "CONFIG_DRV_USB_XHCI", "label": "USB 3.0 Extensible Host Controller (xHCI)", "type": "bool"},
|
|
{"name": "CONFIG_DRV_HWMON", "label": "HWMON CPU CoreTemp & Fan Tachometer Sensors", "type": "bool"},
|
|
{"name": "CONFIG_DRV_VIRTIO_RNG", "label": "VirtIO True Hardware Random Generator (/dev/hwrng)", "type": "bool"},
|
|
{"name": "CONFIG_DRV_PTY", "label": "Unix98 Pseudo-Terminal (PTY) Subsystem (/dev/pts)", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Security, LSM & Cryptographic Keyrings",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_SECURITY_LSM", "label": "Linux Security Module (LSM) Mandatory Access Control", "type": "bool"},
|
|
{"name": "CONFIG_SECURITY_KEYRING", "label": "X.509 Cryptographic Keyring & Certificates", "type": "bool"},
|
|
]
|
|
},
|
|
{
|
|
"title": "Userland Core & LazyBox Utility Suite",
|
|
"type": "submenu",
|
|
"items": [
|
|
{"name": "CONFIG_USERLAND_LAZYBOX", "label": "LazyBox Multi-Call Userland Utility Suite (70+ Tools)", "type": "bool"},
|
|
]
|
|
}
|
|
]
|
|
|
|
def load_config():
|
|
cfg = dict(DEFAULTS)
|
|
if os.path.exists(CONFIG_FILE):
|
|
with open(CONFIG_FILE, "r") as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
if "=" in line:
|
|
k, v = line.split("=", 1)
|
|
k = k.strip()
|
|
v = v.strip().strip('"')
|
|
if v == "y":
|
|
cfg[k] = True
|
|
elif v == "n":
|
|
cfg[k] = False
|
|
else:
|
|
cfg[k] = v
|
|
return cfg
|
|
|
|
def save_config(cfg):
|
|
os.makedirs(os.path.dirname(AUTOCONF_HEADER), exist_ok=True)
|
|
with open(CONFIG_FILE, "w") as f_cfg, open(AUTOCONF_HEADER, "w") as f_hdr:
|
|
f_cfg.write("# Automatically generated by SUB-OS Kconfig TUI Configurator\n# Do not edit directly\n\n")
|
|
f_hdr.write("/* Automatically generated by SUB-OS Kconfig. Do not edit. */\n#ifndef _AUTOCONF_H\n#define _AUTOCONF_H\n\n")
|
|
|
|
# Write Architecture
|
|
arch = cfg.get("CONFIG_ARCH", "x86_64")
|
|
f_cfg.write(f"CONFIG_ARCH={arch}\n")
|
|
f_hdr.write(f'#define CONFIG_ARCH "{arch}"\n')
|
|
|
|
for k, v in sorted(cfg.items()):
|
|
if k == "CONFIG_ARCH":
|
|
continue
|
|
if isinstance(v, bool):
|
|
if v:
|
|
f_cfg.write(f"{k}=y\n")
|
|
f_hdr.write(f"#define {k} 1\n")
|
|
else:
|
|
f_cfg.write(f"# {k} is not set\n")
|
|
elif isinstance(v, str):
|
|
f_cfg.write(f'{k}="{v}"\n')
|
|
f_hdr.write(f'#define {k} "{v}"\n')
|
|
elif isinstance(v, int):
|
|
f_cfg.write(f"{k}={v}\n")
|
|
f_hdr.write(f"#define {k} {v}\n")
|
|
|
|
f_hdr.write("\n#endif /* _AUTOCONF_H */\n")
|
|
|
|
def run_tui(stdscr):
|
|
curses.curs_set(0)
|
|
curses.use_default_colors()
|
|
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN) # Header / Bar
|
|
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # Main background
|
|
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLUE) # Highlight title
|
|
curses.init_pair(4, curses.COLOR_BLACK, curses.COLOR_WHITE) # Selected row
|
|
curses.init_pair(5, curses.COLOR_CYAN, curses.COLOR_BLUE) # Subtext
|
|
|
|
cfg = load_config()
|
|
current_menu = MENU_STRUCTURE
|
|
menu_stack = []
|
|
cursor_stack = [0]
|
|
|
|
while True:
|
|
stdscr.bkgd(' ', curses.color_pair(2))
|
|
stdscr.clear()
|
|
max_y, max_x = stdscr.getmaxyx()
|
|
|
|
# Top Header Bar
|
|
stdscr.attron(curses.color_pair(1) | curses.A_BOLD)
|
|
title_str = " SUB-OS Kernel v0.2.0 Configuration (Linux-Style Kconfig TUI) "
|
|
stdscr.addstr(0, 0, title_str.ljust(max_x)[:max_x])
|
|
stdscr.attroff(curses.color_pair(1) | curses.A_BOLD)
|
|
|
|
# Active Architecture Indicator
|
|
cur_arch = cfg.get("CONFIG_ARCH", "x86_64")
|
|
cur_opt = cfg.get("CONFIG_OPTIMIZATION", "-O2")
|
|
info_str = f" Target Architecture: [{cur_arch}] | Optimization: [{cur_opt}] "
|
|
stdscr.attron(curses.color_pair(3))
|
|
stdscr.addstr(1, 2, info_str[:max_x-4])
|
|
stdscr.attroff(curses.color_pair(3))
|
|
|
|
# Instructions / Help
|
|
nav_help = "Arrow Keys navigate | <Enter> Select/Toggle | <Space> Toggle | [S]ave | [Q]/<Esc> Back"
|
|
stdscr.attron(curses.color_pair(5))
|
|
stdscr.addstr(2, 2, nav_help[:max_x-4])
|
|
stdscr.attroff(curses.color_pair(5))
|
|
|
|
# Divider line
|
|
stdscr.hline(3, 1, curses.ACS_HLINE, max_x - 2)
|
|
|
|
# Menu Items
|
|
items = current_menu if isinstance(current_menu, list) else current_menu.get("items", [])
|
|
cursor = cursor_stack[-1]
|
|
start_y = 5
|
|
|
|
for idx, item in enumerate(items):
|
|
y = start_y + idx
|
|
if y >= max_y - 3:
|
|
break
|
|
|
|
prefix = " "
|
|
is_selected = (idx == cursor)
|
|
|
|
if item.get("type") == "submenu":
|
|
line_text = f"---> {item['title']}"
|
|
elif item.get("type") == "bool":
|
|
val = cfg.get(item["name"], False)
|
|
state = "[*]" if val else "[ ]"
|
|
line_text = f"{state} {item['label']}"
|
|
elif item.get("type") == "radio":
|
|
group = item.get("group")
|
|
if group == "arch":
|
|
val = (cfg.get("CONFIG_ARCH") == item["val"])
|
|
elif group == "opt":
|
|
val = (cfg.get("CONFIG_OPTIMIZATION") == item["val"])
|
|
else:
|
|
val = False
|
|
state = "(*)" if val else "( )"
|
|
line_text = f"{state} {item['label']}"
|
|
else:
|
|
line_text = item.get("title", "")
|
|
|
|
display_line = f"{prefix}{line_text}".ljust(max_x - 6)[:max_x - 6]
|
|
|
|
if is_selected:
|
|
stdscr.attron(curses.color_pair(4) | curses.A_BOLD)
|
|
stdscr.addstr(y, 2, f" {display_line} ")
|
|
stdscr.attroff(curses.color_pair(4) | curses.A_BOLD)
|
|
else:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(y, 2, f" {display_line} ")
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Bottom Status Bar
|
|
stdscr.attron(curses.color_pair(1))
|
|
bottom_bar = " <Save> [S] <Exit> [Q] <Help> [?] <Defaults> [D] "
|
|
stdscr.addstr(max_y - 1, 0, bottom_bar.ljust(max_x)[:max_x])
|
|
stdscr.attroff(curses.color_pair(1))
|
|
|
|
stdscr.refresh()
|
|
key = stdscr.getch()
|
|
|
|
if key in [curses.KEY_UP, ord('k'), ord('K')]:
|
|
if cursor_stack[-1] > 0:
|
|
cursor_stack[-1] -= 1
|
|
elif key in [curses.KEY_DOWN, ord('j'), ord('J')]:
|
|
if cursor_stack[-1] < len(items) - 1:
|
|
cursor_stack[-1] += 1
|
|
elif key in [curses.KEY_ENTER, 10, 13]:
|
|
sel_item = items[cursor_stack[-1]]
|
|
if sel_item.get("type") == "submenu":
|
|
menu_stack.append(current_menu)
|
|
cursor_stack.append(0)
|
|
current_menu = sel_item
|
|
elif sel_item.get("type") == "bool":
|
|
name = sel_item["name"]
|
|
cfg[name] = not cfg.get(name, False)
|
|
elif sel_item.get("type") == "radio":
|
|
group = sel_item.get("group")
|
|
if group == "arch":
|
|
cfg["CONFIG_ARCH"] = sel_item["val"]
|
|
cfg["CONFIG_ARCH_X86_64"] = (sel_item["val"] == "x86_64")
|
|
cfg["CONFIG_ARCH_AARCH64"] = (sel_item["val"] == "aarch64")
|
|
cfg["CONFIG_ARCH_ARMV8I"] = (sel_item["val"] == "armv8i")
|
|
elif group == "opt":
|
|
cfg["CONFIG_OPTIMIZATION"] = sel_item["val"]
|
|
elif key == ord(' '):
|
|
sel_item = items[cursor_stack[-1]]
|
|
if sel_item.get("type") == "bool":
|
|
name = sel_item["name"]
|
|
cfg[name] = not cfg.get(name, False)
|
|
elif sel_item.get("type") == "radio":
|
|
group = sel_item.get("group")
|
|
if group == "arch":
|
|
cfg["CONFIG_ARCH"] = sel_item["val"]
|
|
cfg["CONFIG_ARCH_X86_64"] = (sel_item["val"] == "x86_64")
|
|
cfg["CONFIG_ARCH_AARCH64"] = (sel_item["val"] == "aarch64")
|
|
cfg["CONFIG_ARCH_ARMV8I"] = (sel_item["val"] == "armv8i")
|
|
elif group == "opt":
|
|
cfg["CONFIG_OPTIMIZATION"] = sel_item["val"]
|
|
elif key in [ord('s'), ord('S')]:
|
|
save_config(cfg)
|
|
stdscr.attron(curses.color_pair(1) | curses.A_BOLD)
|
|
stdscr.addstr(max_y - 2, 4, f" Saved configuration to {CONFIG_FILE} and {AUTOCONF_HEADER}! Press any key... ")
|
|
stdscr.attroff(curses.color_pair(1) | curses.A_BOLD)
|
|
stdscr.refresh()
|
|
stdscr.getch()
|
|
elif key in [ord('d'), ord('D')]:
|
|
cfg = dict(DEFAULTS)
|
|
save_config(cfg)
|
|
stdscr.attron(curses.color_pair(1) | curses.A_BOLD)
|
|
stdscr.addstr(max_y - 2, 4, " Loaded default configuration! Press any key... ")
|
|
stdscr.attroff(curses.color_pair(1) | curses.A_BOLD)
|
|
stdscr.refresh()
|
|
stdscr.getch()
|
|
elif key in [ord('q'), ord('Q'), 27]: # Esc or Q
|
|
if menu_stack:
|
|
current_menu = menu_stack.pop()
|
|
cursor_stack.pop()
|
|
else:
|
|
save_config(cfg)
|
|
break
|
|
|
|
def defconfig(arch="x86_64"):
|
|
cfg = dict(DEFAULTS)
|
|
cfg["CONFIG_ARCH"] = arch
|
|
if arch == "x86_64":
|
|
cfg["CONFIG_ARCH_X86_64"] = True
|
|
cfg["CONFIG_ARCH_AARCH64"] = False
|
|
cfg["CONFIG_ARCH_ARMV8I"] = False
|
|
elif arch in ["aarch64", "arm64"]:
|
|
cfg["CONFIG_ARCH_X86_64"] = False
|
|
cfg["CONFIG_ARCH_AARCH64"] = True
|
|
cfg["CONFIG_ARCH_ARMV8I"] = False
|
|
elif arch in ["armv8i", "arm32", "arm", "armv8"]:
|
|
cfg["CONFIG_ARCH_X86_64"] = False
|
|
cfg["CONFIG_ARCH_AARCH64"] = False
|
|
cfg["CONFIG_ARCH_ARMV8I"] = True
|
|
save_config(cfg)
|
|
print(f"*** Default configuration for '{arch}' written to {CONFIG_FILE} and {AUTOCONF_HEADER} ***")
|
|
|
|
def main():
|
|
if len(sys.argv) > 1:
|
|
cmd = sys.argv[1]
|
|
if cmd in ["--defconfig", "defconfig"]:
|
|
arch = sys.argv[2] if len(sys.argv) > 2 else "x86_64"
|
|
defconfig(arch)
|
|
return
|
|
elif cmd == "--x86_64":
|
|
defconfig("x86_64")
|
|
return
|
|
elif cmd in ["--aarch64", "--armv8"]:
|
|
defconfig("aarch64")
|
|
return
|
|
elif cmd == "--armv8i":
|
|
defconfig("armv8i")
|
|
return
|
|
|
|
try:
|
|
curses.wrapper(run_tui)
|
|
print(f"*** Configuration saved to {CONFIG_FILE} and {AUTOCONF_HEADER} ***")
|
|
except KeyboardInterrupt:
|
|
pass
|
|
|
|
if __name__ == "__main__":
|
|
main()
|