Nei giorni scorsi è rimbalzata, nei vari medium IT, la notizia di una “nuova” architettura a cui Intel starebbe lavorando, chiamata X86-S. In realtà non è esattamente nuova (da cui il precedente virgolettato), ma si tratta di x86-64/x64 (l’estensione a 64 bit di IA32 = x86, che AMD introdusse esattamente 20 anni fa) che, però, ha subito una “cura dimagrante”, avendo eliminato un bel po’ di funzionalità obsolete (“legacy“).
Non si tratta di roba di poco, in quanto (e dopo ben 45 anni di onorata carriera) è stato dato il benservito all’originaria architettura 8086 che ha fatto la fortuna di Intel in primis, come pure di AMD. Dunque non è più possibile eseguire codice nella cosiddetta modalità reale (quella propria di 8086), ma neppure di quella protetta a 16 bit né tanto meno quella virtuale (sempre a 16 bit). Sparisce completamente, quindi, l’esecuzione di codice a 16 bit, in tutte le salse: un cambiamento epocale!
Non solo codice a 64 bit: i 32 bit rimangono!
L’articolo parla di un’architettura solamente a 64 bit (come, purtroppo, è stato riportato anche da alcuni giornalisti del settore, che evidentemente non hanno letto bene tutto il pezzo né tanto meno la precisa documentazione tecnica su tutte le modifiche apportate), ma in realtà è ancora possibile eseguire applicazioni a 32 bit, sebbene esclusivamente in modalità protetta e con la paginazione attiva (per cui non è possible sfruttare anche la famosa modalità unreal a 32 bit). Inoltre il codice a 32 bit può girare esclusivamente per le applicazioni (quindi nel cosiddetto ring 3) e non per il s.o. o driver (che girano nel ring 0).
In soldoni, il sistema opera sempre a 64 bit per applicazioni, kernel e driver, mentre a 32 bit è possibile eseguire soltanto applicazioni. Diciamo che i 64 bit sono “di prima classe”, mentre i 32 bit “di seconda classe” in quanto sono sostanzialmente “ospitati” all’interno di un sistema che è interamente a 64 bit (e che fa tutto ciò che vuole, ma soltanto in questa modalità).
Sebbene negli ultimi anni i s.o. sviluppati siano sostanzialmente solo a 64 bit (il che ha portato Intel a definire e proporre X86-S, per l’appunto), il supporto al codice a 32 bit non è stato del tutto eliminato come per quello a 16 bit, e per un’ottima ragione: sono ancora troppe le applicazioni di questo tipo.
Stessa paginazione della memoria per tutti
Impossibile, quindi, pensare di far fuori anche il codice a 32 bit, ma relegandolo esclusivamente lato applicativo si riduce la complessità della piattaforma, in quanto tutto ciò che attiene alla gestione del sistema viene delegato interamente alla modalità a 64 bit. Questo include, infatti, anche la gestione delle pagine, che su x86 contava 2 o 3 livelli (a seconda che la granularità della pagine fosse di 4MB e 4KB rispettivamente) oltre al fatto che la paginazione stessa fosse o meno attiva, mentre adesso è sempre attiva e può utilizzare 4 o 5 livelli (anche per il codice a 32 bit. Sebbene, ovviamente, l’indirizzo virtuale generabile possa sfruttare effettivamente soltanto 2 o 3 livelli, a seconda della granularità impostata dal s.o. a 64 bit. Ma in ogni caso la logica di traduzione delle pagine in indirizzo fisico dovrà tenere sempre conto di uno o due livelli in più di traslazione, a seconda che ci siano 4 o 5 livelli in totale impostati nel sistema).
In ogni caso nulla di ciò impatta la compatibilità con l’attuale ecosistema a 64 bit, perché stiamo parlando di come già adesso funziona il tutto (ossia l’esecuzione di applicazioni a 32 bit all’interno di un s.o. a 64 bit). Quello che cambia è, invece, l’impossibilità per i s.o. a 64 bit di avere / o delegare a codice a 32 bit parte dell’esecuzione di kernel o driver. Sempre che ce ne siano ancora, ovviamente (e sarebbe decisamente strano, dall’introduzione dei primi processori nonché s.o. a 64 bit).
Segmentazione, addio!
Un’altra fonte di possibili incompatibilità sarebbe, invece, l’addio alla segmentazione anche per le applicazioni a 32 bit, che opererebbero in maniera identica a quelle a 64 bit. Per la precisione, la segmentazione non è del tutto sparita in questa modalità, ma viene mantenuta esclusivamente la possibilità di aggiungere un indirizzo “base” all’indirizzo virtuale quando si utilizzino i segmenti FS o GS (per tutti gli altri, ossia CS, SS, DS ed ES, quest’indirizzo base è sempre forzato a zero). Ciò è comodo per le applicazioni che utilizzino il Thread-Local Storage (TLS) o per il kernel quando deve accedere ad alcune sue strutture interne.
Oltre a ciò, tutti i meccanismi di protezione che erano disponibili (e attivi) per i segmenti sono, adesso, completamente disabilitati. Quindi non esistono più controlli dei limiti per i segmenti (sostanzialmente ogni segmento è “flat“, ossia occupa l’intero spazio d’indirizzamento virtuale. 32 bit per le applicazioni a 32 bit, oppure 48 o 57 bit, a seconda dei livelli delle pagine, per quello a 64 bit). Come pure non esistono più i controlli per l’accesso alla memoria (sola lettura, lettura e scrittura, sola esecuzione) che erano possibili coi segmenti (chiamati selettori, in realtà, in modalità protetta. Che ormai è sempre attiva. Ma per comodità parlerò sempre di segmenti). Rimangono, pertanto, i soli controlli offerti dalla paginazione.
Nulla di trascendentale, comunque, perché tutto il codice a 64 bit funziona già così. Ma quello a 32 bit potrebbe, invece, far ancora uso dei segmenti. In realtà anche le applicazioni a 32 bit non usano più da tempo immemore la segmentazione, e questo già coi vecchi s.o. a 32 bit (quelli più diffusi / di massa, insomma).
Nella mia esperienza disassemblando codice di applicazioni e analizzando le statistiche delle istruzioni trovate, il massimo che si può riscontrare è l’utilizzo del prefisso FS in alcuni accessi in memoria, proprio per sfruttare il suddetto meccanismo di TLS (che è decisamente comodo con x86/x64, rispetto ad altre architetture che richiedono apposite modalità d’indirizzamento allo scopo, oppure istruzioni). Non c’è altro relativo ai segmenti, per cui la loro effettiva eliminazione non dovrebbe portare ad alcun problema di compatibilità.
Benvenute modalità utente e supervisore!
Sempre sulla stessa linea / filosofia risulta la sostanziale rimozione dei famigerati “ring” (livelli di privilegi), che sono stati introdotti con l’80286 e, per l’appunto, con la sua modalità protetta. In realtà i ring sono ancora presenti, ma è possibile utilizzarne esclusivamente due: il 3 (per le applicazioni) e lo 0 (per kernel e driver). I ring 1 e 2 non sono più selezionabili / eseguibili, e ogni tentativo di farlo comporta il sollevamento di un’eccezione. Per cui è possibile soltanto passare da ring 3 a 0, e viceversa (ma non per le applicazioni a 32 bit, che operano sempre in ring 3).
In buona sostanza Intel abbraccia lo stesso modello di esecuzione, semplificato, che è presente in tantissime altre architetture. Sono presenti soltanto due modalità: utente/user (ring 3) e supervisore/kernel (ring 0). D’altra parte e nonostante la notevole flessibilità dovuta alla presenza di ben quattro modalità (da ring 0 a ring 3), nessun s.o. (di massa) ne ha tratto beneficio per un maggior isolamento del codice (ad esempio usando il ring 2 per le librerie di sistema e il ring 1 per i driver), per cui era rimasto soltanto un orpello che aumenta soltanto la complessità del sistema.
Non è più tempo di istruzioni di I/O…
Sebbene le applicazioni (tutte: a 32 e 64 bit) girino soltanto in ring 3, finora era possibile eseguire istruzioni di I/O (quelle che controllano i registri di I/O delle periferiche, che sono mappate in questa speciale modalità d’indirizzamento, la quale è appannaggio soltanto di poche, vecchie, architetture, come ad esempio lo Z80), ma con X86-S ciò non sarà più possibile: il loro utilizzo rimarrà esclusiva pertinenza del s.o. (ring 0). Contestualmente viene eliminata anche la mappa di I/O legata a uno specifico processo, che consentiva al s.o. di regolare in maniera estremamente granulare (a livello di singola porta) quali porte fossero accessibili o meno.
Legata ancora a questa eliminazione dell’utilizzo delle porte di I/O per controllare le periferiche è anche la singolarissima e a dir poco eclatante decisione di togliere di mezzo anche alcune di queste istruzioni che erano state introdotte, in merito, dall’80186: quelle INS
e OUTS
, incluse le controparti “ripetute” (usando il prefisso REP
: REP INS
e REP OUTS
).
Si tratta di una decisione incredibile, a mio avviso, perché per la prima volta Intel decide di togliere di mezzo un’istruzione “legacy” (fardello che si trascina da tempi lontani), infliggendo una picconata alla retrocompatibilità a tutti i costi che l’ha sempre contraddistinta (al contrario di Motorola che, specialmente con l’architettura 68000, ha sempre, sistematicamente, preso decisioni di questo tipo. Infatti non esistono processori di tale famiglia che siano totalmente retrocompatibili).
Similmente e coerentemente con le decisioni prese, viene tolta di mezzo anche l’istruzione LMSW
, che serviva all’80286 per caricare un valore al registro che contiene le più importanti impostazioni per la modalità protetta. Morte tutte le modalità a 16 bit del processore, quest’istruzione è del tutto inutile, per cui non aveva più alcun senso mantenerla e, quindi, è stata giustamente tolta di mezzo.
… e nemmeno di indirizzi a 16 bit!
Sempre in merito ai 16 bit, va sottolineata anche l’impossibilità di utilizzare istruzioni a 16 bit per il calcolo degli indirizzi, tramite gli appositi prefissi: 67 (in esadecimale) o 66, a seconda delle istruzioni. Per essere chiari, x86 dava (dà) la possibilità, per codice a 32 bit, di azzerare i 16 bit alti di un indirizzo, mantenendo soltanto i 16 bit bassi, quindi riducendo, di fatto, gli indirizzi a soli 16 bit (64KB di memoria indirizzabile. Oppure eseguire codice soltanto nei primi 64KB di memoria).
Non m’è mai capitato di vedere istruzioni di questo tipo in applicazioni a 32 bit, per cui non credo che se ne sentirebbe la mancanza, consideratone anche il funzionamento un po’ contorto e oggettivamente inutile. Mentre lo stesso, identico, meccanismo per le applicazioni a 64 bit rimane in piedi, ma in questo caso gli indirizzi vengono troncati da 64 a 32 bit e, quindi, serve sostanzialmente a vincolare l’indirizzamento ai primi 4GB di memoria (funzionalità, questa, che è stata utilizzata dalla famigerata modalità / ABI x32).
FPU x87, mon amour!
Infine viene rimossa anche una funzionalità che è, anch’essa, rimasta ben poco utilizzata: l’emulazione dell’FPU (x87). Finora è stato possibile decidere di disabilitarne il funzionamento (sebbene tale unità sia sempre presente a partire dall’80486), il che implica il sollevamento di un’apposita eccezione quando il processore dovesse incontrare una qualunque sua istruzione, consentendo a un apposito software (che abbia provveduto a installarsi nello specifico vettore delle eccezioni) di emularne interamente il funzionamento.
Anche qui l’obiettivo è ridurre la complessità del sistema, evitando di eseguire appositi controlli e prendendo relative decisioni. Quindi il processore eseguirà sempre ogni istruzione dell’FPU, senza eccezione alcuna. Anziché rimuovere completamente quest’unità di esecuzione che risale a più di 40 anni (e, dunque, facente parte a pieno titolo del “legacy”), Intel decide di renderle vita eterna…
Conclusioni
Penso che sia evidente che lo scopo di Intel sia quello di semplificare l’architettura e la sua implementazione (microarchitettura). Non c’erano dubbi in merito (e fa certamente bene a proporre tale modifica ai propri partner), ma a mio avviso ciò che sfugge è che tutti questi cambiamenti non siano dettati da un vigoroso impulso di dare una rimodernata a un’architettura che si porta dietro troppa roba obsoleta e oggettivamente inutilizzata (magari passando a un’architettura nuova!), quanto a cristallizzare quello che è lo stato di fatto da parecchi anni.
Per essere ancora più chiari, è da parecchio tempo ormai che il codice a 64 bit di s.o. e applicazioni funziona in un certo modo, sfruttando certe caratteristiche, mentre le applicazioni a 32 bit che girano su un s.o. a 64 bit vengono già fatte eseguire con tutte le limitazioni di cui sopra, oltre a non sfruttare più le suddette funzionalità legacy. Come pure l’utilizzo di s.o. e/o applicazioni a 16 bit sia ormai retaggio di microscopiche nicche.
Il pensiero degli ingegneri Intel sarà stato “semplicemente” quello di prendere atto della realtà e di conformarne i suoi prodotti a essa. Quindi, se nessuno (o quasi) utilizza certe funzionalità, perché portarsele dietro e continuare a implementarle? Meglio toglierle di mezzo una volta per tutte!
I benefici sono evidenti in termini di complessità del sistema, che si riduce, come si riduce pure il codice per implementare tutto ciò e che è a carico degli ingegneri che devono mantenerlo (e soltanto quello: non sono certamente previste modiche / evoluzioni).
Avendo lavorato per un po’ di anni nel testing dei processori Intel, mi viene d’obbligo sottolineare che in questo modo venga anche tolto di mezzo il controllo di tutte queste funzionalità che, non essendo più presenti, ovviamente non dovranno più necessitare di appositi test, che altrimenti andrebbero sempre eseguiti a prescindere per ogni nuovo processore, anche se l’implementazione della specifica funzionalità non è più cambiata da diversi anni.
Si potrebbe pensare, a questo punto, che il vero motivo di questa decisione sia stato quello di ridurre il numero di transistor utilizzati, e quindi non soltanto l’area dei chip, ma anche il loro consumo. In realtà non è così, e ho trattato già l’argomento parecchi anni fa sempre su queste pagine:
- ARM vs Intel: I cut the power!
- La “guerra” dell’ISA x86: l’impatto su decoder, compilatori, e implicazioni varie
- Il legacy di x86 & x64
In sintesi: l’impatto è decisamente limitato ed è più rilevante soltanto con chip, come gli Atom, che hanno core molto piccoli. Ma anche qui, non si parla di cifre astronomiche. Avendo avuto la fortuna di lavorare alla Intel e di fruire di alcuni webinar, ne ricordo alcuni proprio sull’argomento e in cui veniva mostrato che l’impatto, per i primi core Atom, in termini di maggior numero di transistor e consumi risultava nell’ordine dell’8-10%, e tutto ciò con processi produttivi molto più vecchi ed energivori.
D’altra parte se è vero che alcune delle funzionalità di cui abbiamo parlato sopra sono sempre attive (ad esempio il controllo dei limiti dei segmenti utilizzati viene effettuato per ogni singola istruzione eseguita) e, quindi, incidono sui consumi, è anche vero che si tratta di poca logica che richiede pochi transistor, per cui sia l’area richiesta nel chip sia l’energia richiesta risultano entrambe estremamente limitate.
Quindi chi sperava che Intel si muovesse per questi motivi o addirittura osasse qualcosa di più (innovativo) può tornare a riporre le speranze nel cassetto, perché non v’è segnale alcuno in tale direzione: non c’è nessuna novità sostanziale in merito.
Intel (ma sia chiaro che lo stesso vale per AMD, la quale non propone assolutamente nulla di nuovo all’orizzonte), insomma, continua a rimanere saldamente ancorata alla sua architettura, probabilmente perché forte dell’enorme diffusione che ha in ambito desktop e server.
Ma su entrambi i fronti è da tempo in atto una lenta erosione che proviene da ARM, che continua a espandere le sue quote di mercato, e prossimamente anche RISC-V diventerà una concorrente temibile (per entrambe: ARM si sta già vedendo rosicchiare il mercato embedded, dove è dominatrice assoluta da decenni).
L’essersi legata mani e piedi alla sua architettura ha rappresentato il successo (enorme) per Intel, ma in futuro potrebbe diventare anche l’abbraccio fatale, considerato il peso sempre minore che hanno x86 e x64.
Proporre architetture nuove di pacca e in grado di ritagliarsi fette di mercato non è certo un tabù, come ha dimostrato ARM con la sua AArch64/ARMv8 (che, tra l’altro, non è retrocompatibile né con “ARM32” né con Thumb, le quali hanno fatto la fortuna di questa casa!) e adesso RISC-V.
Abbracciare RISC-V non avrebbe molto senso, perché non fornirebbe alcun valore aggiunto ai clienti e, quindi, finirebbe fra le centinaia di aziende che hanno già adottato questa nuova ISA.
A Intel e AMD serve un’architettura nuova, innovativa, che faccia tesoro del lavoro fatto con x86/x64 (perché ce n’è tanto, a dispetto di quanto si possa pensare), e proponga del valore aggiunto che manchi alla già citata concorrenza. Quindi non una semplice spolverata, qual è X86-S…