Într-o zi obișnuită de lucru, am primit un CompactFlash de 64 MB — da, megabytes, nu gigabytes — dintr-un calculator industrial care controla o stație de betoane. Misiunea era simplă: să facem o copie de siguranță. Ce a urmat a fost o incursiune fascinantă într-un sistem de operare pe care majoritatea programatorilor nu l-au auzit niciodată.
<h2>Primul contact</h2>
<p>CompactFlash-ul venea dintr-un controller industrial folosit de o centrală de betoane. Aceste calculatoare nu rulează Windows sau Linux — sunt mașini specializate, construite să funcționeze non-stop, fără ecran albastru de eroare, fără actualizări, fără surprize. Unele dintre ele funcționează de peste 20 de ani fără întrerupere.</p>
<p>Conectarea a necesitat un adaptor CompactFlash → IDE → USB, alimentat extern — fără alimentare separată, laptopul nici nu detecta cardul. Un prim semn că avem de-a face cu hardware de altă epocă.</p>
$ lsblk
sdb 61,3M disk SanDisk SD25B-64
└─sdb1 61,1M part <p>Un SanDisk SD25B-64. 64 de megabytes. Pe acest spațiu — cât o singură fotografie de pe telefonul tău — încape un sistem de operare complet, software de automatizare industrială, configurații, rețete de betoane și boot loader.</p>
<h2>Clonarea</h2>
<p>Prima regulă când lucrezi cu hardware vechi: <strong>faci o copie bit-cu-bit înainte de orice</strong>. Am folosit <code>dd</code> pentru a crea o imagine exactă a cardului:</p>
$ sudo dd if=/dev/sdb of=cf_card.img bs=512 status=progress
125440+0 records in
125440+0 records out
64225280 bytes (64 MB, 61 MiB) copied, 21s, 3.0 MB/s <p>3 MB/s. În epoca SSD-urilor NVMe care ating 7 GB/s, viteza aceasta pare o glumă. Dar fiecare byte contează — acest card conține software care nu mai există nicăieri altundeva.</p>
<p>Am verificat integritatea cu un checksum MD5 și am creat imediat o copie read-only a imaginii originale. Regula de aur: <strong>nu te atingi niciodată de original</strong>.</p>
<h2>Ce sistem de operare e ăsta?</h2>
<p>Tabelul de partiții a dezvăluit primul indiciu:</p>
Partition 1: ID=0x09, active — AIX bootable <p>Tipul <code>0x09</code> este asociat cu AIX, dar și cu un alt sistem de operare: <strong>OS-9</strong>. Un <code>hexdump</code> al boot sector-ului a confirmat:</p>
000001A0: 4f 53 2d 39 30 30 30 2f |OS-9000/|
000001A8: 4d 53 2d 44 4f 53 28 4f |MS-DOS(O|
000001B0: 2f 4d 29 |/M) | <p>Iar sectorul de identificare al volumului:</p>
41 45 53 2c 20 4f 53 39 30 30 30 20 56 32 2e 32
|AES, OS9000 V2.2| <p><strong>OS-9000 versiunea 2.2</strong>, produs de Microware Systems Corporation din Des Moines, Iowa. Un sistem de operare real-time (RTOS) pentru procesoare x86, rescris în C din legendarul OS-9 — care fusese creat inițial în anii '80 pentru procesoarele Motorola 6809.</p>
<h2>OS-9000 — un sistem de operare pe care nu l-ai auzit, dar l-ai folosit indirect</h2>
<p>OS-9 și succesorul său OS-9000 au fost unele dintre cele mai răspândite sisteme de operare real-time din industrie. Dacă ai folosit vreodată:</p>
<ul>
<li>Un CD-i Philips (da, acel player multimedia din anii '90)</li>
<li>Un set-top box prin cablu</li>
<li>Un router industrial</li>
<li>O stație de betoane sau asfalt</li>
</ul>
<p>...sunt șanse mari că în spate rula un OS-9.</p>
<p>Ce îl făcea special? <strong>Fiabilitate absolută.</strong> Într-o stație de betoane, un crash software nu înseamnă un ecran albastru — înseamnă tone de beton care se întăresc în malaxor, zeci de mii de euro pagubă și zile întregi de curățare manuală. OS-9000 era proiectat să nu se oprească. Niciodată.</p>
<h2>Tentativa de boot în emulator</h2>
<p>Nu am putut rezista tentației de a vedea sistemul în funcțiune. Am lansat imaginea într-un emulator QEMU:</p>
$ qemu-system-i386 -m 64 -drive file=cf_card.img,format=raw \
-boot c -vga std -display gtk -cpu pentium <p>Și... a pornit! Pe un fundal albastru, un singur mesaj:</p>
<figure class="blog-image">
<img src="/blog/img/screenshot_interbus_error.png" alt="Eroarea Interbus la prima pornire în QEMU" loading="lazy">
<figcaption>Eroarea Interbus la prima pornire în QEMU — ecranul albastru cu mesajul „INITIALISATION IMPOSSIBLE. Erreur #032:032 sur interbus“</figcaption>
</figure>
<blockquote>
<p>INITIALISATION IMPOSSIBLE. Erreur #032:032 sur interbus</p>
</blockquote>
<p>Sistemul de operare a bootat perfect. Kernel-ul OS-9000 s-a inițializat, a montat filesystem-ul, a executat scripturile de startup. Dar aplicația AES — software-ul care controlează stația de betoane — s-a oprit la inițializarea bus-ului de câmp <strong>Interbus-S</strong>, rețeaua industrială care conectează dozatoarele, benzile transportoare și malaxorul.</p>
<p>Normal. În emulator nu există o placă Interbus fizică. Dar faptul că a bootat demonstrează că imaginea este intactă și funcțională.</p>
<h2>Problema: cum citești un filesystem pe care nimeni nu-l mai suportă?</h2>
<p>Aici a început adevărata provocare. OS-9000 folosește un filesystem proprietar numit <strong>RBF</strong> (Random Block File). Nu există suport nativ în Linux. Nu există tool-uri moderne care să-l citească.</p>
<p>Am încercat mai multe abordări:</p>
<p><strong>Toolshed</strong> — un utilitar open-source pentru diskuri OS-9, compilat din sursă. Dar toolshed-ul este făcut pentru OS-9/6809 (Motorola, 8-bit). OS-9000/x86 folosește o variantă diferită a formatului RBF, cu adrese pe 32 de biți și little-endian. Toolshed-ul a refuzat să recunoască imaginea.</p>
<p><strong>Modulul kernel RBF pentru Linux</strong> — dezvoltat în 2001 de Andrew Cannon și portat pe kernel 2.6 de Carsten Emde. Ultima versiune suportă kernel 2.6.21 — din 2007. Cu un kernel 6.19, nici nu are rost să încercăm.</p>
<p><strong>OS9MAX</strong> — un software comercial pentru Windows care poate citi diskuri OS-9000. Site-ul producătorului nu mai răspunde.</p>
<p>Nu exista niciun tool funcțional. Am rămas cu o singură opțiune: <strong>reverse engineering manual al filesystem-ului</strong>.</p>
<h2>Reverse engineering: dezlegarea structurii RBF</h2>
<p>Pornind de la documentația publică a OS-9 (care descrie varianta 6809/68000, pe 24 de biți, big-endian) și de la analiza directă a hexdump-ului, am reconstruit structura filesystem-ului OS-9000/x86.</p>
<h3>Sectorul de identificare</h3>
<p>La offset 0x200 în partiție (sectorul logic 1), am găsit headerul volumului:</p>
<table>
<thead>
<tr>
<th>Offset</th>
<th>Valoare</th>
<th>Semnificație</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>0x00</code></td>
<td><code>0xADB0B0AD</code></td>
<td>Magic number OS-9000</td>
</tr>
<tr>
<td><code>0x08</code></td>
<td>125.151</td>
<td>Total sectoare (× 512B = 61 MB)</td>
</tr>
<tr>
<td><code>0x38</code></td>
<td><code>AES, OS9000 V2.2</code></td>
<td>Numele volumului</td>
</tr>
</tbody>
</table>
<h3>Intrări de director</h3>
<p>Spre deosebire de OS-9 clasic (intrări de 32 bytes), OS-9000/x86 folosește <strong>intrări de 64 bytes</strong>:</p>
<ul>
<li>Bytes 0-27: numele fișierului</li>
<li>Bytes 60-63: adresa File Descriptor-ului (little-endian, 32 biți)</li>
</ul>
<h3>File Descriptors</h3>
<p>Fiecare fișier sau director are un File Descriptor (FD) care începe cu magic-ul <code>0xFDB0B0FD</code>. FD-ul conține atributele fișierului, dimensiunea și lista de segmente (locațiile fizice ale datelor pe disc).</p>
<p>Am descoperit un detaliu subtil: adresa FD din intrarea de director este cu 1 mai mică decât sectorul fizic real. <code>firstboot</code> indică FD=10, dar FD-ul se află de fapt la sectorul 11. Acest offset de +1 a fost cheia care a deblocat întreaga structură.</p>
<h3>Scanarea automată</h3>
<p>Am scris un scanner care a căutat toate sectoarele cu magic-ul <code>0xFDB0B0FD</code> și a găsit <strong>657 de File Descriptors</strong> pe tot discul — 657 de fișiere și directoare pe un card de 64 MB.</p>
<h2>Ce am găsit: anatomia unei stații de betoane</h2>
<p>Cu parserul funcțional, am reconstruit arborele de directoare complet:</p>
/
├── firstboot ─ secvența inițială de boot
├── sysboot ─ configurarea hardware (438 KB)
├── CMDS/ ─ comenzi sistem OS-9000
│ ├── shell, mshell ─ interpretoare de comenzi
│ ├── dir, del, copy ─ utilitare familiare
│ ├── fdisk, format ─ management discuri
│ └── login, backup ─ administrare
├── SYS/ ─ configurări sistem
├── AES/ ─ software-ul stației (versiunea activă)
│ ├── CMDS/
│ │ ├── initial ─ programul principal (89 KB)
│ │ ├── interbus ─ driver Interbus-S (57 KB)
│ │ ├── sequenceur ─ secvențatorul de producție (206 KB)
│ │ ├── visual ─ interfața grafică (388 KB)
│ │ ├── regul ─ regulatoare PID (112 KB)
│ │ ├── maint ─ întreținere preventivă (169 KB)
│ │ └── ...26 module în total
│ └── CLIENT_CONFIG/ ─ configurația clientului
│ ├── aIBS_Config ─ configurare Interbus (231 KB!)
│ ├── ad1..ad4 ─ configurări dozatoare
│ ├── ac1 ─ configurare centrală
│ ├── am1 ─ configurare malaxor
│ ├── ap1, ap2 ─ parametri producție
│ ├── at1..at12 ─ texte multilingve
│ └── formule/ ─ rețetele de beton
└── AES.old/ ─ backup al configurației anterioare <p>Software-ul <strong>AES</strong> (Automatismes et Equipements de Statie) este un sistem complet de automatizare, scris pentru OS-9000, care include:</p>
<ul>
<li><strong>Secvențator</strong> — orchestrează ciclul de producție: cântărire agregate → dozare ciment → adăugare apă → malaxare → descărcare</li>
<li><strong>Regulatoare PID</strong> — control în buclă închisă pentru debitul de agregate pe benzile transportoare</li>
<li><strong>Interfață grafică</strong> — afișaj pe terminal QVT, cu meniuri în franceză, germană, engleză și română</li>
<li><strong>Driver Interbus-S</strong> — comunicare cu modulele I/O distribuite (Phoenix Contact IBS)</li>
<li><strong>Server Modbus TCP</strong> — comunicare cu sisteme externe</li>
<li><strong>Întreținere preventivă</strong> — timer-e pentru schimburi de piese, cu cod de acces</li>
<li><strong>Kermit</strong> — protocol de transfer serial pentru backup-uri</li>
</ul>
<p>Configurația este pentru un client din România — un mare constructor de drumuri.</p>
<h3>Rețetele de beton</h3>
<p>Printre string-urile extrase din imagine am găsit și câteva rețete:</p>
<ul>
<li><code>beton borduri</code> — beton pentru borduri de trotuar</li>
<li><code>beton semiud</code> — beton semi-uscat (pentru prefabricate)</li>
</ul>
<p>Fiecare rețetă definește proporțiile exacte de agregate (pietriș de diferite granulații), ciment, apă și aditivi. Aceste rețete sunt proprietate intelectuală a producătorului de beton — motiv în plus pentru care backup-ul acestui card este esențial.</p>
<h2>Scripturile de startup: secvența de boot</h2>
<p>Din analiza string-urilor am reconstruit secvența completă de pornire:</p>
<ol style="padding-left: 1.5rem; color: var(--text-secondary); margin: 1rem 0 1.5rem;">
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">BIOS</strong> → bootează de pe IDE Primary Master (CompactFlash-ul)</li>
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">sysboot</strong> → încarcă kernel-ul OS-9000 și driverele hardware</li>
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">firstboot</strong> → inițializare minimală</li>
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">startup</strong> → scriptul principal:
setenv SHELL mshell
setenv TERM pcat
profile SYS/set_os ← configurare OS
profile SYS/set_aes ← lansare aplicație AES </li>
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">set_aes</strong> → configurează căile, încarcă drivere seriale, apoi:
initial a -iq <>>>/nil & ← pornește aplicația AES </li>
<li style="margin-bottom: 0.5rem; line-height: 1.7;"><strong style="color: var(--text-primary);">initial</strong> → inițializează Interbus-S, încarcă configurația, pornește secvențatorul</li>
</ol>
<p>Mesajul de eroare pe care l-am văzut în QEMU vine din pasul 6 — <code>initial</code> nu găsește placa Interbus fizică.</p>
<h2>Extragerea scripturilor — cum pornește o stație de betoane</h2>
<p>Cu parserul funcțional, am putut extrage și citi fișierele text de pe disc. Scriptul principal de startup dezvăluie întreaga secvență de inițializare:</p>
* * * * * * * * * AUTOMATISME ELECTROTECHNIQUE SERVICES * * * * * * * *
* *
* 255, avenue de l'Europe - Parc d'activites Jean Monet *
* BP 32 - VERT SAINT DENIS 77241 CESSON CEDEX *
* *
* SYSTEME COMPUMAT *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
setenv TZ GMT:no
setenv SHELL mshell
setenv TERM pcat
profile SYS/set_os
profile SYS/set_aes <p><strong>AES</strong> — Automatisme Electrotechnique Services — era o firmă franceză din Vert-Saint-Denis, lângă Paris. Sistemul lor <strong>Compumat</strong> era platforma software pentru controlul stațiilor de betoane și asfalt. Observați adresa și telefonul din header — un artefact al unei epoci în care informațiile de contact ale producătorului erau hardcodate direct în software.</p>
<h3>Fișierul <code>options_appli</code> — configurația specifică instalației</h3>
<p>Acest fișier conține parametrii specifici fiecărei instalații. Iată secțiunea critică:</p>
* VALIDATION DU CONTROLE INTERBUS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*setenv CONTROL_IBS jjmmaa <p>Asteriscul (<code>*</code>) la început de linie este un comentariu în OS-9. Variabila <code>CONTROL_IBS</code> este dezactivată — ceea ce înseamnă că validarea datei Interbus este oprită. Dar aplicația <code>initial</code> tot încearcă să comunice cu hardware-ul fizic.</p>
<p>Alte opțiuni configurabile: recalibrarea timer-ului 8253 (ceasul hardware), redirecționarea porturilor seriale LCPC (consolă locală) și imprimantă, culoarea interfeței (negru sau gri pe terminal QVT), și posibilitatea de lansare a aplicației pe o conexiune serială remotă — pentru debugging la distanță, printr-un modem!</p>
<h3>Mecanismul de selecție la boot</h3>
<p>Scriptul de startup conține un meniu interactiv surprinzător de sofisticat:</p>
***************************************************
* CHOISISSEZ LA CONSOLE DE DEMARRAGE DU SYSTEME *
***************************************************
* *
* - Tapez '0' pour lancer sur le système local *
* - Tapez '1' pour lancer sur le système distant *
* *
*************************************************** <p>La pornire, operatorul poate alege să lanseze interfața pe terminalul local (opțiunea 0) sau pe o conexiune serială remotă (opțiunea 1, prin modem). Dacă nu se face nicio alegere în 30 de secunde, sistemul pornește automat pe consola implicită. Un timeout configurat, UI în text, totul gândit pentru fiabilitate maximă.</p>
<h2>Bypass-ul Interbus: cum am pornit o stație de betoane fără hardware</h2>
<p>Am încercat mai întâi abordarea brutală: să mapăm zona de memorie a plăcii Interbus cu zerouri în QEMU. Nu a mers — aplicația <code>initial</code> citea registrele, primea doar zerouri, și interpreta asta ca „placa nu răspunde“.</p>
<p>Analiza binară a modulului <code>interbus</code> (57 KB) a dezvăluit detalii despre placa de comunicație:</p>
<ul>
<li><strong>Controller</strong>: Phoenix Contact cu ASIC-ul <strong>PC979K</strong> (generația 4 Interbus)</li>
<li><strong>Module pe bus</strong>: 6 module Phoenix Contact distribuite (terminale de bus, module I/O digitale, module cu bus local)</li>
</ul>
<p>Interbus-S funcționează ca un shift register în inel: datele circulă prin fiecare modul și se întorc la master. Dacă un singur modul lipsește, întregul bus raportează eroare. Este ca o ghirlandă de Crăciun cu becuri în serie — dacă unul lipsește, niciunul nu funcționează.</p>
<p>Simularea completă a hardware-ului ar fi necesitat emularea ASIC-ului PC979K, răspunsurile tuturor modulelor de pe bus și implementarea protocolului de scanare — un proiect de luni de zile.</p>
<p>Dar am avut o idee mai bună: <strong>dacă nu putem simula hardware-ul, de ce să nu-l ocolim complet?</strong></p>
<h3>Chirurgie pe un filesystem proprietar</h3>
<p>Cunoșteam deja structura RBF a filesystem-ului. Știam exact unde se află scriptul <code>startup</code> pe disc (File Descriptor 23699, datele începând la sectorul 23700). Știam că OS-9 folosește <code>*</code> pentru comentarii și <code>%</code> pentru expandarea variabilelor.</p>
<p>Linia critică din startup:</p>
let go = var_rep("initial a -iq <>>>/nil &")
...
%go <p>Planul: să schimbăm <strong>un singur byte</strong> pe imaginea de disc. Caracterul <code>%</code> (0x25) de la <code>%go</code> devine <code>*</code> (0x2A), transformând comanda într-un comentariu. Aplicația <code>initial</code> nu va mai fi lansată, dar tot restul sistemului va porni normal.</p>
<p>Am calculat offset-ul exact în imagine: byte-ul 4117 din fișierul startup, care se traduce la adresa absolută <code>0xB97A15</code> în imaginea de disc. Un singur byte. Am patch-uit și am relansat QEMU.</p>
<h3>Și... a pornit!</h3>
<p>Ecranul albastru familiar cu header-ul AES Compumat a apărut — dar de data aceasta, <strong>fără eroare</strong>. Splash-ul companiei, adresa din Vert-Saint-Denis, autorii software-ului (Christian Be. et Christophe Bl.) — totul afișat pe terminalul QVT emulat.</p>
<p>Splash-ul AES Compumat — afișat pe terminalul QVT emulat, cu adresa firmei din Vert-Saint-Denis și autorii software-ului:</p>
<figure class="blog-image">
<img src="/blog/img/screenshot_qvt_splash.png" alt="Ecranul AES Compumat după bypass-ul Interbus" loading="lazy">
<figcaption>Ecranul AES Compumat afișat pe terminalul QVT emulat — cu adresa firmei din Vert-Saint-Denis și autorii software-ului</figcaption>
</figure>
<p>Am mai dezactivat terminalul QVT și timer-ul hardware (PIT 8253, care se comporta ciudat în emulator) pentru a obține accesul direct la consolă. Și pe ecranul negru, text alb, a apărut:</p>
(C) Microware Reproduit sous licence numéro 1313-0029 1863900 par AES
*********************************************************************
**** Chargement de l'application ****
................. <figure class="blog-image">
<img src="/blog/img/screenshot_console_boot.png" alt="Consola OS-9000 - boot complet în QEMU" loading="lazy">
<figcaption>Consola OS-9000 — boot complet în QEMU cu mesajul de licență Microware și încărcarea aplicației AES</figcaption>
</figure>
<p><strong>OS-9000 bootează complet în QEMU.</strong> Numărul de licență Microware (1313-0029 1863900) confirmă că acesta este un sistem licențiat, nu o copie piratată — un detaliu fascinant despre profesionalismul dezvoltatorilor AES din anii '90.</p>
<p>Dar consola era mută — nu răspundea la taste. Scriptul de startup termina execuția și shell-ul ieșea fără să lase un prompt interactiv. Am mai avut de rezolvat încă o problemă.</p>
<h3>Obținerea shell-ului interactiv</h3>
<p>Am modificat startup-ul (tot prin patch direct pe imaginea de disc) ca la final să lanseze un shell conectat la terminalul consolei:</p>
shell <>>>/term <p>Sintaxa <code><>>>/term</code> este specifică OS-9 și înseamnă „redirecționează stdin, stdout și stderr către device-ul <code>/term</code>“ — adică ecranul VGA.</p>
<p>Și, în sfârșit:</p>
<figure class="blog-image">
<img src="/blog/img/screenshot_shell_prompt.png" alt="Shell-ul OS-9000 — prompt interactiv" loading="lazy">
<figcaption>Shell-ul OS-9000 — primul prompt interactiv pe un sistem de operare uitat de lume</figcaption>
</figure>
<p><code>[1]$ _</code> — primul prompt interactiv OS-9000 pe care l-am văzut vreodată. Am tastat <code>dir</code>:</p>
<figure class="blog-image">
<img src="/blog/img/screenshot_dir_listing.png" alt="Listing-ul root cu dir" loading="lazy">
<figcaption>Listing-ul directorului root — exact structura descoperită prin reverse engineering</figcaption>
</figure>
Directory of . 16:44:41
AES AES.old CMDS SPF SYS
firstboot sysboot <p>Exact structura pe care o descoperiserăm prin reverse engineering! Iar navigând în <code>AES/CMDS</code>:</p>
<figure class="blog-image">
<img src="/blog/img/screenshot_aes_cmds.png" alt="Modulele aplicației AES" loading="lazy">
<figcaption>Toate cele 40+ de module ale aplicației AES — confirmate live în shell-ul OS-9000</figcaption>
</figure>
<p>Toate cele 40+ de module ale aplicației: <code>initial</code>, <code>interbus</code>, <code>sequenceur</code>, <code>visual</code>, <code>regul</code>, <code>maint</code>, <code>modbusTCP</code>, <code>kermit_aes</code>, <code>espion</code>, <code>ClientLAN</code>, <code>modem</code>... Un ecosistem software complet, confirmat live.</p>
<p>Un detaliu surprinzător: tastatura era configurată <strong>AZERTY</strong> (layout francez). Când am tastat <code>AES</code> de pe tastatura noastră QWERTY, pe ecran a apărut <code>QES</code>. Normal — software-ul a fost dezvoltat în Franța, la Vert-Saint-Denis. Am creat un mapping de traducere pentru a putea comunica cu sistemul.</p>
<p>Acum avem acces complet la un sistem OS-9000 live. Putem explora fișiere, rula comenzi, și potențial lansa individual componentele aplicației — interfața grafică <code>visual</code>, secvențatorul <code>sequenceur</code>, modulul de mentenanță <code>maint</code>.</p>
<h2>Disecția binară: module OS-9000 și protecția CRC</h2>
<p>Încercarea de a rula <code>initial a</code> din shell-ul interactiv a eșuat — și motivul a fost revelator.</p>
<h3>Formatul modulelor OS-9000</h3>
<p>Fiecare executabil în OS-9000 este un <strong>modul</strong> — o unitate auto-conținută cu un header standardizat:</p>
<table>
<thead>
<tr>
<th>Offset</th>
<th>Câmp</th>
<th>Exemplu (initial)</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>0x00</code></td>
<td>Sync word</td>
<td><code>0x4AFC</code> (little-endian)</td>
</tr>
<tr>
<td><code>0x04</code></td>
<td>Dimensiune modul</td>
<td>89.200 bytes</td>
</tr>
<tr>
<td><code>0x0C</code></td>
<td>Offset la nume</td>
<td><code>initial</code></td>
</tr>
<tr>
<td><code>0x12</code></td>
<td>Tip/Limbaj</td>
<td>Program / Machine code</td>
</tr>
<tr>
<td><code>0x24</code></td>
<td>Offset execuție</td>
<td><code>0x60</code></td>
</tr>
<tr>
<td><code>0x2C</code></td>
<td>Dimensiune date</td>
<td>5.616 bytes</td>
</tr>
<tr>
<td>ultimi 3 bytes</td>
<td><strong>CRC-24</strong></td>
<td>Checksum integritate</td>
</tr>
</tbody>
</table>
<p>Ultimii 3 bytes ai fiecărui modul sunt un <strong>CRC pe 24 de biți</strong>. Algoritmul:</p>
<ul>
<li>Valoare inițială: <code>0xFFFFFF</code></li>
<li>Polinom: <code>0x800063</code></li>
<li>Când se procesează <strong>tot</strong> modulul (inclusiv CRC-ul), rezultatul trebuie să fie exact <code>0x800FE3</code></li>
</ul>
<p>Acest mecanism garantează integritatea modulelor — dacă un singur bit se schimbă, OS-9000 refuză să încarce modulul. Am descoperit asta când am încercat să patch-uim un singur byte (un <code>jne</code> → <code>jmp</code> pentru a ocoli o verificare) și shell-ul a refuzat să execute modulul, tratându-l ca text simplu:</p>
shell: can't execute "¶J" - Error #000:216 <p><code>¶J</code> sunt primii doi bytes ai sync-ului (<code>FC 4A</code> = <code>0x4AFC</code>) — shell-ul vedea bytes random, nu un modul valid. Doar după recalcularea CRC-ului modulul a fost din nou acceptat.</p>
<h3>Arhitectura aplicației: un sistem distribuit pe un singur procesor</h3>
<p>Analiza modulelor a dezvăluit o arhitectură elegantă în straturi:</p>
initial ─── creează module de date partajate (share, data_ecran,
│ data_reseau, init, cio, input, defaut, vidange, share_ana)
│
└── master ─── orchestratorul, fork-ează toate procesele:
├── visual (388 KB) — interfața grafică operator
├── sequenceur (206 KB) — ciclul de producție
├── regul (112 KB) — regulatoare PID
├── interbus (57 KB) — comunicare fieldbus
├── modbusTCP — comunicare Modbus
├── srvmodbusTCP — server Modbus
├── input/output — gestiune I/O
├── maint (169 KB) — mentenanță preventivă
├── autorise — autorizări acces
├── refresh — actualizare ecran
├── look — monitorizare
├── modem — comunicare serială
├── ClientLAN — client rețea
└── acquit_AU — achitare alarme <p>Tabelul de module din <code>master</code> este structurat ca un array de structuri la intervale de 78 bytes în secțiunea de date inițializate (idata) — fiecare intrare conținând numele modulului și parametrii de lansare.</p>
<p>Comunicarea între procese se face prin <strong>module de date partajate</strong> (shared data modules) — zone de memorie create de <code>initial</code> și accesibile tuturor proceselor prin sistem calls (<code>F$Link</code>, <code>F$DatMod</code>). Este o formă de IPC (Inter-Process Communication) tipică OS-9, mai rapidă decât pipe-urile sau mesajele, esențială pentru un sistem real-time unde latența contează.</p>
<h3>Tastatura AZERTY — un detaliu care schimbă totul</h3>
<p>OS-9000 era configurat cu layout de tastatură <strong>AZERTY</strong> (franțuzesc). QEMU trimite scancode-uri QWERTY, iar OS-9000 le interpretează ca AZERTY. Asta înseamnă:</p>
<ul>
<li><code>a</code> → trebuie trimis ca tasta <code>q</code></li>
<li><code>q</code> → ca tasta <code>a</code></li>
<li><code>z</code> → ca <code>w</code>, <code>w</code> → ca <code>z</code></li>
<li><code>m</code> → ca <code>;</code></li>
<li>Cifrele <code>0-9</code> necesită <strong>Shift</strong> (pe AZERTY, cifrele sunt pe Shift, iar simbolurile <code>&é"'(-è_çà</code> sunt pe rândul principal)</li>
<li><code>/</code> (separator de cale) → <code>Shift+.</code></li>
</ul>
<p>Fără acest mapping, navigarea în sistem este imposibilă — fiecare cale de fișier devine un puzzle criptografic.</p>
<h2>Extragerea completă: un filesystem scos la lumină după 20 de ani</h2>
<p>Cu structura RBF complet înțeleasă, am scris un extractor Python care parsează întreaga imagine și exportă toate fișierele pe disc. Rezultatul:</p>
17 directoare, 637 fișiere, 11.534.829 bytes
594 module OS-9000 cu CRC valid, 5 module boot (CRC diferit)
13 fișiere text (scripturi, configurări) <p>637 de fișiere pe un card de 64 MB. Fiecare bit conta.</p>
<h3>Inventarul complet</h3>
<p>Iată ce conține cardul — un ecosistem software complet:</p>
<p><strong>Sistemul de operare</strong> — 80+ comenzi în <code>/CMDS/</code>:</p>
shell, mshell — interpretoare de comenzi
dir, del, copy — utilitare clasice
fdisk, format — management discuri
login, backup — administrare
load, unlink — management module
telnet, ftp — da, acest card de 64MB are client FTP și Telnet <p><strong>Aplicația AES</strong> — 40+ module în <code>/AES/CMDS/</code>:</p>
initial (87 KB) — bootstrap-ul aplicației
master (36 KB) — orchestratorul proceselor
visual (380 KB) — interfața grafică (cel mai mare modul!)
sequenceur (202 KB) — secvențatorul de producție
regul (110 KB) — regulatoare PID
interbus (56 KB) — driver Interbus-S
maint (166 KB) — mentenanță preventivă
modbusTCP (17 KB) — comunicare Modbus TCP
kermit_aes (41 KB) — transfer de fișiere serial
gzip (77 KB) — compresie — da, pe 64 MB <p><strong>Resurse multilingve</strong> — interfața disponibilă în 5 limbi:</p>
aecran — ecrane franțuzești (implicit)
aecran_gb — ecrane englezești
aecran_d — ecrane germane
aecran_pl — ecrane poloneze
aecran_hu — ecrane maghiare
aerreur* — mesaje de eroare în toate limbile
ahelp* — help operator în toate limbile <p><strong>Configurația clientului</strong> — <code>/AES/CLIENT_CONFIG/</code>:</p>
aIBS_Config (227 KB) — configurare Interbus (toată cablarea I/O!)
ad1..ad4 — configurări dozatoare (4 linii de agregate)
ac1 — configurare centrală de beton
am1 — configurare malaxor
at1..at12 — texte specifice instalației
aformule (69 KB) — rețetele de beton
amagasin (28 KB) — configurare magazie/silozuri <h3>Ecranele operatorului — UI de terminal din anii '90</h3>
<p>Modulele <code>aecran</code> conțin definițiile ecranelor operatorului, desenate cu caractere box-drawing pentru terminalul QVT:</p>
═══════════════════════════════════════════════════════════
║ Att APPELLATIONS % %H2O DEBIT 0% 100% ║
╠═══════════════════════════════════════════════════════════╣
║ TC ║
║ TD1 ║
║ TOTAL ║
║ ED ║
║ TD2 ║
║ DEBIT TM ║
║ MARCHE CENTRALE ║
║ QT DEMANDEE ║
║ MARCHE MATERIAUX ║
║ QT DELIVREE ║
║ CONJUGATEUR en % % ║
║ QT CASQUE ║
╚═══════════════════════════════════════════════════════════╝ <p>Fiecare ecran — <code>DONNEES DE SERVICE</code> (date de serviciu), <code>AJUSTEMENT DE LA FORMULE</code> (ajustarea rețetei), <code>DEFAUTS</code> (defecte) — este o pagină completă de terminal, cu câmpuri editabile marcate prin coduri de control specifice terminalului QVT.</p>
<p>În versiunea engleză, titlurile devin <code>SERVICE DATA</code>, <code>FORMULA ADJUSTMENT</code>, <code>FAULTS</code>. În versiunea germană, operatorul vede <code>WATTMESSER MISCHER</code> (wattmetru malaxor), <code>DOSIERWERKE</code> (dozatoare), <code>WASSERDURCHSATZ</code> (debit apă). Cinci limbi, fiecare compilată într-un modul OS-9000 separat.</p>
<h3>Rețetele de beton — proprietatea intelectuală a clientului</h3>
<p>Din modulul <code>aformule</code> (69 KB) am extras numele tuturor rețetelor stocate:</p>
stabilizat aeroport
spalare statie
beton semiud
beton borduri
BORDURI [ORAS]
stabilizat
stabilizat special
LIMON
limon traite test '4% cim
formula ciment
formula test <p>Fiecare rețetă definește proporțiile exacte pentru fiecare dozator: cantitatea de agregate din silozul 1, silozul 2, ciment, apă, aditivi. „Stabilizat aeroport“ sugerează un contract de construcție a unui aeroport. „BORDURI [ORAS]“ — borduri de trotuar pentru un oraș din România. „Limon traité test 4% ciment“ — un test de tratare a pământului cu ciment.</p>
<p>Aceste rețete sunt calibrate prin încercări succesive, ajustate în funcție de umiditatea agregatelor, temperatura exterioară și cerințele rezistenței betonului. Pierderea lor ar fi însemnat săptămâni de re-calibrare.</p>
<h3>Mesajele de eroare — ce vede operatorul când ceva nu merge</h3>
<p>Modulele <code>aerreur</code> conțin sute de mesaje de diagnostic, fiecare legat de o situație specifică din stație:</p>
Arrêt d'urgence machine → Machine emergency stop
Chaîne thermique matériaux → Materials thermal chain open
Trémie pleine → Hopper full
Trémie vide → Hopper empty
Verrouillage malaxeur → Mixer locking
Défaut de position chargement → Loading position fault
Poids +12 % → Weight +12%
Sous-vitesse vis → Screw underspeed
Défaut lecture poids → Weight reading fault <p>Fiecare mesaj corespunde unui semnal I/O de pe bus-ul Interbus — un contact termic care se deschide, un senzor de nivel din buncăr, un encoder de pe banda transportoare. Când operatorul vede „Sous-vitesse vis“ (sub-viteză șnec), știe exact că motorul șnecului de ciment nu atinge turația setată — poate fi o bandă de transmisie uzată, un blocaj de material, sau o problemă electrică.</p>
<h3>Rețeaua — FTP și Telnet pe o stație de betoane</h3>
<p>Un detaliu neașteptat: cardul conține un stack complet TCP/IP cu server FTP și Telnet. Scriptul <code>start_spf</code> configurează:</p>
load spf — SPF file manager (protocolul de rețea OS-9000)
load sptcp tcp0 — TCP driver
load spudp udp0 — UDP driver
ipstart — inițializare stack IP
inetd <>>>/nil& — daemon Internet (FTP + Telnet) <p>Configurația <code>inetd.conf</code> activează FTP și Telnet — ceea ce înseamnă că un tehnician AES putea, teoretic, să se conecteze la stație prin rețea, să transfere fișiere de configurare prin FTP, și să ruleze comenzi prin Telnet. Pe un card de 64 MB. În anii 2000.</p>
<h3>AES Compumat — o firmă care și-a schimbat adresa</h3>
<p>Comparând scripturile de startup, am descoperit că firma AES și-a mutat sediul:</p>
<p><strong>Versiunea veche</strong> (<code>startup_appli</code>):</p>
85, rue Eugène Delaroue - BP 165 - 77197 DAMMARIE CEDEX
Tél 01 64 37 11 02 - Télécopie 01 64 37 23 23 <p><strong>Versiunea curentă</strong> (<code>startup</code>):</p>
255, avenue de l'Europe - Parc d'activités Jean Monet
BP 32 - VERT SAINT DENIS - 77241 CESSON CEDEX
Tél 01 64 64 33 70 - Télécopie 01 64 64 33 71 <p>De la Dammarie-lès-Lys la Vert-Saint-Denis — ambele în departamentul Seine-et-Marne, la sud-est de Paris. Adresa mai veche, de pe rue Eugène Delaroue, sugerează un birou mic. Mutarea pe avenue de l'Europe, într-un „Parc d'activités“, indică o creștere a firmei. Aceste detalii, hardcodate în scripturile de boot, sunt mici capsule de timp ale unei companii care nu mai există.</p>
<h2>Cum funcționează programul de stație: disecția unei aplicații real-time</h2>
<p>Cu toate fișierele extrase și analizate, putem acum reconstitui complet modul în care acest software controlează o stație de betoane. Este o lecție de arhitectură software industrială din anii '90 — elegantă, minimalistă și construită pentru fiabilitate absolută.</p>
<h3>Pornirea: de la curent la beton</h3>
<p>Secvența de boot durează câteva secunde:</p>
BIOS → CompactFlash (IDE) → sysboot (kernel OS-9000 + drivere)
→ firstboot → startup
→ profile SYS/set_os ← configurare sistem
→ profile SYS/set_aes ← configurare aplicație
→ set_pit8253 ← calibrare timer hardware
→ [meniu: consolă locală sau modem?]
→ initial a -iq <>>>/nil & ← lansează aplicația AES <p>Detaliul cu meniul de la boot este fascinant: operatorul poate alege să lanseze interfața pe ecranul local (opțiunea 0) sau pe o conexiune serială remotă (opțiunea 1, prin modem — pentru debugging la distanță). Dacă nu se face nicio alegere în 30 de secunde, sistemul pornește automat pe consola implicită.</p>
<h3>Arhitectura: un sistem distribuit pe un singur procesor</h3>
<p>Aplicația AES Compumat este structurată în trei straturi:</p>
<p><strong>Stratul 1 — <code>initial</code></strong> (bootstrap)</p>
<p>Primul proces lansat. Rolul lui este să pregătească mediul:</p>
<ul>
<li>Creează <strong>9 module de date partajate</strong> în RAM — zone de memorie accesibile tuturor proceselor:
<ul>
<li><code>share</code> — starea globală a stației</li>
<li><code>share_ana</code> — valorile analogice (greutăți, debite, viteze, temperaturi)</li>
<li><code>data_ecran</code> — buffer-ul ecranului operatorului</li>
<li><code>data_reseau</code> — date de comunicare rețea</li>
<li><code>defaut</code> — registrul defectelor active</li>
<li><code>vidange</code> — starea golirii dozatoarelor</li>
<li><code>cio</code>, <code>init</code>, <code>input</code> — control intrări/ieșiri</li>
</ul>
</li>
<li>Încarcă de pe disc configurațiile: rețetele (<code>formule</code>), configurarea silozurilor (<code>magasin</code>), mappingul Interbus (<code>IBS_Config</code>)</li>
<li>Apoi execută <code>F$Fork</code> pentru a lansa <code>master</code></li>
</ul>
<p><strong>Stratul 2 — <code>master</code></strong> (orchestrator)</p>
<p>Modulul <code>master</code> conține un tabel de fork la intervale fixe de 78 de bytes — o structură pe care am descifrat-o din analiza binară. Fiecare intrare: numele procesului și un ID de lansare. <code>master</code> fork-ează toate cele 18 procese, apoi intră în buclă de supraveghere: dacă un proces moare, afișează eroarea (<code>INITIALISATION IMPOSSIBLE. Erreur #%03d:%03d sur %s</code>) și oprește stația.</p>
<p><strong>Stratul 3 — procesele aplicației</strong></p>
<p>18 procese care rulează simultan, fiecare cu un rol precis:</p>
<p><strong>Nucleul de control:</strong></p>
<table>
<thead>
<tr>
<th>Proces</th>
<th>Dimensiune</th>
<th>Rol</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>sequenceur</code></td>
<td>202 KB</td>
<td>Secvențatorul — orchestrează ciclul complet de producție</td>
</tr>
<tr>
<td><code>regul</code></td>
<td>110 KB</td>
<td>Regulatoare PID — controlează debitele pe benzile transportoare</td>
</tr>
<tr>
<td><code>input</code></td>
<td>14 KB</td>
<td>Citește intrările fizice (senzori, butoane, capace de siguranță)</td>
</tr>
<tr>
<td><code>output</code></td>
<td>8 KB</td>
<td>Scrie ieșirile fizice (contactoare, vane, motoare)</td>
</tr>
</tbody>
</table>
<p><strong>Comunicația cu echipamentele:</strong></p>
<table>
<thead>
<tr>
<th>Proces</th>
<th>Dimensiune</th>
<th>Rol</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>interbus</code></td>
<td>56 KB</td>
<td>Driver Interbus-S — comunicare cu modulele I/O distribuite</td>
</tr>
<tr>
<td><code>modbusTCP</code></td>
<td>17 KB</td>
<td>Client Modbus TCP — comunicare cu echipamente externe</td>
</tr>
<tr>
<td><code>srvmodbusTCP</code></td>
<td>32 KB</td>
<td>Server Modbus TCP — expune date către SCADA</td>
</tr>
</tbody>
</table>
<p><strong>Interfața operator:</strong></p>
<table>
<thead>
<tr>
<th>Proces</th>
<th>Dimensiune</th>
<th>Rol</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>visual</code></td>
<td>380 KB</td>
<td>Interfața grafică — cel mai mare modul!</td>
</tr>
<tr>
<td><code>refresh</code></td>
<td>30 KB</td>
<td>Actualizare periodică a ecranului</td>
</tr>
<tr>
<td><code>look</code></td>
<td>65 KB</td>
<td>Monitorizare, jurnalizare, imprimantă bonuri</td>
</tr>
</tbody>
</table>
<p><strong>Suport:</strong></p>
<table>
<thead>
<tr>
<th>Proces</th>
<th>Dimensiune</th>
<th>Rol</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>autorise</code></td>
<td>32 KB</td>
<td>Gestionare coduri de acces operatori</td>
</tr>
<tr>
<td><code>maint</code></td>
<td>166 KB</td>
<td>Mentenanță preventivă — timere schimb piese</td>
</tr>
<tr>
<td><code>modem</code></td>
<td>41 KB</td>
<td>Debugging remote prin modem serial</td>
</tr>
<tr>
<td><code>lcpc</code></td>
<td>51 KB</td>
<td>Consolă locală (port serial)</td>
</tr>
<tr>
<td><code>ClientLAN</code></td>
<td>15 KB</td>
<td>Client TCP/IP pentru sisteme externe</td>
</tr>
</tbody>
</table>
<h3>Comunicarea între procese: memorie partajată ca bus de date</h3>
<p>Procesele nu comunică prin pipe-uri, socket-uri sau message queues — ci prin <strong>module de date partajate</strong> (shared data modules), o formă de IPC nativă OS-9000. Fiecare modul este o zonă de memorie creată de <code>initial</code> și accesibilă tuturor proceselor prin system call-urile <code>F$Link</code> și <code>F$DatMod</code>.</p>
┌──────────────────────────────┐
│ MEMORIE PARTAJATĂ │
│ │
interbus ──────────►│ share (stare globală) │◄─── visual
(citește senzori, │ share_ana (valori analogice) │ (afișează pe ecran)
scrie actuatoare) │ defaut (defecte active) │
│ vidange (stare golire) │◄─── look
sequenceur ────────►│ data_ecran (buffer ecran) │ (jurnalizare)
(ciclul producției) │ data_reseau (date rețea) │
│ formule (rețete active) │◄─── regul
input ─────────────►│ cio (control I/O) │ (regulatoare PID)
output ◄────────────│ init (date inițializare) │
│ input (date intrări) │◄─── modbusTCP
└──────────────────────────────┘ (SCADA extern) <p>De ce memorie partajată și nu mesaje? <strong>Viteza.</strong> Într-un sistem real-time, regulatorul PID trebuie să citească greutatea de pe un senzor și să ajusteze viteza benzii la fiecare ciclu — de ordinul milisecundelor. Copierea datelor prin mesaje ar introduce latență inacceptabilă. Cu memorie partajată, <code>regul</code> citește direct din <code>share_ana</code>, fără copiere, fără așteptare, fără overhead.</p>
<p>Dezavantajul: sincronizarea trebuie gestionată manual. Un <code>swing_buffer</code> (buffer dublu) apare în codul <code>master</code>, <code>visual</code> și <code>maint</code> — o tehnică clasică de double-buffering unde un producător scrie într-un buffer în timp ce consumatorii citesc din celălalt.</p>
<h3>Ciclul de producție: cum se face o șarjă de beton</h3>
<p>Din help-ul operatorului (în engleză) și mesajele de eroare, putem reconstitui fiecare pas al producției:</p>
<p><strong>1. Selectarea rețetei</strong></p>
<p>Operatorul navighează pe ecranul <code>SERVICE DATA</code> (sau <code>DONNEES DE SERVICE</code> în franceză), selectează o rețetă — de exemplu „beton borduri“ — și introduce cantitatea dorită în tone. Poate ajusta conjugatorul (50-100%), care controlează ritmul de producție. Umiditatea agregatelor se setează manual sau se citește de la sonda automată.</p>
<p>Fiecare rețetă definește, pentru fiecare dozator, procentajul de material în formula uscată, debitul, și parametrii de regulare. Modulul <code>aformule</code> (69 KB) stochează toate rețetele — de la „stabilizat aeroport“ la „beton borduri“.</p>
<p><strong>2. Dozarea agregatelor</strong></p>
<p>Stația are 4 dozatoare (<code>ad1</code>..<code>ad4</code>), fiecare cu:</p>
<ul>
<li>Un buncăr pe cântare (senzori de greutate)</li>
<li>O bandă transportoare cu viteză variabilă</li>
<li>Vibratori pentru materiale lipicioase</li>
<li>Senzori de viteză (encoder pe bandă)</li>
</ul>
<p><code>sequenceur</code> comandă pornirea dozatoarelor în secvență. <code>regul</code> preia controlul — citește greutatea din <code>share_ana</code>, calculează eroarea față de setpoint, și ajustează viteza benzii prin algoritmul PID. Monitorizează în permanență: sub-viteză (<code>Underspeed</code>), supra-viteză (<code>Overspeed</code>), depășire greutate ±12%.</p>
<p><strong>3. Dozarea liantului</strong></p>
<p>Cimentul vine din silozuri prin șnec dozator sau alimentatoare alveolare. Control prin debitmetru. Verificări: presiune aer comprimat, blocare șnec (<code>Jamming on screw</code>), nivel silo, selectare/deselectare corectă a silozului.</p>
<p><strong>4. Dozarea apei și aditivilor</strong></p>
<p>Pompe separate pentru apă, emulsie, și adjuvanți. Debitul de apă e ajustabil ±15% față de rețetă, cu timp de introducere/oprire reglabil la ±5 secunde — pentru a compensa inerția conductelor. Operatorul poate ajusta în timp real dacă betonul e prea ud sau prea uscat.</p>
<p><strong>5. Malaxarea</strong></p>
<p>Malaxorul pornește. Un wattmetru monitorizează consumul motorului — indicator direct al consistenței betonului. Când consumul depășește un prag configurabil, betonul este gata. Opțional: amestecare suplimentară.</p>
<p><strong>6. Evacuarea</strong></p>
<p>Trapa malaxorului se deschide (<code>Mixer unlocking</code>). Betonul cade în buncărul de așteptare (trémie/hopper). O navetă (shuttle) direcționează fluxul — stânga sau dreapta — către camionul care așteaptă. Senzori de nivel: <code>Hopper full</code> / <code>Hopper empty</code>. Interlock mecanic de siguranță: <code>Mixer locking</code> — malaxorul nu poate porni cu trapa deschisă.</p>
<p><strong>7. Înregistrare și livrare</strong></p>
<p>Modulul <code>look</code> jurnalizează fiecare șarjă: formulă, cantități reale per component, dată/oră. <code>tagueur</code> (imprimanta de bonuri) generează bonul de livrare cu cod camion, număr bon, cantitate. Sistemul ține evidența stocurilor și creditelor per client, cu posibilitate de resetare săptămânală.</p>
<h3>Securitatea: cine are acces la ce</h3>
<p>Sistemul de acces este stratificat:</p>
<ul>
<li><strong>Operator</strong> — poate selecta rețete, porni/opri producția, achita alarme</li>
<li><strong>Cod corecție</strong> — permite modificarea rețetelor existente</li>
<li><strong>Cod liant</strong> — acces la parametrii de dozare ciment (critici pentru calitate)</li>
<li><strong>Cod calibrare</strong> — pentru tararea și calibrarea cântarelor</li>
<li><strong>Cod gestiune</strong> — acces la stocuri și credite clienți</li>
<li><strong>Cod mentenanță</strong> — acces complet: parametri mașină, timere preventive, configurare I/O</li>
<li><strong>SUPER_USER</strong> — dezactivat în producție, acces nelimitat (pentru tehnicieni AES)</li>
</ul>
<p>Fiecare nivel are propriul cod, iar <code>autorise</code> și <code>get_psw</code> le validează. Nu e criptare avansată — sunt coduri numerice, suficiente pentru a preveni modificările accidentale într-un mediu industrial unde operatorii poartă mănuși și au alte priorități decât hackingul.</p>
<h3>Comunicarea externă: o stație conectată</h3>
<p>Deși izolată fizic (fără internet), stația nu e izolată informațional:</p>
<ul>
<li><strong>Modbus TCP</strong> — server-ul <code>srvmodbusTCP</code> expune zeci de zone de date către un SCADA extern (PCVue de la Arc Informatique): intrări/ieșiri digitale, cumul producție per formulă, coduri produse, stare mașini. Un operator dintr-o cameră de comandă centrală poate monitoriza mai multe stații simultan.</li>
<li><strong>Modem serial</strong> — <code>modem</code> permite conectarea la distanță pentru Service Après-Vente (SAV). Un inginer AES din Vert-Saint-Denis putea, prin linia telefonică, să se conecteze la o stație din România, să verifice parametrii și să modifice configurația. În anii 2000, asta era „cloud“.</li>
<li><strong>Kermit</strong> — protocolul de transfer serial <code>kermit_aes</code> servea la backup/restore: exporta configurația pe un laptop conectat prin cablu serial, sau restaura o configurație salvată.</li>
<li><strong>LAN TCP/IP</strong> — <code>ClientLAN</code> comunica cu servere OMRON FINS (automate programabile) și terminale Pro-face (HMI-uri grafice), pentru instalații mai complexe cu echipamente suplimentare.</li>
</ul>
<h3>18 procese, 64 MB, zero crash</h3>
<p>Această arhitectură — 18 procese cooperante prin memorie partajată, pe un procesor x86 cu 32 MB RAM, bootat de pe un CompactFlash de 64 MB — este un exemplu de inginerie software cu constrângeri absolute. Fiecare octet de RAM este alocat explicit. Fiecare proces are un rol precis. Nu există garbage collector, nu există memory leaks (modulele de date au dimensiune fixă), nu există procese inutile.</p>
<p>Sistemul a funcționat ani de zile fără repornire, producând mii de tone de beton, în condiții de praf, vibrații, și temperaturi extreme. Este genul de software pe care nu-l vezi niciodată — dar de care depind podurile, drumurile și clădirile din jurul tău.</p>
<h2>Momentul adevărului: aplicația pornește în emulator</h2>
<p>După toate analizele — reverse engineering pe filesystem, disecție binară pe module, reconstituirea arhitecturii aplicației — a venit timpul pentru testul final: să pornim aplicația completă într-un emulator, fără niciun hardware fizic.</p>
<p>Provocarea era clară: modulul <code>interbus</code> (driver-ul pentru placa Phoenix Contact PC979K) accesează direct hardware-ul — porturi I/O ISA și o zonă de memorie partajată (DPRAM) la adresa fizică 0xD0000. Fără placa fizică, <code>interbus</code> abortează cu <code>Erreur #032:032</code> și oprește toată aplicația.</p>
<h3>Soluția: 3 bytes + un bloc de memorie</h3>
<p>Am combinat două tehnici:</p>
<p><strong>1. Neutralizarea accesului I/O</strong> — am înlocuit instrucțiunile <code>in al,dx</code> și <code>out dx,al</code> din funcțiile port_read/port_write ale modulului <code>interbus</code> cu <code>nop</code>. Două instrucțiuni, <strong>2 bytes</strong> modificați. Toate citirile de porturi I/O returnează acum 0 (semnalul „reset complet, nicio eroare“), toate scrierile sunt ignorate silențios.</p>
<p><strong>2. DPRAM pre-populat</strong> — am creat un bloc de 16 KB cu registrele de status ale controller-ului Interbus setate la valorile corecte:</p>
<ul>
<li>Registrul de diagnostic: <code>0x00E0</code> (RUN + ACTIVE + READY)</li>
<li>Status Register 1: <code>0x8800</code> (ambele noduri ready)</li>
<li>Control: <code>0x4000</code> (ciclu de date activ)</li>
</ul>
<p>Acest bloc e încărcat de QEMU la adresa fizică 0xD0000 — exact unde <code>interbus</code> se așteaptă să găsească DPRAM-ul plăcii PC979K.</p>
<p><strong>3. Timer-ul PIT 8253</strong> — un singur byte: <code>%set_ticker</code> → <code>*set_ticker</code> în scriptul de startup. Calibrarea timer-ului hardware nu funcționează în emulator, dar e irelevantă pentru aplicație.</p>
<p>Total: <strong>3 bytes</strong> modificați pe o imagine de 64 MB, plus un blob de memorie. Și apoi:</p>
<h3>Ecranul DONNEES DE SERVICE</h3>
<figure class="blog-image">
<img src="/blog/img/screenshot_gui_working.png" alt="Interfața AES Compumat — DONNEES DE SERVICE live în QEMU" loading="lazy">
<figcaption>Interfața AES Compumat — ecranul DONNEES DE SERVICE afișat live în QEMU, la 20+ de ani după ce software-ul a fost scris</figcaption>
</figure>
<p>Pe ecranul albastru al terminalului QVT emulat, interfața operatorului afișează:</p>
Formule 0 DONNEES DE SERVICE 15/03/26 11:15:56
< ESSAI >
Att APPELLATIONS % %H2O DEBIT 0% 100%
GRA.
GRA.
GRA.
GRA.
GRA.
GRA.
LIA.
LIA.
EMU.
ADJ.
ADJ.
EAU
EAU
TC : 0 0 TD1: 1 1 TOTAL :
ED : TD2: - DEBIT TM : 0.000
MARCHE CENTRALE : 0 0 QT DEMANDEE : 0.000 PRESELECTION : 0.000
MARCHE MATERIAUX : 0 0 QT DELIVREE : 0.000 0.000
CONJUGATEUR en % : 100 % QT CASQUE : 0.500
CURSEUR: Home SOMMAIRE: Esc GUIDE: ? <p>Fiecare linie are un rost:</p>
<ul>
<li><strong>GRA.</strong> × 6 — cele șase dozatoare de agregate (pietriș, nisip, de diferite granulații)</li>
<li><strong>LIA.</strong> × 2 — două silozuri de liant (ciment)</li>
<li><strong>EMU.</strong> — dozator de emulsie</li>
<li><strong>ADJ.</strong> × 2 — doi aditivi (plastifianți, acceleratori de priză)</li>
<li><strong>EAU</strong> × 2 — două circuite de apă</li>
<li><strong>ESSAI</strong> — modul de test (stația nu produce, doar se verifică parametrii)</li>
<li><strong>CONJUGATEUR 100%</strong> — ritmul de producție la maxim</li>
<li><strong>QT CASQUE 0.500</strong> — 500 kg capacitate buncăr</li>
</ul>
<p>Data din colțul dreapta: <strong>15/03/26</strong> — 15 martie 2026. Ceasul OS-9000 funcționează corect în emulator, la 20+ de ani după ce software-ul a fost scris.</p>
<p>Este ecranul pe care operatorul stației îl vedea zilnic, în cabina de comandă, cu praf de ciment pe mâini și telefoane de la șantier. Un ecran care a comandat producția a mii de tone de beton — de la bordurile de trotuar din Negrești la stabilizatul de pe pistele unui aeroport.</p>
<p>Iar acum rulează pe un laptop, într-un emulator, pe un sistem de operare pe care nimeni nu-l mai folosește, fără niciun gram de ciment în raza a sute de kilometri.</p>
<h2>Ce am învățat</h2>
<div class="blog-conclusion">
<p>Acest card de 64 MB conține un ecosistem software complet: sistem de operare, drivere, aplicație industrială, configurații, rețete și stack de rețea. Totul — inclusiv FTP, Telnet, cinci limbi și un compressor gzip — în mai puțin spațiu decât o singură fotografie de pe telefonul mobil.</p>
<p><strong>Simplitatea este rezistență.</strong> Un sistem care rulează de peste 15 ani fără update-uri, fără antivirus, fără conexiune la internet. Boot-ează în secunde, nu în minute. Nu are procese inutile în fundal. Fiecare byte are un rost.</p>
<p><strong>Documentația dispare, hardware-ul se uzează, dar datele persistă.</strong> Nu am găsit niciun tool modern care să citească nativ acest filesystem. Producătorul OS-9000 (Microware) a fost cumpărat de RadiSys, apoi de Eurotech. Software-ul AES pare abandonat. Dar datele de pe card sunt intacte și citibile — dacă știi unde să cauți.</p>
<p><strong>Reverse engineering-ul este o artă a răbdării.</strong> Am reconstruit structura unui filesystem proprietar pornind de la documentație publică pentru o altă arhitectură (6809/68000, big-endian) și adaptând-o pentru x86 (little-endian, adrese pe 32 biți). Cheia a fost un offset de +1 între adresa logică și sectorul fizic — un detaliu pe care nicio documentație nu-l menționa.</p>
<p><strong>Backup-urile sunt critice.</strong> Acest CompactFlash nu se mai fabrică. Dacă ar fi cedat, toată configurația stației — rețete, parametri, calibrări — ar fi fost pierdută. Fără backup, repunerea în funcțiune ar fi însemnat săptămâni de lucru.</p>
<p><strong>Emularea bate simularea.</strong> Am încercat mai întâi să simulăm complet placa Interbus — cu DPRAM, registre de status, secvențe de inițializare. Nu a fost suficient. Soluția a venit din combinația a două tehnici minimaliste: neutralizarea a două instrucțiuni de I/O (2 bytes) și pre-popularea memoriei partajate (16 KB). Uneori, cea mai simplă abordare funcționează cel mai bine.</p>
</div>
<hr>
<p class="blog-endnote">Toate lucrările au fost efectuate pe copii ale imaginii originale. Originalul rămâne neatins, protejat read-only — prima regulă a forensicii digitale.</p>
<p class="blog-endnote">Scripturile folosite în această investigație — extractorul RBF și boot-loader-ul QEMU — sunt disponibile ca Python, scrise de la zero pentru un filesystem și un sistem de operare pe care nimeni nu le mai folosește.</p>