di  -  giovedì 4 ottobre 2012

Per gestire segmenti e selettori a livello applicativo abbiamo visto che sono necessarie poche istruzioni (MOV, PUSH/POP, LDS/LES/LSS/LFS/LGS, CALL/RET, JMP, INT/INTO/IRET), peraltro inutilizzate in un modello di memoria “flat” (fatta eccezione per quelle usate per chiamare il sistema operativo).

Il s.o., invece, fa sempre uso di una parte di queste quanto meno per impostare i selettori (ormai i segmenti 8086 sono, di fatto, inutilizzati) in maniera che l’applicazione che gira nel processo/thread abbia l’ambiente configurato per poter girare, ma tutto ciò non basta per gestire l’intero sistema, per cui già a partire dall’80286 sono state introdotte istruzioni allo scopo.

Questo perché, se è vero che ormai il legacy di x86 nella normale esecuzione non ha praticamente peso, come abbiamo appurato dai precedenti articoli, è anche vero che in ogni caso rimane sempre attivo e che, quindi, i selettori debbano in qualche modo essere caricati almeno una volta, seppur con valori “di comodo” (per abilitare lo spazio d’indirizzamento unico, che copre tutto lo spazio virtuale).

Caricare un selettore significa eseguire un’istruzione MOV o una POP per i dati, oppure una CALL/RET, JMP, o INT/INTO/IRET per quanto riguarda il codice. Operazione che non è possibile se non è stata impostata quanto meno la tabella dei descrittori globali (per maggiori informazioni consiglio sempre di rispolverare il vecchio articolo sull’80286).

Infatti mentre per un segmento 8086 caricare un segmento equivaleva ad avere già immediatamente a disposizione l’indirizzo base da utilizzare per i successivi accessi, fare la stessa operazione con un selettore vuol dire semplicemente piazzare un dato in quel registro, che corrisponde a un indice (e un livello di privilegio) in una delle due tabelle di descrittori (globale o locale).

Per ottenere finalmente l’indirizzo base è, pertanto, necessario accedere a una di queste due tabelle, caricando l’apposito descrittore, cioè una struttura dati che consente di specificare non soltanto tale indirizzo, ma anche l’ampiezza dell’area indirizzabile (il cosiddetto limite; per gli offset, ovviamente) e vari altri flag che ne regolano l’accesso.

Risulta fondamentale, allo scopo, avere già sistemato la tabella dei descrittori globali, tramite la nuova istruzione LGDT, la quale, per quanto detto finora, non può che essere privilegiata, in quanto eseguibile esclusivamente al livello di privilegio più elevato (lo 0, dei 4 messi a disposizione dal meccanismo dei selettori; il 3 è usato per le applicazioni).

Lo scopo è semplice: caricare l’indirizzo base (24, 32, o 64 bit) a partire dal quale si estende la tabella, e un valore a 16 bit che ne rappresenta il limite (in modo da intercettare eventuali accessi a descrittori inesistenti o riservati). La duale è SGDT, che memorizza i valori attuali in memoria.

Un’esigenza simile c’è anche per interrupt ed eccezioni. Prima dell’introduzione della modalità protetta la CPU utilizzava il primo KB di memoria dello spazio d’indirizzamento per ottenere il puntatore al codice relativo a una ben precisa entry di questa tabella (di 256 elementi).

Con la nuova modalità sono sorte due esigenze. La prima è quella di avere un controllo molto più fine, solido, e sicuro sul codice eseguito per queste importantissime nonché delicatissime operazioni, per cui era perfettamente naturale applicare anche qui il concetto di selettori al posto dei segmenti.

La seconda, comune a tanti altri processori, era quella di poter spostare in qualunque punto in memoria tale tabella, ed eventualmente limitare il numero di entry accessibili. L’istruzione LIDT nasce appositamente allo scopo, e funziona esattamente come la LGDT, consentendo, quindi, di caricare l’indirizzo base e il limite dalla memoria. Similmente, la duale è rappresentata dalla SIDT.

Assomiglia a queste anche la LLDT, che consente di caricare la tabella dei descrittori locali, ma la differenza è sostanziale. Non consente, infatti, di specificare direttamente indirizzo base e limite, ma l’istruzione carica un selettore nell’apposito registro (LDTR), e se questi risulta valido (e del tipo giusto) sarà utilizzato per prelevare base e limite dalla tabella dei descrittori globali.

Si tratta, in sostanza, di una doppia lettura dalla memoria: prima il selettore, e successivamente il corrispondente descrittore per recuperare le informazioni che servono. La tabella dei descrittori globali serve, quindi, per conservare un certo numero di tabelle di descrittori locali che il s.o. utilizzerà di volta in volta per impostare gli specifici dati dei vari processi/thread.

