nfdos/src/tui/menu_kernel.py
neo.webmaster.2@gmail.com a005ac4e13
Some checks are pending
Build NFDOS ISO / build (push) Waiting to run
"Auto-commit via make git"
2025-11-16 18:59:11 +01:00

607 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import sys
import subprocess
import time
from pathlib import Path
from rich.console import Console
from glob import glob
# Import menus do TUI
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tui import menu_python, menu_iso, menu_libs # pylint: disable=wrong-import-position, import-error
console = Console()
def corrigir_kernel_headers(linux_dir, env):
"""
Corrige headers incompatíveis com C23 em vários caminhos.
Adiciona guards para typedef bool / enum { false, true }.
"""
console.print("[yellow]→ Patching kernel headers for C23 compatibility...[/]")
header_candidates = [
"include/linux/stddef.h",
"include/linux/types.h",
"include/uapi/linux/stddef.h",
"include/uapi/linux/types.h",
"arch/x86/include/asm/stddef.h",
"arch/x86/include/asm/types.h",
]
# Antes de aplicar os patches:
safe_run(["make", "prepare"], env=env)
safe_run(["make", "scripts"], env=env)
for relpath in header_candidates:
path = linux_dir / relpath
if not path.exists():
continue
content = path.read_text()
patched = False
# Corrige enum false/true
if "false" in content and "__bool_true_false_are_defined" not in content:
content = content.replace(
"enum {\n false = 0,\n true = 1\n};",
"#ifndef __bool_true_false_are_defined\n"
"enum {\n false = 0,\n true = 1\n};\n"
"#define __bool_true_false_are_defined 1\n#endif"
)
patched = True
# Corrige typedef _Bool
if "typedef _Bool" in content and "__STDC_VERSION__" not in content:
content = content.replace(
"typedef _Bool bool;",
"#ifndef __cplusplus\n"
"# if __STDC_VERSION__ < 202000L\n"
"typedef _Bool bool;\n"
"# endif\n"
"#endif"
)
patched = True
if patched:
path.write_text(content)
console.print(f"[green]✔ Patched:[/] {relpath}")
# Corrige Makefile do boot
boot_makefile = linux_dir / "arch/x86/boot/Makefile"
if boot_makefile.exists():
with open(boot_makefile, "a") as f:
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
console.print("[cyan]→ Applied local Makefile override for boot code (C23 fix)[/]")
# Corrige Makefile do boot/compressed
boot_compr_makefile = linux_dir / "arch/x86/boot/compressed/Makefile"
if boot_compr_makefile.exists():
with open(boot_compr_makefile, "a") as f:
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
console.print("[cyan]→ Applied local Makefile override for boot/compressed code (C23 fix)[/]")
# Corrige Makefile do EFI stub
efi_makefile = linux_dir / "drivers/firmware/efi/libstub/Makefile"
if efi_makefile.exists():
with open(efi_makefile, "a") as f:
f.write("\n# C23 fix\nccflags-y += -std=gnu11 -Wno-error\n")
console.print("[cyan]→ Applied local Makefile override for EFI stub (C23 fix)[/]")
def corrigir_kernel_overrides(cross_compile):
env = {
**os.environ,
"ARCH": "x86_64",
"CROSS_COMPILE": cross_compile,
"LOCALVERSION": "-nfdos",
}
console.print("[yellow]→ Aplicando overrides de configuração...[/yellow]")
# Essenciais do sistema base
essentials = [
"CONFIG_PRINTK",
"CONFIG_TTY",
"CONFIG_SERIAL_8250",
"CONFIG_SERIAL_8250_CONSOLE",
"CONFIG_SERIAL_EARLYCON",
"CONFIG_DEVTMPFS",
"CONFIG_DEVTMPFS_MOUNT",
"CONFIG_BLK_DEV_INITRD",
"CONFIG_TMPFS",
"CONFIG_PROC_FS",
"CONFIG_SYSFS",
# EXT4 base + alias para ext2
"CONFIG_EXT4_FS",
"CONFIG_EXT4_USE_FOR_EXT2",
"CONFIG_MCORE2",
#"CONFIG_EXT4_FS_POSIX_ACL",
#"CONFIG_EXT4_FS_SECURITY",
]
# VirtIO (para bloco, rede, PCI)
virtio = [
"CONFIG_PCI",
"CONFIG_VIRTIO",
"CONFIG_VIRTIO_MENU",
"CONFIG_VIRTIO_PCI",
"CONFIG_VIRTIO_PCI_LEGACY",
"CONFIG_VIRTIO_BLK",
"CONFIG_VIRTIO_NET",
"CONFIG_VIRTIO_CONSOLE",
"CONFIG_VIRTIO_INPUT",
"CONFIG_VIRTIO_MMIO",
"CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES",
"CONFIG_BLK_MQ_VIRTIO",
"CONFIG_BLOCK",
"CONFIG_BLK_DEV",
"CONFIG_BLOCK_LEGACY_AUTOLOAD",
"CONFIG_EXPORTFS_BLOCK_OPS",
"CONFIG_MSDOS_PARTITION", # assegura parsing de tabela de partições
]
# Debug e early printk
debug = [
"CONFIG_DEBUG_KERNEL",
"CONFIG_EARLY_PRINTK",
"CONFIG_SERIAL_8250_PNP",
"CONFIG_DEBUG_INFO_NONE", # evita symbols extras
]
# Desativa gráficos e Garante compatibilidade máxima de CPU (para manter o kernel leve, limpo e evitar CR4 panics)
disable_graphics = [
"CONFIG_VT",
"CONFIG_VT_CONSOLE",
"CONFIG_VGA_CONSOLE",
"CONFIG_FRAMEBUFFER_CONSOLE",
"CONFIG_DUMMY_CONSOLE",
"CONFIG_FB",
"CONFIG_DRM",
"CONFIG_DRM_I915",
"CONFIG_LOGO",
"CONFIG_X86_PAE",
"CONFIG_X86_5LEVEL",
"CONFIG_RANDOMIZE_BASE",
"CONFIG_RETPOLINE",
"CONFIG_SMAP",
"CONFIG_SMEP",
"CONFIG_PAGE_TABLE_ISOLATION",
]
# Habilita todos os conjuntos
for opt in essentials + virtio + debug:
safe_run(["scripts/config", "--enable", opt], env=env)
# garante que o driver não é módulo
for opt in [
"CONFIG_VIRTIO_BLK=m",
"CONFIG_VIRTIO_PCI=m",
"CONFIG_VIRTIO_PCI_LEGACY=m",
]:
safe_run(["scripts/config", "--disable", opt], env=env)
# Desativa o que não precisamos
for opt in disable_graphics:
safe_run(["scripts/config", "--disable", opt], env=env)
# Formatos binários básicos
for opt in [
"CONFIG_BINFMT_ELF",
"CONFIG_BINFMT_SCRIPT",
]:
safe_run(["scripts/config", "--enable", opt], env=env)
# Regera configuração coerente
safe_run(["make", "olddefconfig"], env=env)
console.print("[green]✔ Overrides aplicados com sucesso.[/green]")
def safe_run(cmd, **kwargs):
"""Executa um comando e mostra logs legíveis no TUI."""
console.print(f"[dim]{' '.join(cmd) if isinstance(cmd, list) else cmd}[/dim]")
subprocess.run(cmd, check=True, **kwargs)
def limpar_rootfs(nfdos_dir):
rootfs = nfdos_dir / "rootfs"
initramfs = nfdos_dir / "initramfs.cpio.gz"
if rootfs.exists():
console.print("[yellow]🧹 Limpando RootFS anterior...[/yellow]")
safe_run(f"rm -rf {rootfs}", shell=True)
if initramfs.exists():
console.print("[yellow]🧹 Removendo initramfs anterior...[/yellow]")
safe_run(f"rm -f {initramfs}", shell=True)
def run():
while True:
console.clear()
console.rule("[bold yellow]Kernel / BusyBox / Python[/bold yellow]")
console.print("1. Obter código-fonte do Kernel Linux")
console.print("2. Compilar Kernel com Toolchain NFDOS")
console.print("3. Obter e compilar BusyBox")
console.print("4. Compilar Python estatico com Toolchain NFDOS")
console.print("5. Obter e compilar Bibliotecas do Neurotron")
console.print("6. Montar RootFS e gerar imagem bootável")
console.print("7. Gerar imagem ISO e iniciar o NFDOS no QEMU")
console.print("0. Voltar")
choice = console.input("\n[cyan]nfdos> [/cyan]")
base_dir = Path(__file__).resolve().parents[1]
kernel_dir = base_dir / "_nfdos" / "kernel"
linux_dir = kernel_dir / "linux"
nfdos_dir = base_dir / "_nfdos"
busybox_dir = nfdos_dir / "busybox"
rootfs_dir = nfdos_dir / "rootfs"
toolchain_prefix = Path.home() / "x-tools" / "x86_64-nfdos-linux-musl"
cross_compile = f"{toolchain_prefix}/bin/x86_64-nfdos-linux-musl-"
linux_repo = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
busybox_repo = "git://busybox.net/busybox.git"
env = {
**os.environ,
"ARCH": "x86_64",
"CROSS_COMPILE": cross_compile,
"CFLAGS": "-std=gnu11 -fcommon -Wno-error",
"LOCALVERSION": "-nfdos",
"KCFLAGS": "-std=gnu11 -fcommon -Wno-error",
"HOSTCFLAGS": "-std=gnu11 -fcommon -Wno-error",
"KBUILD_CFLAGS": "-std=gnu11 -fcommon -Wno-error",
"KBUILD_AFLAGS": "-std=gnu11 -fcommon",
"KBUILD_CPPFLAGS": "-std=gnu11 -fcommon",
"KCFLAGS_FOR_HOST": "-std=gnu11 -Wno-error",
}
if choice == "1":
kernel_dir.mkdir(parents=True, exist_ok=True)
os.chdir(kernel_dir)
console.print("[yellow]Baixando código-fonte do Kernel Linux...[/yellow]")
if not linux_dir.exists():
safe_run(["git", "clone", "--depth=1", "--branch", "v6.12", linux_repo, "linux"])
else:
os.chdir(linux_dir)
safe_run(["git", "pull"])
console.print("[green]✔ Kernel atualizado![/green]")
elif choice == "2":
os.chdir(linux_dir)
console.print("[cyan]Compilando Kernel Linux...[/cyan]")
# Verificação do compilador
if not Path(cross_compile + "gcc").exists():
console.print("[red]✗ Toolchain não encontrada![/red]")
console.print(f"Esperado: {cross_compile}gcc")
time.sleep(2)
continue
# Passo 1 — Limpar tudo antes de começar
safe_run(["make", "mrproper"], env=env)
# Passo 2 — Baixar configuração base mínima
safe_run(["make", "allnoconfig"], env=env)
# Passo 3 — Aplicar patches C23 aos headers
corrigir_kernel_headers(linux_dir, env)
# Passo 4 — Aplicar overrides minimalistas (serial-only, sem VGA)
corrigir_kernel_overrides(cross_compile)
# Passo 5 — Regerar dependências e .config
safe_run(["make", "olddefconfig"], env=env)
# Passo 6 — Compilar
safe_run(["make", "-j", str(os.cpu_count())], env=env)
console.print("[green]✔ Kernel compilado com sucesso![/green]")
elif choice == "3":
busybox_dir.mkdir(parents=True, exist_ok=True)
os.chdir(busybox_dir)
console.print("[yellow]📦 Baixando e compilando BusyBox...[/yellow]")
if not (busybox_dir / ".git").exists():
safe_run(["git", "clone", "--depth=1", busybox_repo, "-b", "master", "."], env=env)
# 🧹 Limpeza preventiva se houver restos de builds anteriores
if (busybox_dir / ".config").exists():
console.print("[cyan]🧼 Limpando build antigo (make mrproper)...[/cyan]")
safe_run(["make", "mrproper"], env=env)
console.print("[cyan]🧩 Gerando configuração base (defconfig)...[/cyan]")
safe_run(["make", "defconfig"], env=env)
console.print("[cyan]🧠 Aplicando overrides de configuração (persistência + EXT4)...[/cyan]")
config_updates = {
"CONFIG_STATIC": "y",
"CONFIG_MKFS": "y",
"CONFIG_FEATURE_MKFS_EXT2": "y",
"CONFIG_FEATURE_MKFS_EXT3": "y",
"CONFIG_FEATURE_MKFS_EXT4": "y",
"CONFIG_MOUNT": "y",
"CONFIG_UMOUNT": "y",
"CONFIG_BLKID": "y",
"CONFIG_LSBLK": "y",
"CONFIG_FSCK": "y",
"CONFIG_FEATURE_MOUNT_HELPERS": "y",
"CONFIG_FEATURE_MOUNT_FSTAB": "y",
"CONFIG_FEATURE_VOLUMEID": "y",
"CONFIG_FEATURE_VOLUMEID_EXT": "y",
"CONFIG_FEATURE_VOLUMEID_FAT": "y",
"CONFIG_FEATURE_VOLUMEID_EXFAT": "y",
"CONFIG_FEATURE_VOLUMEID_NTFS": "y",
"CONFIG_FEATURE_VOLUMEID_LINUXSWAP": "y",
"CONFIG_FEATURE_VOLUMEID_BTRFS": "y",
"CONFIG_FEATURE_VOLUMEID_XFS": "y",
"CONFIG_FEATURE_VOLUMEID_ISO9660": "y",
}
for key, value in config_updates.items():
safe_run([
"sed", "-i",
f"s/^# {key} is not set/{key}={value}/; t; s/^{key}=.*/{key}={value}/; t; $a\\{key}={value}",
".config"
], env=env)
# 🧠 Shell e utilitários básicos
safe_run(["sed", "-i", "s/^CONFIG_TC=.*/# CONFIG_TC is not set/", ".config"], env=env)
safe_run(["sed", "-i", "s/^# CONFIG_ASH is not set/CONFIG_ASH=y/", ".config"], env=env)
safe_run(["sed", "-i", "s/^# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set/CONFIG_ASH_OPTIMIZE_FOR_SIZE=y/", ".config"], env=env)
safe_run(["sed", "-i", "s/^# CONFIG_FEATURE_SH_STANDALONE is not set/CONFIG_FEATURE_SH_STANDALONE=y/", ".config"], env=env)
console.print("[yellow]🔧 Regerando configuração coerente (make oldconfig)...[/yellow]")
safe_run(["make", "oldconfig"], env=env)
console.print("[yellow]🔨 Compilando BusyBox (estático, com EXT4 e ferramentas de disco)...[/yellow]")
safe_run(["make", "-j", str(os.cpu_count())], env=env)
safe_run(["make", "install"], env=env)
console.print("[green]✔ BusyBox compilado e instalado com sucesso![/green]")
elif choice == "4":
menu_python.run()
elif choice == "5":
menu_libs.run()
elif choice == "6":
os.chdir(nfdos_dir)
console.print("[cyan]Montando RootFS e gerando imagem bootável...[/cyan]")
limpar_rootfs(nfdos_dir)
rootfs_dir = nfdos_dir / "rootfs"
rootfs_dir.mkdir(exist_ok=True)
# Estrutura de diretórios básica
for d in ["bin", "sbin", "etc", "proc", "sys", "usr/bin", "usr/sbin", "opt/kernel"]:
(rootfs_dir / d).mkdir(parents=True, exist_ok=True)
# Garante os device nodes no initramfs
safe_run(f"mkdir -p {rootfs_dir}/dev", shell=True)
safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/console c 5 1", shell=True)
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/null c 1 3", shell=True)
safe_run(f"sudo mknod -m 600 {rootfs_dir}/dev/ttyS0 c 4 64", shell=True)
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/random c 1 8", shell=True)
safe_run(f"sudo mknod -m 666 {rootfs_dir}/dev/urandom c 1 9", shell=True)
# Copiar o BusyBox instalado para o rootfs
console.print("[blue]🔗 Copiando BusyBox para o rootfs...[/blue]")
safe_run(f"cp -a {busybox_dir}/_install/* {rootfs_dir}/", shell=True)
safe_run(["chmod", "-R", "755", str(rootfs_dir / "bin")])
console.print("[green]✔ BusyBox incluído no rootfs![/green]")
# Inserir a Lib Python (TODO: No NFDOS V0.2 build “fully frozen”)
safe_run(f"mkdir -p {rootfs_dir}/usr/lib/python3.13", shell=True)
safe_run(f"rsync -av --exclude='test' --exclude='idlelib' --exclude='tkinter' \
{nfdos_dir}/cpython/Lib/ {rootfs_dir}/usr/lib/python3.13/", shell=True)
# --- Copiar binário Python estático para o RootFS ---
python_bin = nfdos_dir / "python"
usr_bin = rootfs_dir / "usr" / "bin"
usr_bin.mkdir(parents=True, exist_ok=True)
if python_bin.exists():
console.print("[yellow]→ Adicionando Python estático ao RootFS...[/yellow]")
safe_run(f"cp {python_bin} {usr_bin}/python3", shell=True)
else:
console.print("[red]⚠ Python estático não encontrado em nfdos/python — compilar antes.[/red]")
# Inserir Neurotron (se existir)
opt_kernel = rootfs_dir / "opt" / "kernel"
opt_kernel.mkdir(parents=True, exist_ok=True)
# ============================================
# Instalar Neurotron nativamente no RootFS
# ============================================
neurotron_src = kernel_dir / "neurotron" / "src"
neurotron_data = kernel_dir / "neurotron" / "data"
neurotron_bin = kernel_dir / "neurotron" / "neurotron" # gerado pelo autotools
neurotron_root = opt_kernel / "neurotron"
neurotron_root.mkdir(parents=True, exist_ok=True)
if neurotron_src.exists():
console.print("[yellow]→ Instalando código-fonte do Neurotron...[/yellow]")
safe_run(f"cp -r {neurotron_src} {neurotron_root}/", shell=True)
else:
console.print("[red]✗ Código-fonte do Neurotron não encontrado.[/red]")
if neurotron_data.exists():
console.print("[yellow]→ Instalando diretório data/ do Neurotron...[/yellow]")
safe_run(f"cp -r {neurotron_data} {neurotron_root}/", shell=True)
# Instalar binário /usr/bin/neurotron
usr_bin = rootfs_dir / "usr" / "bin"
usr_bin.mkdir(parents=True, exist_ok=True)
if neurotron_bin.exists():
console.print("[yellow]→ Instalando wrapper /usr/bin/neurotron[/yellow]")
safe_run(f"cp {neurotron_bin} {usr_bin}/neurotron", shell=True)
safe_run(f"chmod +x {usr_bin}/neurotron", shell=True)
else:
console.print("[red]✗ Wrapper 'neurotron' não encontrado — corre 'make' em kernel/neurotron[/red]")
# Instalar terminais
lterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "l"
lterm_dir.mkdir(parents=True, exist_ok=True)
safe_run(f"cp {nfdos_dir}/linux {lterm_dir}/", shell=True)
xterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "x"
xterm_dir.mkdir(parents=True, exist_ok=True)
safe_run(f"cp {nfdos_dir}/xterm {xterm_dir}/", shell=True)
vterm_dir = rootfs_dir / "usr" / "share" / "terminfo" / "v"
vterm_dir.mkdir(parents=True, exist_ok=True)
safe_run(f"cp {nfdos_dir}/vt100 {vterm_dir}/", shell=True)
# Instalar libs externas do Neurotron (se existirem)
libs_dir = nfdos_dir / "libs"
site_packages = rootfs_dir / "usr/lib/python3.13/site-packages"
site_packages.mkdir(parents=True, exist_ok=True)
lib_files = []
for ext in ("*.whl", "*.tar.gz", "*.zip", "*.tgz"):
lib_files.extend(glob(f"{libs_dir}/{ext}"))
if lib_files:
libs_str = " ".join(lib_files)
console.print("[cyan]→ Instalando bibliotecas externas do Neurotron...[/cyan]")
safe_run(
f"pip install --no-deps --target={site_packages} {libs_str}",
shell=True
)
else:
console.print("[yellow]⚠️ Nenhuma biblioteca externa encontrada em libs/.[/yellow]")
# Script init com chamada ao Neurotron
init_file = rootfs_dir / "init"
initramfs_file = nfdos_dir / "initramfs.cpio.gz"
safe_run(f"cd {rootfs_dir} && cp ../init .", shell=True) # TODO: usar f.write para automatizar o init
safe_run(["chmod", "+x", str(init_file)])
# Gerar initramfs
console.print("[blue]Gerando initramfs.cpio.gz...[/blue]")
if initramfs_file.exists():
safe_run(f"rm {initramfs_file}", shell=True)
safe_run(f"cd {rootfs_dir} && find . | cpio -H newc -o | gzip > {initramfs_file}", shell=True)
console.print("[green]✔ RootFS criado e compactado![/green]")
# 🧠 Validação do init antes de gerar o initramfs
console.print("[blue]🔍 Verificando integridade do init...[/blue]")
# Garante que o init existe
if not init_file.exists():
console.print(f"[red]✗ Ficheiro init não encontrado em {init_file}[/red]")
raise SystemExit(1)
# Mostra onde ele está dentro do initramfs
safe_run(f'cd {nfdos_dir} && lsinitramfs initramfs.cpio.gz | grep -E "(^|/)init$"', shell=True)
# Mostra tipo e encoding
console.print("[cyan]→ Verificando tipo de ficheiro...[/cyan]")
safe_run(f'file {init_file}', shell=True)
# Mostra primeiras linhas (para confirmar shebang)
console.print("[cyan]→ Conteúdo inicial do init (máx 10 linhas)...[/cyan]")
safe_run(f'head -n 10 {init_file}', shell=True)
# Sanitização: remove BOM e CRLF
console.print("[blue]→ Removendo BOM e CRLF (normalização universal)...[/blue]")
safe_run(f"sed -i '1s/^\\xEF\\xBB\\xBF//' {init_file}", shell=True)
safe_run(f"sed -i 's/\\r$//' {init_file}", shell=True)
# Confirma permissões
console.print("[cyan]→ Ajustando permissões de execução...[/cyan]")
safe_run(f'chmod 0755 {init_file}', shell=True)
# Segunda verificação do tipo
console.print("[green]✔ Ficheiro final após normalização:[/green]")
safe_run(f'file {init_file}', shell=True)
# Validação do shebang e encoding
console.print("[blue]→ Testando assinatura e line endings...[/blue]")
safe_run(f"head -n1 {init_file} | od -c", shell=True)
safe_run(f"grep -Ua 'bin/sh' {init_file} | head -n1", shell=True)
console.print("[green]✔ init validado e pronto para inclusão no initramfs[/green]")
# Criar disco (se não existir)
data_disk = nfdos_dir / "nfdos_data.img"
if not data_disk.exists():
console.print("[cyan]💽 Criando disco persistente (hipocampo físico)...[/cyan]")
safe_run(f"dd if=/dev/zero of={data_disk} bs=1M count=512", shell=True)
else:
console.print("[green]✔ Disco persistente já existe.[/green]")
time.sleep(5)
# Testar no QEMU
bz_image = linux_dir / "arch" / "x86" / "boot" / "bzImage"
data_disk = nfdos_dir / "nfdos_data.img"
if bz_image.exists():
console.print("\n[bold blue]Iniciando QEMU (modo kernel direto)...[/bold blue]")
# 🔒 Pergunta ao utilizador se deve permitir formatação automática do disco
console.print(
"\n[yellow]O Neurotron detetará o disco físico e poderá formatá-lo se estiver vazio.[/yellow]"
)
console.print(
"[bright_yellow]Deseja permitir formatação automática do disco?[/bright_yellow] "
"([green]y[/green]/[red]N[/red]): ",
end=""
)
choice = input().strip().lower()
allow_format = choice in ("y", "yes", "sim", "s")
# 🧠 Monta a linha base do QEMU
kernel_params = (
"console=ttyS0 earlyprintk=serial,ttyS0,115200 "
"keep_bootcon loglevel=8"
)
# 🧩 Injeta flag de formatação se permitido
if allow_format:
kernel_params += " nfdos_force_format=1"
console.print("[green]✔ Formatação automática permitida neste boot.[/green]")
else:
console.print("[cyan] Formatação automática desativada (modo seguro).[/cyan]")
qemu_cmd = (
f"qemu-system-x86_64 "
f"-machine q35,accel=kvm "
f"-cpu qemu64 "
f"-kernel {bz_image} "
f"-initrd {nfdos_dir}/initramfs.cpio.gz "
f"-append '{kernel_params}' "
f"-drive file={data_disk},if=virtio,format=raw "
f"-m 1024 "
f"-nographic "
f"-no-reboot"
)
# 🚀 Executa o QEMU
safe_run(qemu_cmd, shell=True)
else:
console.print("[red]✗ bzImage não encontrado! Compile o kernel primeiro.[/red]")
elif choice == "7":
menu_iso.run()
elif choice == "0":
break
else:
console.print("[red]Opção inválida![/red]")
time.sleep(1)