# 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"
# GRUB_DISABLE_OS_PROBER=true   (aucune entrée GRUB->Windows -> PCR4/PCR7 propres)
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 `<ESP>/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=<swap> (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 <FWS>,…,<Windows>` (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.