23 KiB
Passation — simulateur iPod Touch 2G / iPhone OS 2.2.1
État au 2026-10-01. Environnement : conteneur Arch Linux, utilisateur dev avec sudo, sans CAP_NET_ADMIN, sans /dev/ppp ni TUN.
Redémarrage à chaud de l'interface
Le blocage de respring est reproduit sur 5H11a : le nouveau SpringBoard reste
bloqué dans IOServiceClose, après l'ouverture d'AppleM2TVOut. Le modèle de
sortie TV limitait ses interruptions à deux pour toute la vie de QEMU. Il répond
maintenant à chaque soumission, conserve les événements masqués et acquitte les
bits demandés. Le LCD dispose également de registres distincts pour le masque
(0x08) et l'état W1C (0x0c), conformément aux accès du pilote AppleM2CLCD.
Pour le reset matériel, les états LCD, TV et MIPI sont réinitialisés. La machine réalise désormais le périphérique MIPI : sans cette étape, son callback de reset n'était jamais appelé, ce qui faisait échouer la lecture de l'identifiant de dalle. Le tactile libère les transferts/trames en cours, annule ses timers et relâche son interruption. SPI vide ses FIFO et abaisse aussi sa ligne d'interruption.
ipod-emu respring -W et ipod-emu reset -W synchronisent la NAND, mémorisent
la position du journal puis attendent uniquement les nouveaux marqueurs. Le
client unlock utilise la même position. ipod-agent respring et ipod-qmp reset
restent des commandes brutes ; utiliser le lanceur pour attendre le nouveau boot.
Régressions : neuf tests tactile/SPI et trois tests d'affichage sous ASan/UBSan,
cinq tests du lanceur et trois resets QMP/QTest des périphériques d'affichage
réels. Le test natif tests/test-display-session.py vérifie le déverrouillage,
la calculatrice au premier plan, HTTP local, le fichier témoin en NAND et les PID
QEMU/relais conservés. Diagnostics : work/interface-20261001/.
Validation native finale : trois resprings et deux resets complets par firmware
(5H11a et 5F138), avec les mêmes PID QEMU/relais. La calculatrice affiche
7 × 8 = 56 après les relances sur les deux versions. Les resprings complets
prennent environ 26–28 s, les resets 64–80 s dans cet environnement partagé.
Synthèse : work/interface-20261001/validation-finale.json.
La session utilisateur sur VNC 5900 reste sur le binaire précédemment déployé.
Reprise PPP après reset matériel
L'UART possède maintenant un callback de reset : registres et FIFO remis à
zéro, IRQ baissée, qemu_chr_fe_disconnect sur la connexion série. La fermeture
fait repartir la machine LCP/IPCP du relais existant, sans tuer ipod-netd ni
QEMU et sans remplacer la NAND. ipod-qmp reset expose le reset brut ; faire
ipod-agent sync avant son utilisation.
Validation native avec l'agent v12 : deux resets successifs par firmware,
5H11a (48,2 / 51,3 s) et 5F138 (48,4 / 51,6 s), mêmes PID QEMU et relais,
fichier témoin conservé et requête HTTP locale réussie depuis l'iPod.
Le diagnostic attend ppp0 up et configd publié, puis laisse cinq secondes
au réseau avant les transferts. Des fermetures TCP ponctuelles ont été observées
avec des requêtes immédiatement après les premiers pings ; un ping isolé ne
suffit donc pas à qualifier la stabilité du service.
Les deux régressions UART passent sous ASan/UBSan, dont trois reconnexions avec
émission et réception sur un vrai backend socket QEMU.
Les premiers essais du correctif PPP laissaient encore l'affichage bloqué après
reset. Les causes et les corrections sont décrites dans la section précédente.
Les anciens diagnostics sont conservés dans work/ppp-20261001 ; ils précèdent
la correction de la sortie TV et ne décrivent plus l'état actuel du code.
Dernière mise à jour — RTC D1759
Le modèle d1759 remplace pcf50633 sur la machine 2G. Il corrige le
pointeur I²C et fournit le compteur LE32 en 0x5c avec décalage Unix LE32 en
0x64. Les notes anciennes attribuant un accès indirect RTC à 0x61/0x62
étaient incorrectes : ces registres concernent le démarrage.
start -W et wait ne règlent plus l'heure via l'agent.
Voir RTC.md pour le protocole, les preuves et les limites.
Le raccordement GPIO est aussi borné aux cinq IRQ définies, pour éviter
l'accès hors limites révélé à la recompilation.
Validation du 1er octobre 2026 — iPhone OS 2.1.1
- Image distincte
5F138-validation-20261001, créée depuis la base 5F138 conservée, avec agent v12, TouchProbe et HelloEmu. Session :work/validation-20261001/.system-version.plistconfirme 2.1.1 / 5F138 ; démarrage déverrouillé en 28 s. - Calibration : sept points exacts de
(20,40)à(300,460)danscalibration-complete.log, après attente du marqueurTouchProbe ready. Les ordonnées du journal sont relatives à la vue, située à y=20. - Six cycles alternant Power/Home et Power/Power passent, sans perte du tactile.
- Safari : clavier virtuel QWERTY, formulaire envoyé avec
texte=bonjour, défilement jusqu'au lien final et requête/finreçue par le serveur HTTP local. Journal :http/requests.jsonl. Une version réutilisable de la page et du serveur est fournie danstests/http-fixture.py; aucun site extérieur n'est requis. - Calculatrice :
7 × 8 = 56, capturecalculatrice-56.png. - Notes : note « Bonjour » créée par le clavier virtuel puis sauvegardée.
Les lignes de
Noteetnote_bodiessont identiques dansnotes-avant.dbetnotes-apres.db, et la note réapparaît dans l'interface après redémarrage. - Nouvelle app
HelloEmu21.app(bundle-idcom.ioslegacy.hello21) installée viapush-app, cache reconstruit, redémarrage sans réinitialiser la NAND en 50 s, lancement au premier plan et journal HelloEmu validés. Captures :hello21-apres-push.pngetnote-apres-reboot.png. - Synthèse locale :
validation.json. Session et serveur HTTP de test arrêtés. Aucun défautKilling device,Fatal ExceptionouMACH Rebootrelevé dans la console finale. Les images et NAND d'origine sont conservées. - Particularités : l'image 5F138 conserve ses réglages de langue et de fuseau
d'origine ; les captures sont en anglais. Le lancement
--urld'un Safari déjà ouvert n'a pas changé la page pendant le test : passer par les liens ou relancer le navigateur. Le RTC est depuis implémenté (voir ci-dessus) ; la veille profonde reste à faire.
Historique — fiabilisation GPIO/SPI et agent v12
Les sections de diagnostic plus anciennes ci-dessous décrivent les étapes précédentes.
Le workflow push-app puis déverrouillage/lancement a été validé avec l'agent v11.
Cette suite corrige les débordements GPIO/SYSIC, les commandes tactiles invalides,
les trames instables et les transactions SPI abandonnées à la reprise de l'écran.
Huit cycles veille/réveil alternant Home et Power ont passé sur 5H11a sans perte
du tactile. La calibration TouchProbe retrouve les coordonnées écran sur sept
points ; la vitesse verticale et le calcul signé des vitesses sont corrigés.
L'agent v12 conserve le protocole et transfère par blocs de 64 Kio avec fichiers
temporaires distincts. ipod-test-app prépare une NAND indépendante, vérifie le
premier plan, récupère journal et capture, puis arrête sa propre session.
Voir le README pour les commandes et les tests reproductibles ASan/UBSan.
Validation finale : huit régressions matérielles avec ASan/UBSan et sept tests
sur les transferts ; HelloEmu réussit le workflow automatique, l'application
absente échoue avec capture et arrêt de la VM. Un fichier de 8 460 608 octets
fait l'aller-retour via l'agent v12 avec SHA-256 identique. Trois cycles de
veille/réveil supplémentaires avec la calibration finale et l'agent v12 passent,
puis HelloEmu se lance au premier plan avec son journal. Diagnostics locaux :
work/fiabilisation-20260930/ (dont test-hello, test-echec, hello-final.png).
Les sessions de validation sont arrêtées.
Les fichiers générés, images et diagnostics restent hors du dépôt. Les images
5H11a et les NAND d'origine sont conservées ; le RTC, le Wi-Fi matériel, l'audio
et la veille profonde restent à implémenter. Les nouveaux correctifs n’étaient
pas encore validés sur 5F138 à cette étape.
Objectif
On fournit un simulateur d'iPod Touch 2G sous iPhone OS 2.2.1 qui sert surtout à un agent IA pour tester les applications iOS 2.x d'AlloVoisins. Les apps sont compilées en armv6 avec /opt/cctools et /opt/theos/sdks/iPhoneOS2.2.1.sdk. L'agent doit pouvoir faire les choses suivantes, sans intervention humaine :
- installer une app ;
- la lancer ;
- lire ses logs ;
- toucher l'écran et prendre des captures ;
- utiliser le réseau.
On veut le comportement le plus fidèle possible à un vrai appareil. La consigne de l'utilisateur est de travailler en autonomie et de se créer ses propres outils, voire une skill.
Ce qui marche
- Boot 2.2.1 (5H11a), SpringBoard prêt en environ 25 s.
- 2.1.1 (5F138) marche aussi, avec l'ancienne image de devos50.
- Écran : capture 320×480 par QMP. Touch, boutons et VNC sur
127.0.0.1:5900. - Réseau / Internet : PPP sur l'UART1 émulée, relié à
ipod-netdcôté hôte (libslirp, en userland).- iPod en 10.0.2.15, passerelle 10.0.2.2, DNS 10.0.2.3.
- Le DNS et HTTP marchent depuis l'iPod, et Safari affiche example.com.
- Agent sur l'iPod (
emuagent, v10), joignable depuis l'hôte sur127.0.0.1:7788viaipod-agent. Commandes :launch(bundle id, avec--logpour stdout/stderr et--url),apps,front;exec,ps,kill,respring;put,get,ls,rm,mkdir;fetch,net,routes,sc(SCDynamicStore) ;settime,sync.
- Persistance NAND : programmation des pages et métadonnées, effacement des blocs de 128 pages et détection des
pages vierges fonctionnent avec le format VSVFL de production. La base 5H11a a été migrée ;
nand-write=onest inscrit dans ses options machine. Les nouveauxipod-build-fw/ipod-mkimageutilisentgen-v1/mknand. - Apps :
ipod-mkimage MonApp.app|.ipa|.deb|dossier/construit une image dérivée. Les apps signées avecldidpassent grâce au boot-argamfi_allow_any_signature. - Heure :
start -W/waitenvoiesettimedès que l'agent répond, avant la fin du démarrage de SpringBoard. Ce réglage précoce évite d'initialiser les timers de l'interface en 1970 avec des préférences datées dans le futur. - Veille : agent v10, propriété
SleepDisabled=truesurIOPMrootDomain(acceptée). Les assertions publiquesIOPMAssertionCreateWithNamesont non supportées sur ce firmware. Le SoC ne sait toujours pas reprendre une veille. - Réglages de l'image : langue fr, région fr_FR, fuseau Europe/Paris. Verrouillage auto désactivé, pas d'alerte « Edit Home Screen ».
- Reconstruction complète depuis l'IPSW Apple :
ipod-build-fw 5H11a.
Limites connues, et suite logique par priorité
- Installation / lancement dans une session conservée : les apps copiées dans
/Applicationssont maintenant persistées, mais la reconstruction du catalogue lors d'unrespringreste peu fiable.push-appsynchronise puis redémarre l'émulateur sans-fet sans reconstruire l'image. Le lancement après ce redémarrage répond encore parfoisdevice locked; un écran de code a été observé dans l'image de test. Ne pas annoncer ce workflow comme entièrement validé.ipod-mkimagereste disponible pour intégrer l'app avant le premier démarrage.- La persistance elle-même est validée : témoin texte et binaire de 256 Kio identiques après redémarrage ; fichier
aléatoire de 8 Mio conservé, SHA-1 calculé dans l'iPod identique à l'hôte :
4d322e06f3433b874bc77d8b0298d97346210eb5. - Le téléchargement de 8 Mio par
geta été tronqué. Le client vérifie désormais la longueur reçue et signale ce cas. Utiliser un calcul d'empreinte dans l'iPod pour distinguer le transport de l'intégrité NAND. - Ancienne base sauvegardée :
images/5H11a/nand-readonly-backup,rootfs-v8-backup.img,machine-opts-readonly-backup. Session d'origine :run/nand-before-persistenceetfw-before-persistence. Session de test avec app et fichier de 8 Mio :run/nand-persistence-verified(firmwarepersistence-test-v10).
- La persistance elle-même est validée : témoin texte et binaire de 256 Kio identiques après redémarrage ; fichier
aléatoire de 8 Mio conservé, SHA-1 calculé dans l'iPod identique à l'hôte :
- Horloge RTC du PMU : compteur et décalage D1759 implémentés ; IRQ d'alarme et persistance du décalage entre instances QEMU restent absentes. Voir la dernière mise à jour et
RTC.md. - Réglages > Wi-Fi affiche « Pas de Wi-Fi », parce que la puce BCM4325 n'est pas émulée. Le réseau passe par une interface ppp0, que l'app peut voir comme un VPN ou une connexion transitoire. Émuler le WiFi pour de vrai (SDIO + firmware FullMAC) serait un gros chantier ; le pont slirp est réutilisable.
- Pas encore écrits :
- un script
ipod-test-app(construit l'image, boote, lance l'app avec--log, fait une capture, affiche les logs) ; - une skill Claude/Codex qui documente ce workflow ;
- la mise à jour de
~/ipod-emu/README.md(réseau, agent, heure, français).
- un script
- Mise à jour de l'agent à chaud (
putpuiskill emuagent) : elle coupe PPP pendant la renégociation. Préférer reconstruire l'image.
Démarrer
ipod-emu start -f -W # 2.2.1 (défaut), NAND vierge, attend SpringBoard
ipod-agent ping # l'agent répond quand PPP est monté (quelques secondes)
ipod-agent launch com.apple.mobilesafari --url http://example.com/
ipod-qmp screenshot /tmp/s.png # tap X Y | swipe | home | hmp "info registers"
ipod-emu stop
Ne jamais toucher l'écran avant la fin de ipod-emu wait ou start -W : le contrôleur tactile fait planter QEMU s'il est touché pendant son démarrage.
Logs :
~/ipod-emu/run/serial.log: console kernel et syslog, pppd, emuagent ;~/ipod-emu/run/qemu.log;~/ipod-emu/run/netd.log: avecIPOD_NETD_FWD=-v, trace de chaque paquet IP.
Debug : IPOD_QEMU_EXTRA="-d unimp,guest_errors -D ~/ipod-emu/run/int.log" ; IPOD_QEMU=~/ipod-emu/bin/qemu-gdb pour avoir une backtrace en cas de crash.
Carte des fichiers
| Où | Quoi |
|---|---|
~/qemu-ios |
Fork Mahtan/devos50 (branche ipod_touch_2g). Sources et outils sauvegardés dans le dépôt (outils sous contrib/ipod-emu). Build : cd build && make -j4 |
/opt/ios-legacy/bin/ |
Copies installées des outils (réinstaller avec sudo install -m 755 ~/ipod-emu/bin/X /opt/ios-legacy/bin/) |
~/ipod-emu/bin/ipod-emu |
Launcher : QEMU (serial0 = fichier, serial1 = run/uart1.sock), ipod-netd, wait, settime |
~/ipod-emu/bin/ipod-qmp |
Écran, touch, boutons, HMP |
~/ipod-emu/bin/ipod-agent |
Client de l'agent (protocole : ligne à champs séparés par TAB, réponse OK <n> [info]\n + n octets) |
~/ipod-emu/bin/ipod-mkimage |
Image dérivée avec apps / .deb / overlay (re-signe avec ldid en gardant les entitlements) |
~/ipod-emu/bin/ipod-build-fw |
IPSW → NOR + rootfs (mkbase-rootfs) + NAND (gen-v1/mknand, VSVFL de production, signature 2 et écritures activées) |
~/ipod-emu/bin/mkbase-rootfs |
LaunchDaemons réduits, fstab rw, Lockdown (assets/), prefs, fr/Paris, intègre agent/overlay |
~/ipod-emu/agent/ |
emuagent.c + Makefile (make → overlay/), entitlements.plist (com.apple.springboard.launchapplications etc., indispensables pour SBSLaunchApplication) |
~/ipod-emu/netd/ipod-netd.c |
Serveur PPP (HDLC, LCP, IPCP) ↔ libslirp. gcc -O2 -o ipod-netd ipod-netd.c $(pkg-config --cflags --libs slirp) -Wno-deprecated-declarations |
~/ipod-emu/bin/armdis.py, dtdump.py |
Désassembleur capstone (base, début, fin, arm) et dump du DeviceTree. Kexts du kernelcache : base de fichier 0xc0029000 |
~/ipod-emu/fw-5H11a/dec/ |
kernelcache, iBoot, LLB, DeviceTree déchiffrés (clés via api.ipsw.me) |
~/ipod-emu/xpwn/ |
Outil hfsplus (patché : grow alloue ensuite dans l'espace neuf) |
Découvertes clés (modifs QEMU)
- AES (
ipod_touch_aes.c) :- clé GID choisie d'après le contenu du KBAG (
ipod_touch_gid_keys.h) ; - le dernier bloc incomplet d'une IMG3 est laissé en clair ;
- la vérification de longueur LZSS d'iBoot est patchée, trouvée par signature ;
- dans le DeviceTree déchiffré, les propriétés DMA de
uart1sont renommées : le pilote reste en PIO.
- clé GID choisie d'après le contenu du KBAG (
- SHA1 (
ipod_touch_sha1.c) : c'est une fonction de compression brute.CONFIG 0x2= premier bloc,0x8puis0xa= suite ;- état H0–H4 lisible et écrivable, mots byte-swappés ;
- bit
0x4= mode asynchrone, avec IRQ 40 (activée par0x0c, acquittée par0x08, levée par un timer de 20 µs).
- UART (
ipod_touch_uart.c, nouveau modèle, remplace l'Exynos) :- IRQ activées dans UCON (
0x2000TX,0x1000/0x0880RX) ; - flags en attente dans UTRSTAT (
0x08/0x10/0x20), effacés en écrivant 1 ; UFSTAT: un FIFO plein vaut 0 + le bit0x100;- FIFO limité à 8 octets.
- IRQ activées dans UCON (
- NAND / FMSS (
ipod_touch_fmss.c) :- La programmation
CSGENRC=0xa02utilise une liste de paires enD10, terminée par un mot zéro.D08=8est la taille d'une paire, pas le numéro de page ;D18est une ancienne valeur de lecture. - Premier mot : masque CE dans les bits 0–3, commande 80h/81h dans les bits 16–23 et flags dans les autres bits.
Deuxième mot : page physique.
D20pointe deux adresses de données (2048 octets chacune) par page ;D1Ccontient les métadonnées de 12 octets. Toutes les paires doivent être enregistrées. - Effacement reconnu dans la liste du séquenceur
C04par les écritures immédiates NAND 60h/D0h ;D0Cpointe la page de début de bloc,D10un index CE,D18=1. Supprimer les 128 fichiers de pages du bloc. - Une page sans fichier est vierge (
FF).C30=0x20000000pour une lecture entièrement vierge fait retourner0xe00002e5par le pilote ; sans ce statut,_FTLRestoreignore les blocs de logs et perd les écritures. - Les autres micro-commandes restent émulées par les chemins de haut niveau existants ; pas d'interpréteur complet.
.ipod-nand-format=vsvfl-production-v1dans la NAND : le launcher refusenand-write=onsur une ancienne image.
- La programmation
- Écran MIPI DSI :
CLKCTRL[31]contrôleSTATUS.TxReadyHsClk; le bit doit aussi pouvoir retomber à zéro. Le modèle précédent le renvoyait toujours actif, bloquant le pilote lors de l'arrêt de l'écran. - Machine :
- stubs RAM MPVD (
0x39600000) et0x38100000; - la NAND 2.2.1 exige la signature
0x43313132; - options
legacy-noretnand-write.
- stubs RAM MPVD (
- Réseau iOS :
- pppd est lancé avec
serviceid emuppp; - l'agent publie
Setup:/Network/Service/emupppetSetup:/Network/Global/IPv4 ServiceOrder, sans quoi IPMonitor n'installe ni route ni DNS ; - mDNSResponder est réactivé (nécessaire au DNS) ;
- tous les descripteurs passés à pppd doivent être
FD_CLOEXEC; - SpringBoard refuse
SBSLaunchApplicationsans l'entitlementlaunchapplications.
- pppd est lancé avec
Pièges
pkill -f 'ipod-netd -s'tue aussi le shell qui lance la commande : utiliserpkill -x ipod-netd.ipod-build-fwréécritimages/5H11a/. Refairemakedansagent/avant, si l'agent a changé.-fefface la session persistée. Ne pas l'utiliser pour vérifier la conservation d'un fichier.- QEMU et netd sont lancés avec
setsidpour survivre à la fin du terminal appelant. Le launcher suit netd par PID. - Un
.deb2.x qui dépend d'un jailbreak (bash, etc.) ne marchera pas : aucun shell dans l'image.
Reprise du 30 septembre 2026 — après déplacement des homes
- Projets retrouvés sous
/srv/homes/iphoneos2/{ipod-emu,qemu-ios}. - Bibliothèques QEMU/libslirp et ImageMagick réinstallées dans le conteneur courant ;
lien BootROM 5H11a corrigé en relatif ; commandes accessibles par wrappers dans
/home/dev/.local/bin. Ces installations locales ne modifient pas l'image Docker. - Lanceur adapté aux chemins déplacés, sélection automatique des keymaps via
-L, contrôle du démarrage QEMU et du relais, nettoyage du relais même après arrêt QEMU.ipod-qmpprend en compteIPOD_EMU_HOME. - Test sur une copie de NAND dans
ipod-emu/work/reprise-20260930: boot de l'image de base en 28 s, Safari et HTTP validés.push-app HelloEmu.appcopie les deux fichiers, redémarre sans réinitialiser la NAND ; HelloEmu apparaît ensuite dans le catalogueapps. Le lancement répond toujoursdevice locked, écran noir. Le programme de diagnosticunlockretourne 0 sans débloquer le lancement. Ne pas considérer le lancement après installation comme validé. - La copie de la session initiale est conservée dans
work/reprise-20260930/run-session-initiale; la session d'originerun/nandn'a pas été modifiée. Les captures et préférences de diagnostic sont dans le dossier de reprise. Les sessions de test ont été arrêtées. - Un ancien relais survivant à QEMU occupait 7788 : supprimé avant de refaire le test. L'ancien code continuait malgré l'échec de redirection ; le nouveau échoue.
- Vérifications : syntaxe Bash/Python, compilation du relais avec
-Wall, échec QEMU volontaire détecté immédiatement, port 7788 occupé détecté et QEMU arrêté,stopaprès échec. Aucun changement des modèles matériels dans cette reprise.
Correction du verrouillage — agent v11
SBGetScreenLockStatusconfirmelocked=1 passcode=0après redémarrage.SBApplicationRequestedDeviceUnlockréveille un clavier de code sans déverrouiller.- Solution validée :
SBDimScreen(port, false), attendre deux secondes, glisser(60,450)→(319,450), attendre deux secondes, vérifierlocked=0. Le geste historique(40,430)→(280,430)n'atteint pas correctement le bord de la surface tactile émulée. Home/Power et gestes lors de la reprise du pilote peuvent encore provoquer un arrêt QEMU ; aucun correctif matériel n'est revendiqué. - Agent v11 : commandes
screenetwake. Client :unlock, vérification des marqueurs de disponibilité, refus si un code est actif, trois essais maximum.start -W/waitne rendent la main avec succès qu'après déverrouillage. - Validations sans débogueur sur la session copiée : démarrage en 36 s ; nouvelle
installation de HelloEmu avec
push-app, redémarrage conservant la NAND en 47 s,launchréussi etfront=com.allovoisins.helloemu. Capture :work/reprise-20260930/hello-v11-apres-push.png. - L'agent v11 a été installé atomiquement dans la session de test puis synchronisé
avant redémarrage ; aucune relance à chaud de l'agent/PPP.
Nouvelle image
images/5H11a-agent-v11construite avec l'overlay de l'agent, sans modifier l'image 5H11a ni la NAND d'origine. L'image de base v10 doit être mise à jour avant d'utiliser le déverrouillage automatique. - La faute
diff_yutilisantxdansget_framereste à étudier séparément ; elle n'a pas été modifiée pour cette validation.
Relecture avant merge
- Corrigé
start -Wsur une session déjà lancée : attendre et vérifier le déverrouillage avant de rendre la main, au lieu de retourner immédiatement. - Image distincte 5H11a-agent-v11 démarrée et déverrouillée en 27 s ; agent v11 confirmé. Les deux sessions de test antérieures sont conservées séparément.