Błąd autobusu

W informatyce błąd magistrali to błąd zgłaszany przez sprzęt, powiadamiający system operacyjny (OS), że proces próbuje uzyskać dostęp do pamięci , której procesor nie może fizycznie zaadresować: nieprawidłowy adres magistrali adresowej , stąd nazwa. We współczesnym zastosowaniu w większości architektur są one znacznie rzadsze niż błędy segmentacji , które występują głównie z powodu naruszeń dostępu do pamięci: problemów z adresem logicznym lub uprawnieniami.

Na platformach zgodnych z POSIX błędy magistrali zwykle skutkują wysłaniem sygnału SIGBUS do procesu, który spowodował błąd. SIGBUS może być również spowodowany jakąkolwiek ogólną usterką urządzenia wykrytą przez komputer, chociaż błąd magistrali rzadko oznacza fizyczne uszkodzenie sprzętu komputerowego — zwykle jest to spowodowane błędem w oprogramowaniu . [ Potrzebne źródło ] Błędy magistrali mogą być również zgłaszane w przypadku niektórych innych błędów stronicowania; patrz poniżej.

Powoduje

Istnieją co najmniej trzy główne przyczyny błędów magistrali:

Nieistniejący adres

Oprogramowanie nakazuje procesorowi odczytanie lub zapisanie określonego adresu pamięci fizycznej . W związku z tym CPU ustawia ten adres fizyczny na swojej szynie adresowej i żąda od wszystkich innych urządzeń podłączonych do CPU odpowiedzi z wynikami, jeśli odpowiedzą na ten konkretny adres. Jeśli żaden inny sprzęt nie odpowiada, procesor zgłasza wyjątek , stwierdzając, że żądany adres fizyczny nie jest rozpoznawany przez cały system komputerowy. Należy zauważyć, że dotyczy to tylko fizycznej . Próba uzyskania dostępu do niezdefiniowanego pamięci wirtualnej jest ogólnie uważana za błąd segmentacji, a nie błąd magistrali, chociaż jeśli MMU jest oddzielne, procesor nie może odróżnić.

Niewyrównany dostęp

Większość procesorów jest adresowana bajtowo , gdzie każdy unikalny adres pamięci odnosi się do 8-bitowego bajtu . Większość procesorów może uzyskiwać dostęp do poszczególnych bajtów z każdego adresu pamięci, ale generalnie nie mogą one uzyskać dostępu do większych jednostek (16-bitowych, 32-bitowych, 64-bitowych itd.) bez „dopasowania” tych jednostek do określonej granicy (platforma x86 jest godnym uwagi wyjątkiem ).

Na przykład, jeśli dostępy wielobajtowe muszą być wyrównane do 16 bitów, adresy (podane w bajtach) w 0, 2, 4, 6 itd. będą uważane za wyrównane, a zatem dostępne, podczas gdy adresy 1, 3, 5 i i tak dalej byłyby uważane za niewyrównane. Podobnie, jeśli dostępy wielobajtowe muszą być wyrównane do 32-bitów, adresy 0, 4, 8, 12 itd. będą uważane za wyrównane, a zatem dostępne, a wszystkie adresy pomiędzy nimi będą uważane za niewyrównane. Próba uzyskania dostępu do jednostki większej niż bajt pod niewyrównanym adresem może spowodować błąd magistrali.

Niektóre systemy mogą mieć ich hybrydę, w zależności od używanej architektury. Na przykład w przypadku sprzętu opartego na komputerze IBM System/360 , w tym IBM System z , Fujitsu B8000, RCA Spectra i UNIVAC Series 90 , instrukcje muszą znajdować się na granicy 16-bitowej, to znaczy adresy wykonania muszą zaczynać się od nawet bajt. Próby rozgałęzienia do nieparzystego adresu powodują wyjątek specyfikacji. Dane mogą być jednak pobierane z dowolnego adresu w pamięci i mogą mieć jeden bajt lub więcej, w zależności od instrukcji.

