# Plan de build — FWS « Hibernate‑Swap Dual‑Boot » (Valorant/Vanguard) > Document de build final. Le design est validé et acquis : ce plan le rend **buildable**, intègre les corrections bloquantes de la revue adversariale et fixe l'ordre d'exécution. Cible réelle : UEFI, Zen 5, 60,45 GiB RAM, 3× NVMe 2 To (Samsung 990 PRO), **RTX 5090 Blackwell** (pilote propriétaire 610.43.02), TPM 2.0, GRUB, noyau 7.1.2‑arch3‑1, Secure Boot **OFF**, aucun swap. --- ## 1. Résumé & principe L'utilisateur clique **« Jouer à Valorant »** dans FWS. FWS **hiberne** (RAM → swap disque) après avoir armé un boot **one‑shot UEFI** (`BootNext`) vers un **Windows 11 bare‑metal** installé sur une partition NTFS dédiée. Le firmware lance Windows **directement** (`\EFI\Microsoft\Boot\bootmgfw.efi`, jamais via GRUB) : Vanguard voit un vrai Windows natif. À la fermeture **ou** au crash de Valorant, Windows arme `BootNext=FWS` et **reboote**, le noyau voit `resume=` et **reprend la session FWS intacte**. C'est un dual‑boot bare‑metal des deux côtés — configuration que Vanguard tolère — avec `BootOrder[0]=FWS` comme filet de sûreté permanent. --- ## 2. Prérequis matériels / logiciels **Matériel (vérifié sur cible)** - UEFI en User Mode (SetupMode=0), db d'usine Microsoft présents, TPM 2.0, IOMMU activable au firmware (à confirmer dans le setup). - 3× NVMe **entièrement partitionnés, zéro espace non alloué** (à re‑confirmer via `parted … print free`). - **GPU RTX 5090** : facteur critique d'hibernation (VRAM 32 Go) — voir §7. **Logiciels côté FWS (Arch)** - Paquets à ajouter : `sbsigntools` / `sbctl`, `efibootmgr`, `mokutil`, `wimlib`, `ntfs-3g`, `polkit`, `python-gobject`, `gtk3`, `nvidia`/`nvidia-utils` + `nvidia-hibernate`/`nvidia-resume` (hooks S4 NVIDIA). - **Interdits** (casseraient l'hibernation) : `linux-hardened`, patch auto‑lockdown Fedora, `lockdown=` en cmdline, initramfs systemd non planifié. - Invariants à figer en CI : `/sys/kernel/security/lockdown == [none]`, `/sys/power/state` contient `disk`, cmdline sans `lockdown=`. **Côté Windows (fourni par l'utilisateur, non bundlé)** - ISO Windows 11 légitime, TPM 2.0 + Secure Boot exigés par Riot, VBS/HVCI actifs (défaut 24H2). --- ## 3. Roadmap par phases ### Phase 0 — Recon disque + firmware (root requis, BLOQUANT avant toute écriture) ```bash for d in /dev/nvme0n1 /dev/nvme1n1 /dev/nvme2n1; do sudo parted "$d" unit MiB print free; sudo sgdisk -p "$d"; done sudo lsblk -dpno NAME,SIZE,MODEL ``` Confirmer l'absence réelle d'espace libre → détermine chemin **neuf (Anaconda)** vs **shrink post‑install**. Dans le firmware : vérifier IOMMU (VT‑d/AMD‑Vi) **actif** et BIOS à jour (exigence Vanguard). ### Phase 1 — Provisionner l'hibernation (chemin machine réelle : swapfile) Sizing **RAM + VRAM + marge = 96 GiB** (et non 64 : la VRAM préservée est recopiée dans l'image — voir §7). ```bash sudo mkswap -U clear --size 96G --file /swapfile sudo chmod 600 /swapfile sudo swapon /swapfile && swapon --show # fstab : ajouter '/swapfile none swap defaults 0 0' ; supprimer la ligne /mnt/games2 dupliquée N=$(sudo filefrag -v /swapfile | awk '$1=="0:"{print substr($4,1,length($4)-2)}') # resume_offset sudo chattr +i /swapfile # fige l'offset (anti-dérive silencieuse) ``` UUID de reprise = **FS hôte (racine)** `84888eb3-cab9-407b-b407-ea4b3133c4a6`, pas l'UUID interne du swap. ### Phase 2 — Hook resume + cmdline ```bash # /etc/mkinitcpio.conf : resume APRÈS block, AVANT filesystems (busybox, PAS systemd) # HOOKS=(base udev autodetect keyboard keymap modconf block resume filesystems fsck) sudo mkinitcpio -P sudo lsinitcpio /boot/initramfs-linux.img | grep -i resume # doit matcher # /etc/default/grub : # GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet resume=UUID=84888eb3-cab9-407b-b407-ea4b3133c4a6 resume_offset=N hibernate.compressor=lz4" # → hibernate.compressor=lz4 : compression la plus RAPIDE de l'image (moins de # CPU que lzo) → hibernate/resume plus courts sur une image de 60-90 Go. # GRUB_DISABLE_OS_PROBER=true (aucune entrée GRUB->Windows -> PCR4/PCR7 propres) # GRUB_TIMEOUT=1 + GRUB_TIMEOUT_STYLE=hidden → resume quasi immédiat (menu # masqué, maintenir Maj/Échap pour l'afficher). Boot le plus rapide côté FWS. sudo grub-mkconfig -o /boot/grub/grub.cfg ``` ### Phase 3 — GPU NVIDIA (sans quoi le resume graphique est cassé) ```bash # /etc/modprobe.d/nvidia-hibernate.conf # options nvidia NVreg_PreserveVideoMemoryAllocations=1 NVreg_TemporaryFilePath=/var/tmp sudo systemctl enable nvidia-suspend.service nvidia-hibernate.service nvidia-resume.service ``` ### Phase 4 — Valider l'hibernation AVANT de la câbler au bouton « Jouer » ```bash sync; echo test_resume | sudo tee /sys/power/disk; sudo systemctl hibernate # non destructif echo platform | sudo tee /sys/power/disk # Puis cycle réel, SESSION GRAPHIQUE CHARGÉE (jeu/desktop lourd) : sudo systemctl hibernate # rallumer journalctl -b -1 -k | grep -iE 'PM: hibernation|Image saved|resume|Restarting tasks' ``` Critère de succès : session préservée **et** affichage NVIDIA intact au resume. Échec → le flux « Jouer » doit basculer en reboot propre (§7). ### Phase 5 — Secure Boot signé, lockdown OFF (§4) ### Phase 6 — Installateur : carve NTFS + outillage Windows (§6) ### Phase 7 — Orchestrateur one‑shot + GUI (§5) ### Phase 8 — Spike end‑to‑end sur ISO réelle : hibernate → BootNext → Windows → Valorant → retour FWS. --- ## 4. Point dur Secure Boot ↔ hibernation — SOLUTION RETENUE **Le nœud :** Vanguard exige Secure Boot **globalement** au firmware → FWS doit aussi booter sous SB. Or Fedora/Ubuntu bloquent l'hibernation sous SB via le **lockdown**. **Fait établi et vérifié :** sur **noyau mainline Arch**, activer Secure Boot **n'arme PAS** le lockdown. Le patch Garrett/Howells liant SB↔lockdown a été **refusé upstream** ; il est downstream Fedora/Ubuntu uniquement. Sur la cible : `CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT` **absent**, `CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y`, pas de `LSM_EARLY`, `/sys/kernel/security/lockdown = [none]`. **Signer ≠ lockdown : ils sont orthogonaux.** **Solution retenue : `sbctl` (clés db custom), en CONSERVANT les clés Microsoft.** Justification : firmware déjà en User Mode avec db Microsoft → Windows boote sans y toucher ; friction minimale ; hook pacman de re‑signature intégré. On **garde GRUB** (pas d'UKI) : cmdline `resume=` éditable et **PCR4 firmware stable** à chaque MAJ noyau (favorable à un futur scellement TPM du swap LUKS). *Voie alternative documentée : shim+MOK (modèle Ubuntu/Fedora, plus robuste sur OEM verrouillés, au prix d'un prompt MokManager) — à retenir si le firmware refuse l'enrôlement db custom.* ```bash sudo pacman -S sbctl # PRÉREQUIS NON NÉGOCIABLE : le grubx64.efi installé n'a NI .sbat NI shim_lock -> réinstaller GRUB d'abord : sudo grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB \ --sbat /usr/share/grub/sbat.csv --modules='normal search part_gpt part_msdos fat ext2 configfile linux echo test true loadenv all_video efi_gop tpm' objdump -h /boot/EFI/GRUB/grubx64.efi | grep -E 'sbat' # doit exister # Setup Mode au firmware, puis : sudo sbctl create-keys sudo sbctl enroll-keys --microsoft # IMPÉRATIF : réinjecte MS -> Windows/OROM bootent sudo sbctl sign -s /boot/EFI/GRUB/grubx64.efi sudo sbctl sign -s /boot/vmlinuz-linux sudo sbctl verify ls /usr/share/libalpm/hooks/ | grep sbctl # re-signe après MAJ noyau/grub ``` **Ordre impératif :** signer **avant** d'activer SB au firmware. Après tout `grub-install`, **re‑signer** (il régénère un binaire non signé). Vérif post‑activation : `bootctl status` → SB enabled ; `/sys/kernel/security/lockdown` → `[none]` ; `/sys/power/state` contient `disk`. --- ## 5. Orchestration du boot **Invariant de sûreté :** `BootOrder[0]=FWS` en permanence. `BootNext` (var UEFI one‑shot `8be4df61-93ca-11d2-aa0d-00e098032b8c`) **uniquement** pour les transitions. Tout crash retombe sur FWS. ### Aller FWS → Windows (`/usr/local/bin/fws-gameboot to-windows`, via pkexec) Preflight **avant toute écriture NVRAM** — abort si un test échoue : ```bash grep -q disk /sys/power/state || die 'hibernation indispo' awk '/^SwapTotal/{s=$2}/^MemTotal/{m=$2}END{exit !(s>=m)}' /proc/meminfo || die 'swap < RAM' # + garde VRAM (voir §7) : image projetée <= swap grep -q 'resume=' /proc/cmdline || die 'resume= absent' bootctl status 2>/dev/null | grep -qi 'Secure Boot: enabled' || die 'Secure Boot inactif' WIN=$(efibootmgr | sed -n 's/^Boot\([0-9A-Fa-f]\{4\}\)\*\? Windows Boot Manager.*/\1/p' | head -1) [ -n "$WIN" ] || die 'entrée Windows introuvable' findmnt -rno TARGET -t ntfs3,ntfs | while read m; do umount "$m" || true; done # NTFS jamais rw persistante efibootmgr -n "$WIN" efibootmgr | grep -q "BootNext: $WIN" || { efibootmgr -N; die 'BootNext non écrit'; } # RELECTURE obligatoire # Watchdog anti-hang (§7) autour de : timeout 180 systemctl hibernate || { efibootmgr -N; die 'échec/hang hibernation'; } ``` ### Retour Windows → FWS (`C:\ProgramData\FWS\fws-play.ps1`, compte jeu autologin) ```powershell & "$PSScriptRoot\fws-return.ps1" -Target Windows # RE-ARME BootNext=Windows au boot -> crash/WU réatterrit sur Windows Start-Process 'C:\Riot Games\Riot Client\RiotClientServices.exe' -ArgumentList '--launch-product=valorant','--launch-patchline=live' do { Start-Sleep 5 } until (Get-Process VALORANT-Win64-Shipping -EA SilentlyContinue) Get-Process VALORANT-Win64-Shipping -EA SilentlyContinue | Wait-Process # quit OU crash & "$PSScriptRoot\fws-return.ps1" -Target FWS # pose BootNext=FWS shutdown /r /t 0 ``` Pose de `BootNext` côté Windows = **écriture directe** de la variable UEFI (`SetFirmwareEnvironmentVariableExW` + `SeSystemEnvironmentPrivilege`), repli `bcdedit /set {fwbootmgr} bootsequence`. Belt‑and‑suspenders : tâche `ONSTART` (SYSTEM) qui arme `BootNext=FWS` dès le boot (couvre les crashs), + hook GPO shutdown, + `powercfg /h off` (reboot plein, NTFS jamais sale). ### À chaque boot FWS — `fws-gameboot-bootfix.service` (oneshot, `ConditionPathExists=!/run/archiso`) Réasserte `BootOrder[0]=FWS` (auto‑guérison anti Windows Update) et réécrit le marqueur FAT `/EFI/FWS/return.json = {fws_bootnum, windows_bootnum}` (les `Boot####` bougent avec `efibootmgr`). **Filet ultime :** même mécanisme Windows HS → `BootOrder[0]=FWS` ramène à FWS, image d'hibernation intacte (Windows ne touche jamais l'ext4). --- ## 6. Intégration installateur FWS Deux chemins (la cible réelle est déjà installée, sans espace libre). **Chemin NEUF (Anaconda).** Nouveau spoke `fws_windows.py` (clone exact de `fws_desktop.py`, découvert au runtime, aucun rebuild) : case « Dual‑boot Windows (Valorant) », combo disque, spin taille (défaut **200 GiO** — Win11 ~40 + Valorant ~40 + updates ; min 100). Écrit `/tmp/fws-windows`. Le **partitionnement NTFS se fait en `%pre`** (blivet ne sait pas créer du NTFS) : ```bash # %pre — REMPLACE le clearpart --all destructeur (voir §7). UEFI + enabled=1 requis : sgdisk --zap-all "$DISK" sgdisk -n1:0:+1GiB -t1:ef00 -c1:EFI "$DISK" # ESP >=1 GiO sgdisk -n2:0:+96GiB -t2:8200 -c2:swap "$DISK" # swap DÉDIÉ = RAM+VRAM -> pas de resume_offset sgdisk -n3:0:+${WIN_GIB}GiB -t3:0700 -c3:WINDOWS "$DISK" # slot NTFS (Microsoft basic data) sgdisk -n4:0:0 -t4:8300 -c4:FWSROOT "$DISK" partprobe "$DISK"; udevadm settle mkfs.fat -F32 ${DISK}p1; mkswap ${DISK}p2; mkfs.ntfs -Q -L WINDOWS ${DISK}p3 ``` ```ks ignoredisk --only-use=nvme2n1 # protège nvme0n1/nvme1n1 (games) clearpart --none part /boot --onpart=nvme2n1p1 --fstype=efi --noformat part swap --onpart=nvme2n1p2 --noformat part / --onpart=nvme2n1p4 --fstype=ext4 # nvme2n1p3 NON référencé -> NTFS intact ; en %post : resume=UUID= (partition dédiée, pas d'offset) ``` **Chemin POST‑INSTALL (machine réelle) — `fws-windows-setup`.** Shrink hors‑ligne, ordre **load‑bearing** (cibler un NVMe games pour garder la racine intacte) : ```bash e2fsck -f /dev/nvme1n1p1 resize2fs /dev/nvme1n1p1 1550G # FS sous la taille finale parted /dev/nvme1n1 resizepart 1 1560GiB # puis la partition resize2fs /dev/nvme1n1p1 # re-remplit sgdisk -n0:0:0 -t0:0700 -c0:WINDOWS /dev/nvme1n1 mkfs.ntfs -Q -L WINDOWS /dev/nvme1n1p2 ``` **Outillage Windows (aucun bundling).** - `fws-windows-media` : clé USB Secure‑Boot‑propre depuis l'ISO **de l'utilisateur**. `install.wim` >4 GiO illégal en FAT32 → FAT32 + `wimlib-imagex split install.wim /usb/sources/install.swm 3800` (pas de uefi‑ntfs, `bootmgfw.efi` signé MS). - `fws-windows-postinstall` : lit le `Boot####` « Windows Boot Manager » → `/etc/fws/windows-boot-id` ; `efibootmgr -o ,…,` (Setup Windows se remet en tête) ; vérifie SB/TPM2/VBS ; **rappels DANS Windows** : `powercfg /h off`, **NE PAS activer BitLocker** (ou suspendre aux bascules). --- ## 7. Risques & mitigations (revue adversariale intégrée) | # | Sévérité | Problème | Mitigation retenue | |---|----------|----------|--------------------| | 1 | **BLOQUANT** | `clearpart --all --disklabel=msdos` inconditionnel dans `interactive-defaults.ks` → efface les 3 NVMe (dont games) + force MBR sur UEFI. | **Ne jamais livrer l'ISO en l'état.** `%pre` conditionné `/sys/firmware/efi` + `ignoredisk --only-use` + `clearpart --none` + `part --onpart` sur layout sgdisk. Protéger nvme0/1 explicitement. Tester sur ISO. | | 2 | **BLOQUANT** | Resume GPU cassé : RTX 5090 Blackwell sans `PreserveVideoMemoryAllocations` → écran noir/corruption au S4. Design muet sur le GPU. | `NVreg_PreserveVideoMemoryAllocations=1` + `NVreg_TemporaryFilePath` ; `nvidia-hibernate/resume` actifs ; **tester le resume session chargée AVANT** de câbler le bouton ; fallback reboot obligatoire si échec (Phase 4). | | 3 | Majeur | Swap = RAM ignore la VRAM recopiée (jusqu'à 32 Go) → image 75‑90 GiO > swap 64 → échec. | **Swap = RAM + VRAM + marge = 96 GiO.** Preflight : estimer VRAM en usage (`nvidia-smi`), refuser/basculer reboot si image projetée > swap. Tester pire cas (jeu déjà lancé côté Linux). | | 4 | Majeur | Brick FWS par révocation **dbx/SBAT** poussée par Windows Update (précédents BootHole/SBAT réels). Windows booté **fréquemment** ici → risque élevé. | shim/grub à jour et re‑signés ; **différer/figer Windows Update** sur ce Windows gaming minimal ; tester bascule après chaque MAJ Windows/Vanguard ; **fournir un média de récupération FWS** (ré‑enrôlement/re‑signature). | | 5 | Majeur | **BitLocker auto‑activé** par TPM+SB (Win11 24H2 Device Encryption) : le flip SB OFF→ON change PCR7 → écran de récupération, clé dans le compte MS. | **Activer Secure Boot AVANT d'installer Windows** (PCR7 stable dès l'install, pas de flip). Documenter : suspendre/désactiver BitLocker, **sauvegarder la clé**, `powercfg /h off`. Vérifier device‑encryption au postinstall et alerter. Nuance : les bascules `BootNext` récurrentes ne touchent PAS PCR7 (bootmgfw chargé à l'identique). | | 6 | Majeur | `systemctl hibernate` qui **hang** (driver refuse S4) : machine allumée, session ni sauvée ni basculée, `BootNext=Windows` resté armé → départ surprise. | ⚠️ **NON mitigeable en userspace** : pendant un hang S4 le process (et tout watchdog) est gelé — un `timeout` est impossible (il tuerait aussi les hibernations *réussies*, qui ne rendent la main qu'au resume). Parades réelles : **préflight strict** (élimine les causes courantes) + **auto-guérison** au reset (BootNext=Windows → Windows → tâche ONSTART arme FWS → retour) + **filet BootOrder[0]=FWS**. Tester la robustesse S4 sur la carte ; documenter la récupération post-hang. | | 7 | Majeur | Resume **silencieux** en échec (offset dérivé/image corrompue) → cold boot, session perdue **sans notification**. Incohérence swapfile+offset (fragile) vs partition dédiée (robuste). | **Unifier sur partition swap dédiée** dès que possible (chemin installeur) ; `chattr +i` sur tout swapfile résiduel ; revalider l'offset au preflight ET au retour ; **notifier explicitement** « session non restaurée » au cold boot post‑hibernation. | | 8 | Majeur | Politique de fallback **contradictoire** entre docs (`hibernate || die` reste sur FWS vs `|| reboot` part sur Windows sans session). | **Trancher UNE politique** (reco : échec hibernation → confirmation utilisateur puis reboot Windows sans session ; sinon annuler proprement `efibootmgr -N`) et l'implémenter à l'identique. Interdire la divergence en CI. | | 9 | Majeur | Sémantiques `BootNext`/`BootOrder` **non validées** (Windows pas installé) : firmware peut ignorer BootNext, réordonner, purger l'entrée FWS. Mapping `bcdedit {fwbootmgr}` → BootNext non documenté MS. | Valider empiriquement dès la 1re install (écrire BootNext côté Windows, relire via `efibootmgr` côté Linux). Entrée de secours `\EFI\BOOT\BOOTX64.EFI` (`grub-install --removable`). Ne pas dépendre que de BootNext. | | 10 | Majeur | Prérequis SB non résolu : `grubx64.efi` sans `.sbat` ni `shim_lock` → shim refuse GRUB ; `grub-install` régénère non signé. | Réinstall GRUB (`--sbat` + modules) + signature **avant** d'activer SB ; hooks re‑signature couvrant `linux` + LTS/fallback ; vérifier `objdump 'sbat'` ; ne jamais activer SB sans `sbverify` OK (§4). | | 11 | Mineur | Fondement « bit CPUID hyperviseur = 0 » **FAUX** : Zen 5 + Win11 24H2 → VBS/Hyper‑V actif, bit=1, toléré par Vanguard. | **Ne pas combattre VBS.** Corriger la doc : Vanguard vérifie SB actif + TPM présent + **absence d'hyperviseur TIERS**, pas un bit à 0. Valider que Valorant lance avec VBS on par défaut. | | 12 | Mineur | SB sans lockdown côté Linux = conformité, pas défense : initramfs non signé, `grub.cfg` éditable, image d'hibernation **en clair** sur ext4. | Assumer honnêtement (SB ici = case Vanguard). Durcissement hors‑MVP : UKI cmdline scellée, **LUKS+TPM sur le swap** (impose repartition). | | 13 | Mineur | Risque fournisseur Vanguard (changement de politique) + overhead ~3‑5 min/session. | Compat annoncée **best‑effort**, re‑test après chaque bump. **Offrir un mode « reboot simple »** (sans hibernation) comme voie robuste par défaut, hibernation en confort opt‑in → réduit drastiquement la surface de brick/perte de session. | --- ## 8. Décisions ouvertes à trancher avec l'utilisateur 1. **Hibernation vs reboot simple par défaut.** La couche hibernation ajoute VRAM/offset/resume fragiles pour ~3‑5 min gagnées. Recommandation revue : **reboot simple robuste par défaut, hibernation opt‑in**. À arbitrer (c'est un choix produit majeur). 2. **Swap : partition dédiée (repartition, robuste, sans offset) vs swapfile 96 GiO (aucun repartition, offset fragile).** Sur la machine déjà pleine, swapfile pragmatique ; sur install neuve, partition dédiée. Unifier ? 3. **Chiffrement de l'image d'hibernation (MVP en clair vs LUKS+TPM d'emblée).** Conditionne planning et gestion PCR. 4. **Voie Secure Boot : `sbctl` (db custom, reco) vs shim+MOK** (plus robuste OEM, prompt MokManager). Dépend de l'acceptation du firmware pour l'enrôlement db custom. 5. **Disque Windows : shrink de la racine nvme2n1 (même NVMe que l'ESP) vs un NVMe games (nvme1n1, boot cross‑disque).** Quel disque l'utilisateur sacrifie ? 6. **ESP partagée 512 MiO vs ESP Windows dédiée** lors du carve‑out (512 MiO très juste avec bootmgfw + noyaux + marqueur `return.json`). 7. **NTFS pré‑formaté (`mkfs.ntfs -Q`) vs espace non alloué + MSR** pour des mesures PCR/BitLocker les plus propres (à trancher par test). 8. **Retour auto (watcher WMI, risque heuristique AV) vs bouton manuel** (défaut reco = manuel). 9. **Bootstrap Windows : FWS pilote l'install (autounattend/SetupComplete, le plus propre) vs RunOnce offline** sur Windows existant. 10. **Politique clé de signature FWS : commune dans l'ISO (simple, fuite = compromission de flotte) vs générée par machine** (sûre, non industrialisable en masse). 11. **Taille NTFS par défaut : 150 vs 200 GiO** (recommandation : 200). 12. **Différer/figer Windows Update** sur le Windows gaming (mitigation brick dbx/SBAT #4) — acceptable pour l'utilisateur ? > **Portes bloquantes avant tout ship :** (a) kickstart rendu non destructif et testé sur ISO ; (b) resume GPU NVIDIA validé session chargée ; (c) swap ≥ RAM+VRAM ; (d) GRUB signé+`.sbat` avant activation SB ; (e) `BootNext` validé empiriquement sur la carte mère ; (f) média de récupération FWS prêt.