Si tratta di un’istruzione un po’ più complicata rispetto alle precedenti, che richiedevano soltanto una lettura (o scrittura, per le store) dalla memoria, ma la cui implementazione non richiede certamente esagerate risorse. Ovviamente la sua duale, la SLDT, risulta molto più semplice, in quanto deve memorizzare soltanto i 16 bit del selettore correntemente caricato.

Molto simile a alla LLDT è l’istruzione LTR, che serve a caricare un selettore nel Task Register (la STR lo memorizza, invece). Anche qui, trattandosi di un selettore, se è valido ed è del giusto tipo, vengono prelevati base e limite dalla tabella dei descrittori globali; questi valori vengono utilizzati per individuare la zona di memoria dove sono memorizzate tutte le informazioni relative a un ben preciso processo/thread.

Com’è stato evidenziato nell’articolo sull’80286, con la modalità protetta è stato introdotto il concetto di task, che consente di implementare lo switch di processi/thread in maniera molto semplice ed efficiente (sebbene vengano richiesti parecchi cicli di clock). Infatti lo stato del task correntemente eseguito viene memorizzato nella zona di memoria individuata dal Task Register (TR), subito dopo viene prelevato il selettore del nuovo task, caricati indirizzi base e limite, e infine caricato lo stato completo per poi cedergli l’esecuzione.

Purtroppo questa interessantissima novità non è stata sfruttata da chi ha scritto i s.o., in quanto pochissimi microprocessori offrono funzionalità equivalenti, per cui i programmatori hanno preferito progettare kernel generici, in grado di essere facilmente adattati al più gran numero di architetture, piuttosto che realizzarne versioni apposite per la modalità protetta degli x86.

In effetti forse è anche un bene che tale funzionalità non sia stata utilizzata e ulteriormente sviluppata, poiché è opinabile cosa s’intenda per “stato” di un processore, tant’è che non vengono memorizzati, ad esempio, i registri dell’FPU né dell’unità SIMD (ove presente) … né altro che potrebbe essere utile per un processo/thread.

Difatti si rende necessario l’uso di un bit presente nel registro CR0 (ex MSW, Machine Status Word, introdotto nell’80286) per indicare se si è verificato un task switch, in modo che il kernel possa valutare l’opportunità di conservare lo stato di tutti i registri che non sono stati conservati nello switch. Allo scopo è utile anche l’istruzione CLTS, che serve ad azzerare questo flag, una volta portata a termine l’operazione.

Sarà, dunque, per questi motivi che in modalità a 64 bit (x64) non è presente alcun supporto ai task (sebbene debba essere impostato un selettore nel Task Register; infatti non è supportato il meccanismo di context-switch automatico, ma il concetto di task permane), similmente alla tabella dei descrittori locali che in questa modalità è completamente inutile (i selettori sono, di fatto, disabilitati).

Rimane l’esigenza di poter gestire la tabella dei descrittori globali, perché i registri di segmento contengono comunque dei selettori, e in ogni caso FS e GS continuano a essere validi quanto meno per specificare l’indirizzo base. Inoltre anche per interrupt ed eccezioni è ancora necessario poter accedere all’apposita tabella dei descrittori.

Riprendendo il citato registro MSW, sono presenti due istruzioni, LMSW e SMSW, che consentono di caricarvi un valore o salvarlo in memoria. La prima, in particolare, veniva usata per passare dalla modalità reale a quella protetta, imposta alcuni bit in esso presenti. Questa coppia di istruzioni privilegiate va senz’altro contemplata nel legacy, in quanto dall’80386 è presente il più ampio (32 bit) registro CR0, oltre a una coppia di istruzioni MOV che consentono di leggere e scrivere valori presenti in uno qualunque dei nuovi registri di controllo definiti con questa ISA.

Ricapitolando, abbiamo visto che non sono molte le istruzioni privilegiate introdotte per poter gestire la modalità protetta e i selettori, con le sole istruzioni LMSW, SMSW, LLDT e SLDT che si possono configurare come legacy, in quanto non più utilizzate per la presenza di istruzioni più generiche oppure a causa del modello flat che da parecchi anni viene utilizzato dai s.o..

Per concludere, il “peso” di tutte le istruzioni citate (quindi non soltanto di queste ultime) non è elevato. Introdurne una manciata in un’architettura che ne contempla centinaia e centinaia è un’operazione di poco conto. La loro implementazione, poi, è abbastanza semplice, con pochi casi in cui è necessario ricorrere a una doppia indirezione (due letture consecutive e dipendenti).

A runtime, eseguendo il codice di tutti i giorni, il loro costo è quasi nullo, in quanto nei modelli flat l’ambiente di lavoro del processo/thread è già impostato, salvo per il s.o. che deve eseguirne il setup prima dell’avvio.