Procesory zwykle uzyskują dostęp do danych na całej szerokości magistrali danych przez cały czas. Aby zaadresować bajty, uzyskują dostęp do pamięci na całej szerokości szyny danych, a następnie maskują i przesuwają, aby zaadresować pojedynczy bajt. Systemy tolerują ten nieefektywny algorytm, ponieważ jest to podstawowa funkcja większości programów, zwłaszcza ciągów znaków . W przeciwieństwie do bajtów, większe jednostki mogą obejmować dwa wyrównane adresy, a zatem wymagałyby więcej niż jednego pobrania na szynie danych. Procesory mogą to obsługiwać, ale ta funkcja rzadko jest wymagana bezpośrednio na kodu maszynowego , dlatego projektanci procesorów zwykle unikają jej implementacji i zamiast tego powodują błędy magistrali w przypadku niewyrównanego dostępu do pamięci.

Błędy stronicowania

FreeBSD , Linux i Solaris mogą sygnalizować błąd magistrali, gdy strony pamięci wirtualnej nie mogą być stronicowane , np. ponieważ pamięć zniknęła (np. dostęp do pliku mapowanego w pamięci lub wykonanie obrazu binarnego , który został obcięty podczas działania programu), [ niewiarygodne źródło? ] lub ponieważ właśnie utworzony plik mapowany w pamięci nie może zostać fizycznie przydzielony, ponieważ dysk jest pełny.

Segment nieobecny (x86)

Na x86 istnieje starszy mechanizm zarządzania pamięcią znany jako segmentacja . Jeśli aplikacja ładuje rejestr segmentu z selektorem nieobecnego segmentu (co w systemach operacyjnych zgodnych z POSIX można zrobić tylko za pomocą języka asemblera ), generowany jest wyjątek. Niektóre systemy operacyjne używały tego do wymiany, ale pod Linuksem generuje to SIGBUS.

Przykład

To jest przykład niewyrównanego dostępu do pamięci, napisany w języku programowania C ze składnią asemblera AT&T .

 

     

     
     
    


    
    

     
    



    
        
    
    
        

    
      

    








    


     0
 #include  <stdlib.h>  int  main  (  int  argc  ,  char  **  argv  )  {  int  *  iptr  ;  char  *  cptr  ;  #if zdefiniowany(__GNUC__)  # if zdefiniowany(__i386__)  /* Włącz sprawdzanie wyrównania na x86 */  __asm__  (  "pushf  \n  orl $0x40000,(%esp)  \n  popf"  );  # elifdefined(__x86_64__)  /* Włącz sprawdzanie wyrównania na x86_64 */  __asm__  (  "pushf  \n  orl $0x40000,(%rsp)  \n  popf"  );  # endif  #endif  /* malloc() zawsze udostępnia pamięć dopasowaną do wszystkich podstawowych typów */  cptr  =  malloc  (  sizeof  (  int  )  +  1  );  /* Zwiększenie wskaźnika o jeden, przez co jest źle wyrównany */  iptr  =  (  int  *  )  ++  cptr  ;  /* Dereferencja jako wskaźnik typu int, powodująca nierówny dostęp */  *  iptr  =  42  ;  /*  Kolejne dostępy spowodują również błąd sigbus.  krótki *sptr;  int ja;  sptr = (krótki *)&i;  // Dla wszystkich nieparzystych przyrostów wartości spowoduje to sigbus.  sptr = (krótki *)(((char *)sptr) + 1);  *sptr = 100;  */  powrót  ;  } 

Kompilowanie i uruchamianie przykładu w systemie operacyjnym zgodnym z POSIX na x86 pokazuje błąd:


 


 

 
  
   $  gcc -ansi sigbus.c -o sigbus  $  ./sigbus  Błąd magistrali  $  gdb ./sigbus  (gdb)  r  Program odebrał sygnał SIGBUS, błąd magistrali.  0x080483ba w głównym ()  (gdb)  x/i $pc  0x80483ba <główny+54>: mov DWORD PTR [eax],0x2a  (gdb)  p/x $eax  $  1  =  0x804a009  (gdb)  p/t $eax & ( sizeof(int) - 1)  $  2  =  1 

Debugger GDB pokazuje, że bezpośrednia wartość 0x2a jest zapisywana w miejscu przechowywanym w rejestrze EAX , przy użyciu asemblera X86 . To jest przykład rejestrowego adresowania pośredniego .

Wydrukowanie bitów niskiego rzędu adresu pokazuje, że nie jest on wyrównany do granicy słowa („dword” przy użyciu terminologii x86).