- La multiplication en virgule flottante du VU de la PS2 comporte une erreur d’opération d’1 bit, si bien que pour certaines valeurs,
1 * Xpeut différer deX - D’après le manuel développeur du VU,
X * 1est garanti exact, mais1 * Xne bénéficie pas de la même garantie, et cette différence devient un signal de détection d’émulateur - L’exemple utilise 129.5f, choisi parmi des valeurs problématiques trouvées par force brute, pour vérifier la différence de comportement entre une vraie PS2 et un émulateur
- L’implémentation, en mode macro VU0, consiste simplement à multiplier
129.5fpar1, puis à vérifier si le résultat diffère de l’entrée d’origine - PCSX2, Play!, DobieStation et hps2x64 n’émulent actuellement pas ce comportement, et la difficulté de détection est évaluée à 1/5
Erreur d’1 bit dans la multiplication VU de la PS2
- Cette méthode est le deuxième volet d’une série sur la détection d’émulateur PS2, et peut être utilisée avec VU1, le mode micro de VU0 et le mode macro de VU0
- L’exemple utilise le mode macro de VU0 pour simplifier l’implémentation
- VU0 est utilisé comme un coprocesseur, donc l’exécution peut se faire directement depuis le CPU EE
- Il n’est pas nécessaire de manipuler un programme VU séparé
- Le manuel développeur du VU indique dans les commentaires des instructions de multiplication comme
MULetMULiqu’il existe une erreur d’opération d’1 bit1 * Xpeut différer de la valeur d’origineX- Si
VF[fs]est utilisé comme multiplicande, l’exactitude du résultat sous la formeX * 1est garantie
- La raison exacte de cette perte de bit n’est pas clairement établie
Valeur de détection et méthode d’implémentation
- Pour détecter cette erreur, il faut un nombre qui la provoque, et la méthode de recherche la plus simple est la force brute
- L’auteur a auparavant établi une liste des 250 premiers nombres, espacés de 0.5, qui provoquent le problème, et l’a publiée dans ce gist
- Le code d’exemple utilise 129.5f comme valeur cible pour la détection
QMTC2définit129.5fdansVF1VADDwcrée1dansVF2VMULcalculeVF1 = 1 * 129.5fQMFC2rapatrie le résultat côté EE pour le comparer à l’entrée
- La valeur de retour est
in[0] != out[0], et si la valeur d’origine diffère du résultat de la multiplication, on considère que l’erreur de multiplication VU est présente
Impact selon les émulateurs
- Actuellement, PCSX2, Play!, DobieStation, hps2x64 n’émulent pas ce comportement de multiplication VU de la PS2
- Comme il suffit de multiplier un nombre par
1puis de vérifier le résultat, la difficulté de cette méthode de détection est estimée à 1/5
1 commentaires
Avis sur Hacker News
Sur un vrai ARM, à cause du pipeline, le processeur lit PC+8 pendant qu’il exécute PC et décode PC+4, donc l’instruction nouvellement écrite ne devrait pas avoir d’effet. Un émulateur qui ne reproduit pas le pipeline matériel finira par exécuter cette instruction
Un article qui l’explique plus en détail, avec plusieurs techniques anti-émulation de 2004 : https://mgba.io//2014/12/28/classic-nes/
Il semble que la valeur du registre soit restée indéfinie pendant quelques cycles. Écrire du code assembleur optimisé au cordeau pour ce genre de puce donnait une impression assez atroce, comme jouer à un clone de Zachtronics particulièrement pervers
Bien plus tard, quelqu’un a trouvé un autre cas limite non détecté : une instruction de chaîne répétée qui s’écrase elle-même
https://silviocesare.wordpress.com/2009/02/02/anti-debugging...
x86 a ce type de mécanisme, mais je ne sais pas s’il a fini par être supprimé dans la variante 64 bits
Il faut non seulement connaître tous les comportements particuliers du matériel et du logiciel d’origine, mais aussi les reproduire tels quels, aussi étranges soient-ils. C’est déjà difficile en soi, et il faut encore tenir compte de l’impact sur les performances
Utiliser un recompileur JIT empêche d’être parfaitement exact au cycle près par rapport au matériel d’origine, mais ce n’est généralement pas un problème, sauf si le code du jeu a été conçu exprès pour casser les émulateurs
Dolphin a lui aussi dû gérer cet équilibre quand quelques jeux Wii commerciaux ont inclus du code anti-émulateur exploitant des détails du comportement du cache du vrai CPU Wii. En théorie, il aurait été possible d’émuler le vrai cache CPU pour faire tourner le jeu correctement, mais le surcoût en performances aurait probablement ralenti le tout d’un facteur 10, rendant le jeu injouable ; ils ont donc choisi un patch de contournement
https://dolphin-emu.org/blog/2017/02/01/dolphin-progress-rep...
On dirait qu’il faut à la fois comprendre l’électronique et une forme de sorcellerie avancée en programmation
Au début, et même dans la plupart des cas à la fin, il n’est pas nécessaire de comprendre une magie profonde. En général, il suffit de lire les spécifications et de les implémenter telles quelles. Il faut savoir structurer son code pour que cela ne devienne pas ingérable, mais il existe des schémas courants, et après avoir créé un ou deux émulateurs, cela devient beaucoup plus simple
Il est aussi rarement nécessaire de comprendre l’électronique. Ce qu’on émule, c’est le comportement. Quand on découvre un bug dans le comportement du matériel d’origine, il suffit généralement d’ajouter un traitement spécial dans l’émulateur. Des connaissances en électronique peuvent aider à comprendre pourquoi ce comportement existe, mais c’est plus de l’intérêt historique qu’un besoin pratique
Il existe des difficultés propres à ce domaine. Quand un problème survient, on se retrouve souvent à déboguer en même temps sa compréhension du matériel, l’implémentation de l’émulateur et le jeu en cours d’émulation. Il peut être difficile d’isoler la cause exacte. Cela dit, je recommande quand même de bricoler quelque chose rapidement. Ce n’est pas élégant, mais tous les émulateurs sont pleins de traitements spéciaux destinés à faire fonctionner tant bien que mal les jeux populaires. Si quelques hacks sales suffisent à faire tourner un jeu, alors il faut les faire. Il n’est pas nécessaire de reproduire exactement le comportement du matériel d’origine ; il faut simplement faire en sorte que le jeu fonctionne
Un CPU 8 bits est une simple machine à états qui ne possède que quelques octets d’état, c’est-à-dire des registres. Il suffit de lire le programme octet par octet et d’imiter ce que le CPU ferait après avoir lu chacun de ces octets. Ce sont des opérations très simples, comme additionner ou soustraire des nombres, ou lire et écrire des octets
http://www.6502.org/users/obelisk/6502/registers.html
http://www.6502.org/users/obelisk/6502/instructions.html
Un émulateur de CPU 6502 lit les quelques octets suivants du programme, interprète ces octets comme des instructions, puis exécute ces instructions. Au passage, il met à jour quelques registres ou compteurs du CPU, effectue des opérations arithmétiques ou bit à bit et, si nécessaire, lit ou écrit 1 octet de données d’un emplacement à un autre. Il répète ce processus dans une boucle infinie
Il s’agit d’une simulation du cycle extraction-décodage-exécution
https://en.wikipedia.org/wiki/Instruction_cycle
Il y a longtemps, j’ai porté un interpréteur 6502 d’UNIX vers le Classic Macintosh pour lire des fichiers de musique SID. Il suffisait qu’il tourne assez vite, donc la précision au cycle d’horloge n’avait pas d’importance
Il fonctionnait en appelant du code C depuis l’interpréteur
J’ai toujours envie d’essayer, mais je n’ai pas le temps
À part ça, le commentaire frère de @xcv123 dit vraiment juste
Si un jour il devient possible de recréer la PS2 sur FPGA, comprendre comment ce comportement se produisait pourrait devenir un projet amusant pour quelqu’un
Rien ne garantit qu’une version FPGA de la PS2 n’implémenterait pas le même bug, ou un bug similaire
La virgule flottante logicielle serait lente, mais la solution générale suivrait probablement l’émulateur PS2 de la PS4 : mettre sur liste blanche, jeu par jeu, les sections de code autorisées à utiliser un chemin de virgule flottante logicielle
Il m’a fallu bien trop longtemps pour comprendre qu’il s’agissait de la PlayStation 2, et non du port Personal System/2 qui sert à connecter souris et clavier
Les sigles de trois lettres peuvent rendre le contexte vraiment difficile à trouver. Si on tape seulement le sigle dans Google, on obtient assez souvent en majorité des résultats presque sans rapport