Ошибка шины - Bus error

В вычислении , А ошибка шины является неисправность поднят с помощью аппаратных средств, уведомляя об операционной системе (ОС) , что процесс пытается получить доступ к памяти , что процессор не может физически адрес: недопустимый адрес для адресной шины , отсюда и название. При современном использовании на большинстве архитектур они гораздо реже, чем ошибки сегментации , которые возникают в основном из-за нарушений доступа к памяти: проблем с логическим адресом или разрешениями.

На платформах, совместимых с POSIX , ошибки шины обычно приводят к отправке сигнала SIGBUS процессу, вызвавшему ошибку. SIGBUS также может быть вызван любой общей ошибкой устройства, которую обнаруживает компьютер, хотя ошибка шины редко означает, что компьютерное оборудование физически сломано - обычно это вызвано ошибкой в программном обеспечении . Ошибки шины могут также возникать для некоторых других ошибок пейджинга; увидеть ниже.

Причины

Есть как минимум три основных причины ошибок шины:

Несуществующий адрес

Программное обеспечение инструктирует ЦП читать или записывать определенный адрес физической памяти . Соответственно, ЦП устанавливает этот физический адрес на своей адресной шине и запрашивает все остальное оборудование, подключенное к ЦП, для ответа с результатами, если они отвечают на этот конкретный адрес. Если никакое другое оборудование не отвечает, ЦП вызывает исключение , заявляя, что запрошенный физический адрес не распознается всей компьютерной системой. Обратите внимание, что это касается только адресов физической памяти. Попытка получить доступ к неопределенному адресу виртуальной памяти обычно считается ошибкой сегментации, а не ошибкой шины, хотя, если MMU является отдельным, процессор не может заметить разницу.

Невыровненный доступ

Большинство процессоров имеют байтовую адресацию , где каждый уникальный адрес памяти относится к 8-битному байту . Большинство процессоров могут получить доступ к отдельным байтам из каждого адреса памяти, но обычно они не могут получить доступ к более крупным блокам (16 бит, 32 бита, 64 бита и т. Д.) Без того, чтобы эти блоки были " выровнены " по определенной границе ( платформа x86 является заметным исключением. ).

Например, если многобайтовый доступ должен быть выровнен по 16 битам, адреса (в байтах) 0, 2, 4, 6 и т. Д. Будут считаться выровненными и, следовательно, доступными, в то время как адреса 1, 3, 5 и так далее будет считаться невыровненным. Точно так же, если многобайтовый доступ должен быть выровнен по 32 бита, адреса 0, 4, 8, 12 и так далее будут считаться выровненными и, следовательно, доступными, а все адреса между ними будут считаться невыровненными. Попытка получить доступ к блоку размером больше байта по невыровненному адресу может вызвать ошибку шины.

Некоторые системы могут иметь их гибрид в зависимости от используемой архитектуры. Например, для оборудования на основе мэйнфрейма IBM System / 360 , включая IBM System z , Fujitsu B8000, RCA Spectra и UNIVAC Series 90 , инструкции должны находиться на 16-битной границе, то есть адреса выполнения должны начинаться с даже байт. Попытки перейти на нечетный адрес приводят к исключению спецификации. Однако данные могут быть получены с любого адреса в памяти и могут быть одним байтом или больше в зависимости от инструкции.

Обычно процессоры всегда обращаются к данным по всей ширине шины данных . Для адресации байтов они обращаются к памяти по всей ширине своей шины данных, затем маскируют и сдвигают для адресации отдельного байта. Системы терпимо относятся к этому неэффективному алгоритму, поскольку это важная функция для большинства программ, особенно для обработки строк . В отличие от байтов, блоки большего размера могут охватывать два выровненных адреса и, таким образом, потребуют более одной выборки по шине данных. ЦП может поддерживать это, но эта функция редко требуется непосредственно на уровне машинного кода , поэтому разработчики ЦП обычно избегают ее реализации и вместо этого выдают ошибки шины для доступа к невыровненной памяти.

Ошибки подкачки

FreeBSD , Linux и Solaris могут сигнализировать об ошибке шины, когда страницы виртуальной памяти не могут быть выгружены , например, потому что она исчезла (например, доступ к файлу с отображением памяти или выполнение двоичного образа, который был усечен во время работы программы), или потому что только что созданный файл с отображением памяти не может быть физически выделен, потому что диск заполнен.

Отсутствующий сегмент (x86)

На x86 существует более старый механизм управления памятью, известный как сегментация . Если приложение загружает регистр сегмента с помощью селектора отсутствующего сегмента (что в POSIX-совместимых операционных системах может быть выполнено только на языке ассемблера ), генерируется исключение. Некоторые операционные системы использовали это для свопинга, но в Linux это генерирует SIGBUS.

пример

Это пример невыровненного доступа к памяти, написанный на языке программирования C с синтаксисом ассемблера AT&T .

#include <stdlib.h>

int main(int argc, char **argv) 
{
    int *iptr;
    char *cptr;
    
#if defined(__GNUC__)
# if defined(__i386__)
    /* Enable Alignment Checking on x86 */
    __asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__) 
     /* Enable Alignment Checking on x86_64 */
    __asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

    /* malloc() always provides memory which is aligned for all fundamental types */
    cptr = malloc(sizeof(int) + 1);
    
    /* Increment the pointer by one, making it misaligned */
    iptr = (int *) ++cptr;

    /* Dereference it as an int pointer, causing an unaligned access */
    *iptr = 42;

    /*
       Following accesses will also result in sigbus error.
       short *sptr;
       int    i;

       sptr = (short *)&i;
       // For all odd value increments, it will result in sigbus.
       sptr = (short *)(((char *)sptr) + 1);
       *sptr = 100;
    
    */

    return 0;
}

Компиляция и запуск примера в POSIX- совместимой ОС на x86 демонстрирует ошибку:

$ gcc -ansi sigbus.c -o sigbus
$ ./sigbus 
Bus error
$ gdb ./sigbus
(gdb) r
Program received signal SIGBUS, Bus error.
0x080483ba in main ()
(gdb) x/i $pc
0x80483ba <main+54>:    mov    DWORD PTR [eax],0x2a
(gdb) p/x $eax
$1 = 0x804a009
(gdb) p/t $eax & (sizeof(int) - 1)
$2 = 1

В GDB отладчик показывает , что непосредственное значение 0x2a в настоящее время хранятся в местоположении , хранящейся в EAX регистр , используя X86 язык ассемблера . Это пример косвенной адресации регистров .

Печать младших битов адреса показывает, что он не выровнен по границе слова («двойное слово» в терминологии x86).

Ссылки