En informática , un error de bus es un fallo generado por el hardware que notifica al sistema operativo que un proceso está intentando acceder a una memoria a la que la CPU no puede acceder físicamente: una dirección no válida para el bus de direcciones , de ahí su nombre. En la mayoría de las arquitecturas modernas, estos errores son mucho menos frecuentes que los fallos de segmentación , que se producen principalmente por infracciones de acceso a la memoria: problemas en la dirección lógica o en los permisos.
En plataformas compatibles con POSIX , los errores de bus suelen provocar que se envíe la señal SIGBUS al proceso que causó el error. La señal SIGBUS también puede deberse a cualquier fallo general del dispositivo que detecte el ordenador, aunque un error de bus rara vez significa que el hardware del ordenador esté físicamente averiado; normalmente se debe a un error de software . Los errores de bus también pueden producirse por otros errores de paginación; véase más abajo.
Causas
Existen al menos tres causas principales de errores en el autobús:
Dirección inexistente
El software ordena a la CPU que lea o escriba en una dirección de memoria física específica . En consecuencia, la CPU establece esta dirección física en su bus de direcciones y solicita a todo el hardware conectado a ella que responda con los resultados, si responden para esta dirección específica. Si ningún otro hardware responde, la CPU genera una excepción , indicando que la dirección física solicitada no es reconocida por todo el sistema informático. Cabe destacar que esto solo se aplica a las direcciones de memoria física . Intentar acceder a una dirección de memoria virtual no definida generalmente se considera un fallo de segmentación en lugar de un error de bus, aunque si la MMU es independiente, el procesador no puede distinguir la diferencia.
Acceso no alineado
La mayoría de las CPU son direccionables por bytes , donde cada dirección de memoria única se refiere a un byte de 8 bits . La mayoría de las CPU pueden acceder a bytes individuales desde cada dirección de memoria, pero generalmente no pueden acceder a unidades más grandes (16 bits, 32 bits, 64 bits, etc.) sin que estas unidades estén " alineadas " a un límite específico (la plataforma x86 es una excepción notable).
Por ejemplo, si los accesos a varios bytes deben estar alineados a 16 bits, las direcciones (expresadas en bytes) en 0, 2, 4, 6, etc., se considerarían alineadas y, por lo tanto, accesibles, mientras que las direcciones 1, 3, 5, etc., se considerarían no alineadas. De manera similar, si los accesos a varios bytes deben estar alineados a 32 bits, las direcciones 0, 4, 8, 12, etc., se considerarían alineadas y, por lo tanto, accesibles, y todas las direcciones intermedias se considerarían no alineadas. Intentar acceder a una unidad mayor que un byte en una dirección no alineada puede provocar un error de bus.
Algunos sistemas pueden tener una combinación de estos dependiendo de la arquitectura que se utilice. Por ejemplo, para el hardware basado en el mainframe IBM System/360 , incluidos IBM System z , Fujitsu B8000, RCA Spectra y UNIVAC Series 90 , las instrucciones deben estar en un límite de 16 bits, es decir, las direcciones de ejecución deben comenzar en un byte par. Los intentos de saltar a una dirección impar dan como resultado una excepción de especificación. [ 1 ] Sin embargo, los datos pueden recuperarse de cualquier dirección en la memoria y pueden ser de un byte o más, dependiendo de la instrucción.
Generalmente, las CPU acceden a los datos ocupando todo el ancho de su bus de datos en todo momento. Para direccionar bytes, acceden a la memoria ocupando todo el ancho de su bus de datos, luego aplican máscaras y desplazamientos para direccionar el byte individual. Los sistemas toleran este algoritmo ineficiente, ya que es una característica esencial para la mayoría del software, especialmente para el procesamiento de cadenas . A diferencia de los bytes, las unidades más grandes pueden abarcar dos direcciones alineadas y, por lo tanto, requerirían más de una lectura en el bus de datos. Si bien es posible que las CPU admitan esto, esta funcionalidad rara vez se requiere directamente a nivel de código máquina , por lo que los diseñadores de CPU normalmente evitan implementarla y, en su lugar, generan errores de bus para el acceso a memoria no alineada.
Errores de paginación
FreeBSD , Linux y Solaris pueden señalar un error de bus cuando no se pueden paginar páginas de memoria virtual , por ejemplo, porque ha desaparecido (por ejemplo, al acceder a un archivo mapeado en memoria o al ejecutar una imagen binaria que se ha truncado mientras se ejecutaba el programa), [ 2 ] o porque no se puede asignar físicamente un archivo mapeado en memoria recién creado , porque el disco está lleno.
Segmento no presente (x86)
En la arquitectura x86 existe un mecanismo de gestión de memoria antiguo conocido como segmentación . Si la aplicación carga un registro de segmento con el selector de un segmento inexistente (lo cual, en sistemas operativos compatibles con POSIX, solo se puede hacer con lenguaje ensamblador ), se genera una excepción. Algunos sistemas operativos lo utilizaban para el intercambio de memoria, pero en Linux esto genera una señal SIGBUS.
Ejemplo
Este es un ejemplo de acceso a memoria no alineada, escrito en el lenguaje de programación C con sintaxis de ensamblador de AT&T .
#include <stdlib.h>int main ( int argc , char ** argv ) { int * iptr ; char * cptr ; #if defined(__GNUC__) # if defined(__i386__) /* Habilitar la comprobación de alineación en x86 */ __asm__ ( "pushf \n orl $0x40000,(%esp) \n popf" ); # elif defined(__x86_64__) /* Habilitar la comprobación de alineación en x86_64 */ __asm__ ( "pushf \n orl $0x40000,(%rsp) \n popf" ); # endif #endif/* malloc() siempre proporciona memoria alineada para todos los tipos fundamentales */ cptr = malloc ( sizeof ( int ) + 1 ); /* Incrementa el puntero en uno, desalineándolo */ iptr = ( int * ) ++ cptr ;/* Desreferenciarlo como un puntero int, lo que provoca un acceso no alineado */ * iptr = 42 ;/* Los siguientes accesos también darán como resultado un error de sigbus. short *sptr; int i; sptr = (short *)&i; // Para todos los incrementos de valor impares, dará como resultado sigbus. sptr = (short *)(((char *)sptr) + 1); *sptr = 100; */devolver 0 ; }Compilar y ejecutar el ejemplo en un sistema operativo compatible con POSIX en x86 demuestra el error:
$ gcc -ansi sigbus.c -o sigbus $ ./sigbus Error de bus $ gdb ./sigbus (gdb) r El programa recibió la señal SIGBUS, error de bus. 0x080483ba en 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 = 1El depurador GDB muestra que el valor inmediato 0x2a se almacena en la ubicación del registro EAX , utilizando lenguaje ensamblador X86 . Este es un ejemplo de direccionamiento indirecto de registros .
Al imprimir los bits de orden inferior de la dirección, se observa que no está alineada con un límite de palabra ("dword" según la terminología x86).
Referencias
- ↑ z/Architecture Principles of Operation , SA22-7832-04, Página 6-6, Quinta edición (septiembre de 2005) IBM Corporation, Poukeepsie, NY, Disponible en http://publibfp.dhe.ibm.com/epubs/pdf/a2278324.pdf Archivado el 22 de mayo de 2022 en Wayback Machine (Consultado el 31 de diciembre de 2015)
- ↑ "¿Qué es SIGBUS - Error de hardware específico del objeto?" .
- Gestión de la memoria
- Errores informáticos
- buses informáticos