Los descriptores [1] [2] son una característica arquitectónica de los grandes sistemas de Burroughs , incluidos los sistemas Unisys Clearpath/MCP actuales (a partir de 2024) . Además de estar basados en etiquetas y pilas , una característica arquitectónica notable de estos sistemas es que están basados en descriptores. Los descriptores son el medio para tener datos que no residen en la pila, como matrices y objetos . Los descriptores también se utilizan para datos de cadena como en compiladores y aplicaciones comerciales .
Los descriptores son parte integral del sistema de administración automática de memoria y de la memoria virtual. Los descriptores contienen metadatos sobre bloques de memoria, incluyendo dirección, longitud, tipo de máquina (palabra o byte, para cadenas) y otros metadatos. Los descriptores proporcionan protección esencial de la memoria, seguridad y protección, detectando todos los intentos de acceso fuera de los límites y desbordamiento del búfer. Los descriptores son una forma de sistema de capacidad. [3]
El desarrollo del descriptor fue el método de Burroughs para implementar la gestión, asignación y desasignación de memoria, así como la memoria virtual. En 1958, Robert S. Barton , entonces en Shell Research, sugirió que el almacenamiento principal debería asignarse automáticamente en lugar de que el programador se preocupara por las superposiciones de la memoria secundaria, en efecto, la memoria virtual. [4] : 49 [5] La memoria virtual se desarrolló originalmente para el proyecto Atlas en la Universidad de Manchester a fines de la década de 1950.
En 1960, Barton se había convertido en el arquitecto principal del proyecto Burroughs B5000. De 1959 a 1961, WR Lonergan fue el director del Grupo de Planificación de Productos de Burroughs, que incluía a Barton, a Donald Knuth como consultor y a Paul King. Según Lonergan, en mayo de 1960, la UCLA organizó un seminario de dos semanas titulado "Uso y explotación de ordenadores gigantes" al que asistieron Paul King y otros dos. Stan Gill hizo una presentación sobre la memoria virtual en el ordenador Atlas I. Paul King llevó las ideas a Burroughs y se determinó que la memoria virtual debería incluirse en el núcleo del B5000. [4] : 3 Burroughs Corporation lanzó el B5000 en 1964 como el primer ordenador comercial con memoria virtual. [6]
A mediados de la década de 1960, otros fabricantes, entre ellos RCA y General Electric, desarrollaron máquinas que admitían memoria virtual, con sistemas operativos orientados al tiempo compartido. IBM no admitió memoria virtual en máquinas destinadas al procesamiento general de datos hasta 1972. Sin embargo, otros sistemas no se basan en descriptores y han agregado memoria virtual por encima de la arquitectura básica del procesador.
El descriptor fue una parte esencial del desarrollo del B5000 con gestión automática de memoria y memoria virtual en Burroughs. Si bien los detalles han cambiado desde 1964, la idea del descriptor sigue siendo esencialmente la misma hasta las actuales máquinas Unisys Clearpath MCP (Libra), que son descendientes directos del B5000.
Los descriptores describen áreas de almacenamiento, solicitudes de E/S y resultados de E/S. Contienen campos que indican, por ejemplo, el tipo de descriptor, la dirección, la longitud y si los datos están presentes en el almacenamiento. Los detalles difieren según la línea de productos y el tipo de descriptor. El texto siguiente numera el bit más a la izquierda (el más significativo) como 0, de acuerdo con la documentación de Burroughs.
Los descriptores de programas y datos tienen un bit llamado "bit de presencia" o "bit p" que indica si el objeto al que hace referencia el descriptor se encuentra actualmente en la memoria o en el almacenamiento secundario. Este bit se utiliza para implementar la memoria virtual .
Cuando se hace referencia a un descriptor, el hardware comprueba el bit p. Si es 1, los datos están presentes en la memoria en la ubicación indicada en el campo de dirección. Si el bit p es 0, el bloque de datos no está presente y se genera una interrupción ( interrupción de bit p) y se introduce el código MCP para que el bloque esté presente. En este caso, si el campo de dirección es 0, el bloque de datos no se ha asignado (bit p inicial) y el MCP busca un bloque libre cuyo tamaño se indica en el campo de longitud.
El último escenario de p-bit es cuando el p-bit es 0, lo que indica que los datos no están en la memoria, pero la dirección no es cero, lo que indica que los datos se han asignado y, en este caso, la dirección representa una dirección de disco en el área de memoria virtual del disco. En este caso, se genera una interrupción de p-bit y se anota como "otro" p-bit.
El B5000 [7] fue el primer ordenador basado en descriptores. Cada descriptor tiene un indicador (bit 0) de 1. Los descriptores de datos contienen una dirección de almacenamiento de 15 bits y un tamaño de 10 bits, al igual que la mayoría de los descriptores de E/S. Los descriptores de programa y los descriptores de resultados externos tienen una dirección de 15 bits pero no tienen campo de tamaño.
Los descriptores de programa se utilizan para definir segmentos de programa. Tanto una llamada de operando como una llamada de descriptor que haga referencia a un descriptor de programa provocarán una llamada de subrutina si el bit de presencia es 1. De lo contrario, provocarán una interrupción de presencia.
Los descriptores de datos hacen referencia a un bloque de datos presente en la memoria (P=1) o a un bloque de datos que se debe leer en la memoria (P=0), según el valor del bit de presencia. Tanto una llamada de operando como una llamada de descriptor que hagan referencia a un descriptor de datos comprobarán el bit de presencia y el campo de tamaño; si el bit de presencia es 0, se producirá una interrupción de presencia; si el campo de tamaño no es cero, la segunda palabra de la pila debe estar dentro del rango o se producirá una interrupción de índice.
Un descriptor de resultado externo contiene el descriptor de E/S utilizado para iniciar la operación con algunos campos reemplazados.
Los descriptores describen bloques de datos. Cada descriptor contiene un campo de dirección de 20 bits que hace referencia al bloque de datos. Cada bloque tiene una longitud que se almacena en el descriptor, también de 20 bits. También se indica el tamaño de los datos, que pueden ser de 4, 6, 8 o 48 bits en un campo de tres bits.
La primera computadora con esta arquitectura fue la B6500. En esa implementación, el significado de los distintos bits de estado era:
En implementaciones posteriores, estos bits de estado evolucionaron para mantenerse al día con el aumento del tamaño de la memoria y los conocimientos adquiridos con el tiempo.
En ALGOL , los límites de una matriz son completamente dinámicos, se pueden tomar de valores calculados en tiempo de ejecución, a diferencia de Pascal , que vino después, basado en ALGOL, donde el tamaño de las matrices se fija en tiempo de compilación. Esta es la principal debilidad de Pascal tal como se define en su estándar, pero que se ha eliminado en muchas implementaciones comerciales de Pascal, en particular las implementaciones de Burroughs (tanto la versión de la Universidad de Tasmania de Arthur Sale y Roy Freak, como la implementación posterior en el sistema Burroughs Slice Compiler de Matt Miller et al.).
En un programa en el entorno MCP de Burroughs/Unisys, una matriz no se asigna cuando se declara, sino solo cuando se la utiliza por primera vez en tiempo de ejecución; de esta manera, se pueden declarar matrices y se evita la sobrecarga que supone asignarlas si no se utilizan. De esta forma, la gestión de memoria es completamente dinámica.
Además, no se necesitan llamadas al sistema de asignación de memoria de bajo nivel, como la clase de llamadas malloc de C y Unix : las matrices se asignan automáticamente a medida que se utilizan. Esto le ahorra al programador la gran carga de llenar los programas con la actividad propensa a errores de la gestión de memoria, que es crucial en las aplicaciones de mainframe .
Al portar programas en lenguajes de nivel inferior como C, la estructura de memoria de C se maneja haciendo su propia asignación de memoria dentro de un gran bloque asignado – por lo tanto la seguridad del resto del sistema no puede ser comprometida por desbordamientos de buffer por parte de programas C erróneos. De hecho, muchos desbordamientos de buffer en programas C aparentemente de otra manera funcionando correctamente han sido detectados cuando se portaron a la arquitectura MCP de Unisys. [8] C, como Pascal, también se implementa usando el sistema de compilación Slice, que usa un generador de código común y optimizador para todos los lenguajes. El compilador de C, el sistema de tiempo de ejecución, las interfaces POSIX , así como un puerto de muchas herramientas Unix fueron hechos por Steve Bartels. Un compilador Eiffel también fue desarrollado usando Slice.
En el caso de los programas orientados a objetos que requieren una creación de objetos más dinámica que la arquitectura MCP, es mejor asignar los objetos dentro de un único bloque. Esta asignación de objetos es de un nivel superior al de malloc de C y se implementa mejor con un recolector de basura moderno y eficiente .
El campo de dirección en los modelos B5000, B5500 y B5700 es de tan solo 15 bits, lo que significa que los descriptores solo pueden direccionar 32 000 palabras (192 KB) de memoria. El campo de dirección en el B6500 es de 20 bits o 1 megapalabras (6 MB). A mediados de los años setenta, esto todavía suponía una importante restricción de la arquitectura. Para superarlo, se implementaron dos soluciones:
No fue necesario modificar el código del programa para utilizar estas funciones. Ambas soluciones pueden incluso combinarse, pero con el tiempo los requisitos de memoria del MCP y los requisitos de uso compartido de datos del programa superaron el tamaño máximo de los espacios de direcciones.
Con la llegada de la Serie A a principios de los años 80, el significado de este campo cambió para incluir la dirección de un descriptor maestro, lo que significa que se pueden asignar bloques de datos de 1 megabyte, pero que la memoria de la máquina se puede ampliar en gran medida a gigabytes o quizás terabytes. Esta arquitectura se denominó memoria ASD (Advanced Segment Descriptors). Esto requirió una nueva especificación de microcódigo común, conocida como Beta. El principal visionario detrás de la memoria ASD es John McClintock. Más tarde, la etiqueta de memoria de 3 bits se aumentó a una especificación de 4 bits, lo que permitió que el descriptor de segmento creciera de 20 a 23 bits de tamaño, lo que permite direccionar incluso más memoria simultáneamente. Esta especificación de microcódigo se conoció como nivel Gamma.
Otra ventaja significativa se logró con la memoria virtual . En el diseño B5000, si se desplegaba un bloque de datos, era necesario encontrar todos los descriptores que hacían referencia a ese bloque para actualizar el bit de presencia y la dirección. Con el descriptor maestro, solo es necesario cambiar el bit de presencia en el descriptor maestro. Además, el MCP puede mover bloques en la memoria para compactación y solo necesita cambiar la dirección en el descriptor maestro.
Una diferencia entre el B5000 y la mayoría de los demás sistemas es que estos últimos utilizan principalmente memoria virtual paginada, es decir, las páginas se intercambian en fragmentos de tamaño fijo independientemente de la estructura de la información que contienen. La memoria virtual del B5000 funciona con segmentos de tamaño variable , como se describe en los descriptores.
Cuando la memoria se llena hasta una determinada capacidad, se invoca un proceso del sistema operativo denominado "Working Set Sheriff" para compactar la memoria o comenzar a sacar segmentos de la memoria. Primero elige los segmentos de código, ya que no pueden cambiar y se pueden volver a cargar desde el original en el archivo de código, por lo que no es necesario escribirlos, y luego los segmentos de datos que se escriben en el archivo de memoria virtual.
Las interrupciones de bit p [9] también son útiles para medir el rendimiento del sistema. Para asignaciones que se realizan por primera vez, los "bits p de inicio" indican un problema de rendimiento potencial en un programa, por ejemplo, si se llama continuamente a un procedimiento que asigna una matriz. Recargar bloques desde la memoria virtual en el disco puede degradar significativamente el rendimiento del sistema y no es culpa de ninguna tarea específica. Es por eso que muchas de las computadoras actuales pueden obtener un mayor rendimiento del sistema al agregar memoria. En las máquinas B5000, los "otros bits p" indican un problema del sistema, que se puede resolver ya sea equilibrando mejor la carga de procesamiento a lo largo del día o agregando más memoria.
De esta forma, la arquitectura de grandes sistemas de Burroughs facilita la optimización tanto de las tareas individuales como del sistema en su conjunto.
El último punto, y quizás el más importante, que hay que tener en cuenta sobre los descriptores es cómo afectan a las nociones complementarias de seguridad del sistema y corrección del programa. Una de las mejores herramientas que tiene un hacker para comprometer los sistemas operativos actuales es el desbordamiento del búfer. C, en particular, utiliza la forma más primitiva y propensa a errores de marcar el final de las cadenas, utilizando un byte nulo como centinela de fin de cadena en el propio flujo de datos.
Los punteros se implementan en los sistemas MCP de Unisys mediante descriptores indexados. Durante las operaciones de indexación, los punteros se comprueban en cada incremento para asegurarse de que ni los bloques de origen ni los de destino estén fuera de los límites. Durante una operación de escaneo o reemplazo, los mecanismos utilizados para leer o copiar grandes bloques de memoria, tanto de origen como de destino, se comprueban en cada incremento de palabra para detectar una etiqueta de memoria válida. Cada segmento de memoria está limitado por una etiqueta de 3 palabras, lo que haría que dicha operación fallara. Cada segmento de memoria que contiene datos sensibles a la integridad, como el código del programa, se almacena en una etiqueta de 3 palabras, lo que hace imposible una lectura no controlada, y mucho menos una modificación. De este modo, se puede detectar una fuente significativa de errores de programa antes de que el software entre en producción, y no es posible una clase más significativa de ataques a la seguridad del sistema.