Non è trascurabile, però, la gestione degli interrupt, che fanno uso dei cosiddetti interrupt gate, accennati nell’articolo sull’80286. Fin dai tempi dell’MS-DOS questo meccanismo veniva utilizzato per richiamare API del s.o., per cui se ci sono ancora s.o. che lo impiegano, s’incappa nel costo del context-switch (non di tutto lo stato del processore, fortunatamente) e nel controllo dei limiti della tabella degli interrupt (poca roba, comunque: giusto un confronto).

Da parecchio, però, i s.o. mettono a disposizione altri meccanismi e istruzioni allo scopo, nettamente più pratici e veloci. Anche di questo parleremo nel prossimo articolo, in cui analizzeremo brevemente le poche istruzioni non privilegiate rimaste che attengono all’argomento legacy finora trattato.

12 Commenti »

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.

  • # 1
    Giacomo
     scrive: 

    Una curiosità, ma oggi esistono ancora le fantomatiche istruzioni riservate, delle quali sono a conoscenza solo il produttore e pochi sviluppatori software privilegiati, come accadeva negli anni ’90?

  • # 2
    Cesare Di Mauro (Autore del post)
     scrive: 

    Per lo più si trattava di esperimenti, che diventavano pubblici dopo qualche versione del processore, o perché venivano scoperte da qualcuno ed erano realmente utili.

    Ma non sempre ciò si verifica. Mi vengono in mente, su due piedi, la LOADALL (mi pare fosse apparsa sull’80286) e la SETALC.

    Non credo, però, che queste istruzioni fossero realizzate per pochi sviluppatori privilegiati. Magari questi ne erano venuti a conoscenza perché smanettavano con gli opcode a caccia di questo tipo di istruzioni, o perché ne erano venuti a conoscenza da qualcuno che l’aveva fatto, e poi le avevano usate nelle loro applicazioni.

    Ma dubito che vi fosse una cerchia di privilegiati. Le istruzioni, se sono “buone”, offrono un vantaggio rispetto alla concorrenza, per cui il produttore della CPU ha tutto l’interesse alla loro pubblicazione e a che se ne diffonda l’uso.

  • # 3
    Giacomo
     scrive: 

    Grazie, avevo sentito di questa storia, non so se leggenda metropolitana, riguardo i Motorola 680×0 e Amiga, dove i top developer come il Team 17 avvano accesso ad informazioni riservate sulle istruzioni per spingere al massimo i loro giochi :D

  • # 4
    Cesare Di Mauro (Autore del post)
     scrive: 

    Prima di cercare queste informazioni, avrebbero dovuto studiare meglio la documentazione dell’hardware (chip custom inclusi) a disposizione di tutti. O:-)

    Sono pochi i dettagli poco noti dei Motorola 68000. Ad esempio quanto costa effettivamente una moltiplicazione, che non è quel numero esatto che si trova generalmente nei manuali, ma era variabile e dipendeva da quanti bit a 1 erano presenti in uno dei due operandi (non ricordo quale al momento né la formula esatta), per cui alcune moltiplicazioni potevano essere più veloci del classici shift + add che si usavano per cercare di evitare quelle istruzioni.

    Non ricordo di altri casi particolari. Ho sentito dire tempo fa che il solo fatto di eseguire del codice in modalità supervisore avrebbe portato miglioramenti alle prestazioni, ma francamente non c’ho mai creduto…

  • # 5
    Ciano
     scrive: 

    Finalmente un’altro articolo. Non vedo l’ora di avere il tempo per leggerlo con attenzione.

  • # 6
    Giallu
     scrive: 

    Lo chiedo qui anche se centra poco,
    è possibile in futuro leggere su AD un articolo sul CellBE? Ho preso spunto l’idea da questo thread:
    http://forum.beyond3d.com/showthread.php?t=61048
    dove si parla di pregi e difetti dell’architettura. Anche se ci ho capito poco, non (mi) è ben chiaro se i difetti ad esso imputabili fossero scelte già palesemente scellerate in partenza oppure si critica erroneamente l’architettura con il senno di poi. Inoltre sarebbe interessante sapere se e dove le moderne architetture hanno preso spunto dal CellBE (Larrabee, HSA, ecc.) oppure se quella di IBM si è dimostrata una dead-end road.

  • # 7
    Cesare Di Mauro (Autore del post)
     scrive: 

    Francamente di Cell ne ho (abbiamo, con altri) parlato fino alla nausea in passato, prima ancora che la PS3 fosse commercializzata. Ti riporto alcuni link:

    http://www.hwupgrade.it/forum/showpost.php?p=8192788&postcount=48
    http://www.hwupgrade.it/forum/showthread.php?t=1000669
    http://www.hwupgrade.it/forum/showthread.php?t=1102887

    Tra l’altro molte discussioni sono state fatte quando ancora non era disponibile nemmeno la documentazione, giusto con le poche informazioni che Sony & co. rilasciavano. Nonostante tutto, alla fine le previsioni che avevamo fatto (io e altri utenti) si sono verificate.

    Tutti e tre i 3 thread sono interessanti, soprattutto per l’epoca in cui si è discusso, ma l’ultimo, in particolare (anche se molto lungo), che ha visto coinvolti sviluppatori ufficiali PS3, e di PC & XBox360, e ingegneri che hanno progettato alcune GPU Radeon, oltre ad altri professionisti (ci trovi anche i miei messaggi).

    Come potrai vedere, i difetti furono già ampiamente sviscerati, e quindi non si tratta di discorsi “col senno di poi”, ma di MOLTO prima.

    Poi le moderne architetture non hanno preso spunto da Cell, se non per il fatto che questo processore ha anticipato l’uso di molti core semplici per calcoli massicciamente paralleli e/o distribuiti. Ma a livello architetturale non vi sono somiglianze né con Larrabee né tanto meno con l’HSA di AMD.

    Infine, penso sia ormai evidente che Cell sia una strada morta. Nemmeno Sony, da quelle notizie che sono circolate finora, dovrebbe usarlo nella sua prossima console.

    P.S. Scusami se non leggo il thread di Beyond3D, sicuramente molto interessante, ma non ho tempo. E poi, come ti dicevo, discussioni ne abbiamo già ampiamente fatto in passato, e ritengo che non siano meno valide di quella che hai postato. ;)

  • # 8
    Giallu
     scrive: 

    Non conoscevo, grazie per la segnalazione.

  • # 9
    Giacomo
     scrive: 

    Riguardo al Cell aggiungo l’articolo di AD
    http://www.appuntidigitali.it/5965/perche-sony-mettera-una-pietra-tombale-su-cell/

  • # 10
    Cesare Di Mauro (Autore del post)
     scrive: 

    Non ho voluto riportare quel link per due motivi.
    Primo, perché è mio e mi si sarebbe potuto accusare di autoreferenzialità (io do ragione… a me stesso :D).
    Secondo, perché si tratta di un’analisi a posteriori, anche se sostanzialmente dice le stesse cose che affermavo 5 anni prima.

    Comunque grazie per averlo riportato: è altro materiale che può interessare sicuramente a Giallu sulla questione :)

  • # 11
    Giallu
     scrive: 

    L’ultimo link è interessante, anche se bisogna fare lo slalom tra una miriade di insulti e flame.

    Leggendo anche i due precedenti thread non mi è chiara la strategia di IBM: se Cell è sbilanciato sullo stream processing, è possibile che questo facesse parte dei loro piani a lungo termine?
    Se è chiaro che Sony avrebbe usato in ogni caso Cell su PS3 per recuperare i finanziamenti e Toshiba…boh, pure( forse si aspettavano di riuscire a passare più velocemente a processi produttivi migliori), IBM avrà per lo meno collocato Cell in una qualche road-map.

    Daltronde IBM ha deciso di far parte di una joint-venture quando poteva fare benissimo da committente e assecondare ogni assurda richiesta di Sony-Toshiba. Difficile credere allo svarione intergalattico in fase progettuale, IBM avrebbe riportato i due compari sulla retta via a suon di scoppole proponendo ai due un approccio tipo Xenon che, ipotizzo, ad IBM sarebbe andato pure bene nell’ottica di piani futuri.

    Fino almeno al 2008 IBM ha supportato Cell con documentazioni, risorse, corsi e in ambito hardware con server e supercomputer, fino al momento in cui era evidente che l’architettura era diventata obsoleta. A quel punto hanno tirato le somme, visto cosa ha funzionato, cosa gettare alle ortiche. Da qui la mia espressione “critica con il senno di poi”.

  • # 12
    Cesare Di Mauro (Autore del post)
     scrive: 

    Mi spiace per il casino che c’è in quei link. Purtroppo è un forum, in cui è facile che si vada in escandescenze. Ma, tempo permettendo, ne vale la pena per il contenuto tecnico che emerge.

    Riguardo a IBM, beh, anche lei pensava di sfruttare la potenza di calcolo bruta di Cell per i suoi server e anche supercomputer, e alcuni li ha realizzati. Purtroppo Cell è troppo complicato ed è un inferno programmarci.

    Toshiba l’ha usato in alcuni suoi televisori, ma mi sembra che sia un esperimento rimasto figlio unico.

    Insomma, Cell, alla fine, ha deluso proprio tutti.

    Non credo che come soluzione alternativa Xenon sarebbe potuto andare bene (come sostituto di Cell), perché è stato customizzato su indicazioni di Microsoft appositamente per accelerare alcune operazioni comuni nei videogiochi.

Scrivi un commento!

Aggiungi il commento, oppure trackback dal tuo sito.

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.