Chyba v procesorech Intel Pentium -- softwarové řešení
           -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

         Have you heard about the new Cray? It's so fast, it requires
                       TWO halt instructions to stop it!

                       Jan Kasprzak, 21. listopadu 1997

          V předchozím  čísle  Linuxových  novin  byla  uveřejněna  zpráva
      o tom, že byla  objevena  nová  chyba v procesorech  Intel  Pentium.
      Tato chyba umožňuje běžnému  uživateli  zablokovat  procesor tak, že
      je nutno provést  studený start počítače. Této chybě se začalo říkat
      "F00F bug" podle hodnoty prvních dvou bajtů chybné instrukce.

          Dnes   je   situace    podstatně    lepší.   Existuje    způsob,
      jak  softwarově  danou  chybu  odstínit.  Stojí  za  povšimnutí,  že
      k dnešnímu dni (21. listopadu 1997) byla podle  stránky  společnosti
      Intel  http://support.intel.com/support/processors/piie/index.html k
      dispozici  softwarová  záplata pouze pro Linux a BSDI.  (Hovořím zde
      o  systémech s jejichž  vývojáři  Intel  spolupracoval. Z  ostatních
      systémů má softwarovou  záplatu na tuto chybu například  FreeBSD. Na
      uvedené stránce jsou zmiňovány tyto systémy nebo tito výrobci: BSDI,
      IBM, Linux, Microsoft, NCR, Novell, SCO, Sequent, SunSoft a Unisys.)
      Ostatní   systémy  včetně  například   Solarisu  a  SCO  UNIXu  mají
      příslušnou záplatu pouze "ve stádiu vývoje" nebo "testů".

          Je zajímavé, co se zde píše o operačních systémech Microsoftu:


          ''Microsoft  has worked  closely  with  Intel to understand  and
      characterize the effects of the recently uncovered Pentium processor
      erratum,  and we're in the  process of studying  the  implementation
      of   potential   workarounds  in order  to meet   the   needs of our
      customers,''  said  Moshe  Dunie  Vice-President  Windows  Operating
      Systems  Division at Microsoft.  ''Since  this  erratum  can only be
      exploited by a program that was developed with malicious  intent and
      deliberately uses this illegal instruction,  following  common-sense
      computing  practices, such as not downloading or running executables
      from unknown sources, can protect a user from this problem.''

          Microsoft a Intel těsně spolupracovali ve snaze pochopit nedávno
      odhalenou  chybu  procesoru  Pentium a určit její  dopad.  Právě teď
      studujeme různé možnosti jak chybu obejít,  abychom co nejlépe vyšli
      vstříc  potřebám našich  zákazníků, řekl Moshe Dunie,  viceprezident
      divize  Windows  Operating  Systems ve  firmě  Microsoft.  "Vzhledem
      k tomu, že tato chyba může být využita  pouze  programem,  který byl
      napsán se zlým úmyslem a záměrně používá tuto nedovolenou instrukci,
      stačí k ochraně  uživatelů  před  tímto  problémem  chovat se  podle
      zdravého rozumu, třeba nestahovat a nespouštět  programy z neznámých
      zdrojů."

          Tedy  Microsoft  se  zřejmě  vzdal  myšlenky  na to, že by  jeho
      operační  systémy  mohly  být  někdy  nasazeny  ve  víceuživatelském
      prostředí.

          Nyní  se  budu  věnovat   mechanismu,  jakým  chybná   instrukce
      pravděpodobně pracuje a navrhovaným softwarovým  řešením. Samozřejmě
      není v silách jednoho člověka pochopit milióny tranzistorů v Pentiu,
      ale z chování CPU při této chybě lze leccos odpozorovat.  Popisované
      mechanismy se tedy snaží  odhadnout, co se v CPU přibližně  děje při
      výskytu této  instrukce.  Nekladu si žádné  nároky na správnost níže
      uvedených  mechanismů,  nicméně s jejich  využitím se podařilo chybu
      izolovat a odstínit.

          Inkriminovanou  instrukci s operačním  kódem  f0  0f c7 by  bylo
      možné  zapsat  jako lock cmpxchg8b s adresovacím  módem,  který není
      pro  tuto  instrukci  platný.  Tato  instrukce  je "téměř  legální".
      Co to znamená? Na to, že jde o neplatnou  instrukci, a že by se tedy
      měla vyvolat  příslušná  výjimka,  procesor přijde až poměrně pozdě,
      když už je provádění  instrukce uvnitř CPU v pokročilém stavu. Tento
      stav se vyznačuje tím, že procesor už zamknul datovou  sběrnici, jak
      mu přikazuje  instrukční  prefix lock. A zde právě nastává  problém.
      Procesor  zjistí, že instrukce je neplatná, a chce vyvolat příslušné
      přerušení. Toto v první řadě znamená podívat se do tabulky přerušení
      (IDT, Interrupt  Description  Table), na které adrese začíná obsluha
      přerušení  "neplatná  instrukce".  Pokus o přístup k IDT ale  selže,
      protože CPU má zamčenou  sběrnici!  Někde v tomto  místě se procesor
      zastaví.

          Jak takovouto chybu  ošetřit? K přístupu na sběrnici  nedochází,
      pokud  se  příslušná  část  IDT  právě  nachází  v  primární   cache
      procesoru.  První a  nejstarší  softwarové  záplaty  na  tuto  chybu
      fungovaly  tak, že zajistily,  aby se v cache  objevil  ovladač  pro
      obsluhu  výjimky "neplatná  instrukce"  (například  vykonáním nějaké
      skutečně  neplatné  instrukce),  a  pak  zamkly  obsah  cache.  Toto
      fungovalo, ale výkon  procesoru  bez primární  cache  klesl až někam
      k průměrným procesorům 486.

          Pozdější  úpravy  využívaly  toho, že jiné  výjimky mají obsluhu
      zamčené  sběrnice  vyřešeny lépe než výjimka  "neplatná  instrukce".
      Pokud se  například  stránka  IDT, ve  které  byl  vektor  přerušení
      "neplatná  instrukce",  nenachází v operační  paměti,  Pentium  toto
      rozpozná  a vyvolá  výjimku  číslo 8 --  "dvojitý  výpadek"  (double
      fault). Jak tohoto ale dosáhnout?  Stačí  zarovnat  začátek IDT tak,
      aby prvních sedm položek IDT (pro výjimky 0 až 6, přičemž  "neplatná
      instrukce"  má  číslo  6)  bylo v jedné  stránce  a  ostatní  byly v
      následující stránce paměti. Tedy aby tabulka IDT začínala těsně před
      koncem stránky. Dále je nutno upravit  obsluhu  výjimky číslo 8 tak,
      aby byla schopna analyzovat situaci a případně zavolat výjimky číslo
      0 až 6. A poslední věc je označit první stránku IDT jako neplatnou.

          V případě  pokusu o vykonání  neplatné  instrukce se tedy zavolá
      výjimka číslo 8 "dvojitý  výpadek", která pak zpětně zjistí o co jde
      a zavolá  příslušnou  výjimku z intervalu 0 až 6. Toto  může  udělat
      dvěma způsoby. Buďto zjistí  příslušnou  informaci z chybového slova
      a pak zavolá  příslušnou  obsluhu jako funkci (což byl způsob, jakým
      byla  situace  řešena v Linuxu)  nebo se první  stránka IDT namapuje
      do paměti a daná instrukce se restartuje (samozřejmě až po kontrole,
      jestli  náhodou  nešlo o instrukci  f0 0f c7 cx.  Toto  byl  způsob,
      jakým  doporučoval chybu izolovat  Intel.  První způsob měl problémy
      s obsluhou  speciálních  případů,  jako je například  ladící  bod na
      místě neplatné  instrukce a podobně.  Ladící a krokovací  funkce zde
      nefungovaly úplně  korektně.  Naproti tomu druhý způsob  (navrhovaný
      Intelem)  měl  problémy se samomodifikujícím se kódem  (například na
      SMP  stroji -- dojde k přerušení,  namapuje se IDT,  ale někdo  jiný
      změní  zatím  instrukci, na které  došlo k přerušení na f0 0f c7 cx.
      Restartuje  se  instrukce,  ale  IDT  je  namapovaná a  procesor  se
      zablokuje). Linus Torvalds napsal na linux-kernel

          Charles  is  right  about  the  problems,  although  they  don't
      actually apply to the current Linux  version of the patch. They _do_
      apply to the intel  one,  exactly  because the intel one tries to be
      more clever, and fails in subtle ways.

          Co se týče těchto problémů, má Charles pravdu, ačkoli se vlastně
      nevztahují k současné  Linuxové  verzi toho patche.  Vztahují se ale
      k Intelovské  verzi,  právě proto, že ten jejich  patch se snaží být
      chytřejší a nezvládá to.
                                              Linus Torvalds

          Obsloužení  chyby F00F  jedním ze dvou  výše  popsaných  způsobů
      stálo  přibližně 55 taktů při  vyvolání  kterékoli z výjimek 0 až 6.
      Záplaty  provedené  tímto  způsobem  se  objevily  v  Linuxu  2.0.32
      (vlastně již v pre-2.0.32-4) a 2.1.63.

          Jak je vidět,  odstranění  takovéto chyby  popisovaným  způsobem
      nebylo  nijak  triviální.  Naštěstí  Linus  ve  spolupráci s Intelem
      vymyslel  ještě  lepší mechanismus  odstínění  chyby. V CPU se totiž
      v průběhu vyvolání výjimky pro neplatnou  instrukci nejen neresetuje
      zamčení  sběrnice, ale také následující přístup do paměti se provádí
      jako read-write přesně tak, jak by jej prováděla  skutečná instrukce
      lock cmpxchg8b. Takže pokud je IDT namapována pouze pro čtení, dojde
      k zavolání  výjimky  "porušení ochrany paměti".  Příslušná  obslužná
      rutina pak zjistí, že byl  proveden  pokus o zápis do IDT na položku
      číslo 6 a detekuje tak jednoznačně pokus o zneužití chyby F00F.

          The  new  workaround  actually  depends  on the  Intel  bug  not
      only  forgetting to clear  the  ''lock''  state of the  instruction,
      it also  forgets to clear the  fact  that the  instruction  tries to
      do a read-modify-write  cycle. So it will not only do the IDT access
      as a locked  cycle, it will do it as a locked  cycle  that  requires
      write permissions.

          Nová  záplata  vlastně  závisí na chybě  Intelu,  která  nejenže
      zapomene  zrušit  "lock"  stav  instrukce, ale také zapomene  změnit
      informaci o tom,  že  se  instrukce  pokouší  přistoupit  do  paměti
      způsobem  čti-modifikuj-zapiš. Takže procesor nejenže vykoná přístup
      k  IDT  se  zamčenou   sběrnicí,  ale  je  vykonán  zamčený  přístup
      vyžadující navíc právo zápisu.
                                               Linus Torvalds

          Tímto  způsobem se kompletně  odstíní  chyba  F00F a navíc  tato
      záplata  nemá žádný vliv na výkon  systému (na rozdíl od předchozích
      řešení). V současné  době  je k dispozici  záplata  na jádro  2.0.32
      i 2.1.x, využívající tohoto mechanismu.

          Operační   systém  Linux  byl  jedním  z  prvních,   které  měly
      k dispozici  záplatu na hardwarovou  chybu  Pentia.  Tato  chyba pro
      současný Linux již nepředstavuje žádné nebezpečí.


            výheň