feat(gameboot-windows): add Windows dual-boot orchestration scripts for FWS gaming
Add PowerShell scripts to manage dual-boot transitions between FWS and Windows 11 for gaming sessions with Valorant. Includes: - fws-return.ps1: Arms firmware boot-next (one-shot) to target OS via bcdedit - fws-play.ps1: Orchestrates Valorant session with robust crash recovery - Install-FwsGameboot.ps1: Deploys scripts, disables hibernation, creates ONSTART task - README.md: Documentation on dual-boot workflow and prerequisites Design principles: - Minimal footprint, no Vanguard interference (no injection/kernel hooks) - Permanent fallback: BootOrder[0]=FWS catches unmanaged reboots - Robust locale-independent bcdedit parsing via EFI paths and GUIDs - Crash-proof game session: ONSTART task disabled during play to prevent mid-match boot changes
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
<#
|
||||||
|
Install-FwsGameboot.ps1 — installe le composant de RETOUR FWS dans Windows.
|
||||||
|
|
||||||
|
A lancer UNE FOIS, EN ADMIN, dans le Windows gaming. Deploie les scripts,
|
||||||
|
desactive l'hibernation/Fast Startup de Windows (pour un reboot PLEIN → NTFS
|
||||||
|
jamais "sale"), et cree une tache ONSTART (SYSTEM) qui arme le boot suivant
|
||||||
|
vers FWS des le demarrage — filet anti-crash : si Windows redemarre tout seul
|
||||||
|
(Windows Update, plantage) sans passer par fws-play, le boot suivant repart
|
||||||
|
vers FWS.
|
||||||
|
|
||||||
|
Empreinte minimale et SANS interference avec Vanguard : aucune injection,
|
||||||
|
aucun pilote/hook noyau — juste des scripts, une tache planifiee et un reglage
|
||||||
|
d'alimentation.
|
||||||
|
#>
|
||||||
|
#Requires -RunAsAdministrator
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$dest = Join-Path $Env:ProgramData 'FWS'
|
||||||
|
New-Item -ItemType Directory -Force -Path $dest | Out-Null
|
||||||
|
Copy-Item (Join-Path $PSScriptRoot 'fws-return.ps1') $dest -Force
|
||||||
|
Copy-Item (Join-Path $PSScriptRoot 'fws-play.ps1') $dest -Force
|
||||||
|
|
||||||
|
# (1) Pas d'hibernation Windows / Fast Startup : reboot PLEIN → volumes propres.
|
||||||
|
& powercfg /h off 2>$null
|
||||||
|
|
||||||
|
# (2) Tache ONSTART (SYSTEM) : armer le boot suivant vers FWS au demarrage.
|
||||||
|
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
|
||||||
|
-Argument ('-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "{0}\fws-return.ps1" -Target FWS' -f $dest)
|
||||||
|
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||||
|
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
|
||||||
|
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
|
||||||
|
Register-ScheduledTask -TaskName 'FWS-Return-OnStart' -Action $action -Trigger $trigger `
|
||||||
|
-Principal $principal -Settings $settings -Force | Out-Null
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Composant FWS installe dans $dest et tache 'FWS-Return-OnStart' creee." -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "RAPPELS IMPORTANTS :" -ForegroundColor Yellow
|
||||||
|
Write-Host " - NE PAS activer BitLocker (Device Encryption) sans sauvegarder la cle :"
|
||||||
|
Write-Host " le passage de Secure Boot OFF->ON cote FWS change PCR7 et declencherait"
|
||||||
|
Write-Host " l'ecran de recuperation BitLocker. (Verifie : manage-bde -status)"
|
||||||
|
Write-Host " - Pour un lancement AUTO de Valorant : ajouter fws-play.ps1 au demarrage"
|
||||||
|
Write-Host " de session du compte gaming (autologin), sinon lance-le a la main."
|
||||||
|
Write-Host " - Vanguard exige Secure Boot + TPM 2.0 + VBS/HVCI : ne les desactive pas."
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# FWS Gameboot — composant Windows
|
||||||
|
|
||||||
|
Composant à déployer **dans le Windows 11 gaming** (partition bare-metal dédiée)
|
||||||
|
pour le dual-boot orchestré « hibernate-swap » de FWS. Il gère le **retour vers
|
||||||
|
FWS** après une session de jeu.
|
||||||
|
|
||||||
|
> ⚠️ **Statut : v1 non validée sur matériel réel.** La sémantique
|
||||||
|
> `bcdedit /set {fwbootmgr} bootsequence` et le retour au boot dépendent du
|
||||||
|
> firmware de la carte mère. À tester avant de s'y fier. Voir le plan complet :
|
||||||
|
> `docs/hibernate-swap-dualboot.md`.
|
||||||
|
|
||||||
|
## Fichiers
|
||||||
|
|
||||||
|
| Fichier | Rôle |
|
||||||
|
|---|---|
|
||||||
|
| `fws-return.ps1` | Arme le boot suivant (one-shot) vers `FWS` ou `Windows`. |
|
||||||
|
| `fws-play.ps1` | Lance Valorant, attend sa fin/crash, puis rebascule vers FWS. |
|
||||||
|
| `Install-FwsGameboot.ps1` | Installe le tout + tâche ONSTART + `powercfg /h off`. |
|
||||||
|
|
||||||
|
## Installation (dans Windows, PowerShell **admin**)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Set-ExecutionPolicy -Scope Process Bypass -Force
|
||||||
|
.\Install-FwsGameboot.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Ces fichiers sont livrés par FWS dans
|
||||||
|
`/usr/local/share/fws/gameboot-windows/` ; l'outillage d'installation Windows de
|
||||||
|
FWS (à venir, cf. plan §6) les copiera sur la partition Windows. En attendant,
|
||||||
|
copie ce dossier à la main sur le Windows cible.
|
||||||
|
|
||||||
|
## Comment ça marche
|
||||||
|
|
||||||
|
1. Depuis FWS : `fws-gameboot to-windows` hiberne FWS et arme le boot suivant
|
||||||
|
vers Windows.
|
||||||
|
2. Windows démarre en **bare-metal** → Vanguard voit un vrai Windows natif.
|
||||||
|
3. Au démarrage, la tâche **ONSTART** arme le boot suivant vers FWS (filet
|
||||||
|
anti-crash).
|
||||||
|
4. `fws-play.ps1` (auto au login gaming, ou manuel) ré-arme Windows le temps du
|
||||||
|
jeu, puis, à la fermeture/crash de Valorant, arme FWS et redémarre.
|
||||||
|
5. FWS reprend sa session hibernée via `resume=`.
|
||||||
|
|
||||||
|
Filet permanent : côté FWS, `BootOrder[0] = FWS` est ré-affirmé à chaque
|
||||||
|
démarrage — tout reboot non géré retombe sur FWS.
|
||||||
|
|
||||||
|
## Rappels
|
||||||
|
|
||||||
|
- **BitLocker** : ne pas l'activer sans sauvegarder la clé (le flip Secure Boot
|
||||||
|
côté FWS change PCR7 → écran de récupération). `manage-bde -status` pour vérifier.
|
||||||
|
- Ne pas désactiver **Secure Boot / TPM / VBS-HVCI** : Vanguard les exige.
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<#
|
||||||
|
fws-play.ps1 — session de jeu Windows orchestree pour le retour vers FWS.
|
||||||
|
|
||||||
|
Flux robuste :
|
||||||
|
- on desactive la tache ONSTART (evite qu'un declenchement tardif ne rearme
|
||||||
|
FWS EN PLEIN MATCH) ;
|
||||||
|
- on arme le boot suivant vers WINDOWS (un crash/reboot pendant le jeu revient
|
||||||
|
sur Windows, pas ejecte vers FWS au milieu d'un match) ;
|
||||||
|
- on lance Valorant et on attend sa fermeture OU son crash ;
|
||||||
|
- dans un FINALLY (donc quoi qu'il arrive) : on rearme le boot suivant vers
|
||||||
|
FWS, on reactive la tache ONSTART, et on reboote — SEULEMENT si le jeu a
|
||||||
|
bien ete vu (pas de reboot force en plein 1er telechargement de patch).
|
||||||
|
|
||||||
|
Le filet permanent BootOrder[0]=FWS couvre tout ce que ce script raterait.
|
||||||
|
A lancer a l'ouverture de session du compte gaming (autologin) ou a la main.
|
||||||
|
Doit tourner EN ADMIN. #>
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$return = Join-Path $here 'fws-return.ps1'
|
||||||
|
$taskName = 'FWS-Return-OnStart'
|
||||||
|
$seen = $false
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Neutraliser la course avec la tache ONSTART pendant la session.
|
||||||
|
try { Disable-ScheduledTask -TaskName $taskName -ErrorAction Stop | Out-Null } catch { }
|
||||||
|
|
||||||
|
# Pendant la session, un crash/reboot doit rester sur WINDOWS.
|
||||||
|
try { & $return -Target Windows } catch { Write-Warning "Arm Windows a echoue : $_" }
|
||||||
|
|
||||||
|
# Lancer Valorant via le Riot Client (adapter le chemin si necessaire).
|
||||||
|
$riot = Join-Path $Env:ProgramFiles 'Riot Games\Riot Client\RiotClientServices.exe'
|
||||||
|
if (Test-Path $riot) {
|
||||||
|
Start-Process $riot -ArgumentList '--launch-product=valorant','--launch-patchline=live'
|
||||||
|
} else {
|
||||||
|
Write-Warning "Riot Client introuvable : $riot — lance Valorant manuellement."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Attendre l'apparition du process (SANS plafond serre : un 1er patch Riot /
|
||||||
|
# une MAJ Vanguard peuvent etre longs), puis attendre sa fermeture/crash.
|
||||||
|
$proc = 'VALORANT-Win64-Shipping'
|
||||||
|
for ($i = 0; $i -lt 1440; $i++) { # ~2 h max d'attente d'apparition
|
||||||
|
if (Get-Process $proc -ErrorAction SilentlyContinue) { $seen = $true; break }
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
}
|
||||||
|
if ($seen) {
|
||||||
|
Get-Process $proc -ErrorAction SilentlyContinue | ForEach-Object { $_.WaitForExit() }
|
||||||
|
} else {
|
||||||
|
Write-Warning "Jeu jamais detecte — pas de reboot automatique."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
# Rearmer FWS et reactiver la tache, QUOI QU'IL ARRIVE.
|
||||||
|
try { & $return -Target FWS } catch { Write-Warning "Arm FWS a echoue : $_ — BootOrder[0]=FWS reste le filet." }
|
||||||
|
try { Enable-ScheduledTask -TaskName $taskName -ErrorAction Stop | Out-Null } catch { }
|
||||||
|
if ($seen) {
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
Restart-Computer -Force
|
||||||
|
} else {
|
||||||
|
Write-Warning "Session sans jeu detecte : redemarre manuellement pour revenir a FWS (BootNext deja arme vers FWS)."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<#
|
||||||
|
fws-return.ps1 — arme le "boot suivant" du firmware (one-shot) vers une cible.
|
||||||
|
|
||||||
|
Cote FWS, l'equivalent est « efibootmgr --bootnext ». Cote Windows, on utilise
|
||||||
|
« bcdedit /set {fwbootmgr} bootsequence <id> » : la sequence de boot UNE FOIS
|
||||||
|
du firmware (consommee au prochain demarrage puis oubliee), pendant exact de
|
||||||
|
BootNext.
|
||||||
|
|
||||||
|
IMPORTANT (robustesse locale) : on NE parse PAS les libelles traduits de
|
||||||
|
« bcdedit /enum firmware » (sur un Windows francais « identifier » devient
|
||||||
|
« identificateur », « Windows Boot Manager » -> « Gestionnaire d'amorçage
|
||||||
|
Windows »). On resout :
|
||||||
|
- Windows : par l'alias NON localise {bootmgr} (aucun parsing) ;
|
||||||
|
- FWS : par le CHEMIN EFI (\EFI\FWS\ ou \EFI\GRUB\ ou grubx64.efi), qui
|
||||||
|
n'est pas traduit, en associant le GUID (motif stable) du bloc.
|
||||||
|
Si FWS est introuvable, on DESARME la one-shot (deletevalue) pour retomber
|
||||||
|
proprement sur BootOrder[0]=FWS plutot que de laisser une bascule erronee.
|
||||||
|
|
||||||
|
Doit tourner EN ADMIN. Usage : fws-return.ps1 -Target FWS | -Target Windows
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[ValidateSet('FWS','Windows')]
|
||||||
|
[string]$Target = 'FWS'
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Set-BootSequence([string]$id) {
|
||||||
|
& bcdedit /set '{fwbootmgr}' bootsequence $id | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "bcdedit bootsequence $id a echoue (code $LASTEXITCODE)." }
|
||||||
|
}
|
||||||
|
function Clear-BootSequence {
|
||||||
|
& bcdedit /deletevalue '{fwbootmgr}' bootsequence 2>$null | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Target -eq 'Windows') {
|
||||||
|
# Alias non localise -> aucun parsing, aucune dependance a la langue.
|
||||||
|
Set-BootSequence '{bootmgr}'
|
||||||
|
Write-Host "Boot suivant arme vers Windows ({bootmgr})."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Target = FWS : resoudre le GUID de l'entree firmware pointant vers FWS ---
|
||||||
|
# /v force l'affichage des GUID complets. On matche le CHEMIN (non localise),
|
||||||
|
# pas la description (localisee).
|
||||||
|
$fw = & bcdedit /enum firmware /v 2>$null
|
||||||
|
if (-not $fw) { throw "bcdedit /enum firmware n'a rien renvoye (droits admin ?)." }
|
||||||
|
|
||||||
|
$reId = '\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}|\{[a-z]+\}'
|
||||||
|
$rePath = '(?i)\\EFI\\(FWS|GRUB)\\|grubx64\.efi'
|
||||||
|
|
||||||
|
$curId = $null; $fwsId = $null
|
||||||
|
foreach ($line in $fw) {
|
||||||
|
$m = [regex]::Match($line, $reId)
|
||||||
|
if ($m.Success) { $curId = $m.Value; continue }
|
||||||
|
if ($line -match $rePath -and $curId) { $fwsId = $curId; break }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $fwsId) {
|
||||||
|
# Rien trouve par le chemin : on ne devine PAS. On desarme toute one-shot
|
||||||
|
# pour retomber sur BootOrder[0]=FWS (filet permanent cote FWS).
|
||||||
|
Clear-BootSequence
|
||||||
|
throw "Entree firmware FWS introuvable (chemin \EFI\FWS ou \EFI\GRUB). One-shot desarmee -> BootOrder assure le retour vers FWS."
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-BootSequence $fwsId
|
||||||
|
Write-Host "Boot suivant arme vers FWS = $fwsId"
|
||||||
Reference in New Issue
Block a user