LOADALL es el nombre común de dos instrucciones de máquina diferentes y no documentadas de los procesadores Intel 80286 e Intel 80386 , que permiten el acceso a áreas del estado interno del procesador que normalmente están fuera del alcance de la API IA-32 , como los registros de caché de descriptores . El LOADALL para los procesadores 286 está codificado como 0Fh 05h, [1] mientras que el LOADALL para los procesadores 386 es 0Fh 07h. [2]
Ambas variantes, como su nombre lo indica, cargan todos los registros internos de la CPU en una sola operación. LOADALL tenía la capacidad única de configurar la parte visible de los registros de segmento (selector) independientemente de su parte en caché correspondiente, lo que permitía al programador llevar la CPU a estados que de otro modo no estarían permitidos por el modelo de programación oficial.
Como ejemplo de la utilidad de estas técnicas, LOADALL puede configurar la CPU para permitir el acceso a toda la memoria desde el modo real , sin tener que cambiarla al modo irreal (lo que requiere cambiar al modo protegido , acceder a la memoria y finalmente volver al modo real). Programas como las versiones pre- XMS de RAMDRIVE.SYS (1985), [3] [1] [4] SMARTDRV.SYS (1986) [4] así como HIMEM.SYS (2.03, 1988-08-04; 2.04, 1988-08-17) [4] controladores en MS-DOS , The Extender (1985) y The Connector (1985) de Uniform Software Systems para Lotus 1-2-3 , Above Disk (1986) [5] (un limitador de Above Software (anteriormente Tele-Ware West también conocido como Los Angeles Securities Group) que convertía el espacio del disco duro o la memoria extendida en memoria expandida ), y OS/2 1.0 [3] [1] y 1.1 [6] usaban la instrucción 286 LOADALL. DOS 3.3 y 4.0 reservaban un búfer de 102 bytes a las 0070:0100h (que normalmente estaba ocupado por datos del BIOS de DOS ) de modo que no había necesidad de guardarlo y restaurarlo para LOADALL. EMM386.EXE de Microsoft hace casos especiales tanto para las instrucciones LOADALL 286 como 386 en su manejador de código de operación no válido . [7] El examen del código de monitor de máquina virtual en Windows/386 2.10 muestra que utiliza tanto la 286 [ cita requerida ] como la variante 386 aún menos conocida [ cita requerida ] . La versión 2.06 de HIMEM.SYS de Microsoft [8] también utilizó LOADALL para copiar rápidamente hacia y desde la memoria extendida en sistemas 286.
Otro uso interesante de LOADALL, expuesto en el libro The Design of OS/2 [ 9], habría sido permitir la ejecución de programas de modo real anteriores en modo protegido de 16 bits, como se utiliza en Concurrent DOS 286 de Digital Research desde 1985 [10] [11] [12], así como en FlexOS 286 [13] y IBM 4680 OS [14] [15] desde 1986. Marcar todos los cachés de descriptores en el GDT y los LDT como "no presentes" permitiría al sistema operativo atrapar recargas de registros de segmento, así como intentos de realizar "aritmética de segmento" específica del modo real y emular el comportamiento deseado actualizando los descriptores de segmento (LOADALL nuevamente). Sin embargo, este " modo de emulación 8086 " para el 80286 era demasiado lento para ser práctico. La idea tuvo que ser descartada en gran parte debido a erratas en algunos procesadores Intel 80286 anteriores a la versión E-2 . [10] [11] [13] Como resultado, OS/2 1.x –y también Windows en modo "estándar"– tuvieron que ejecutar programas DOS en modo real. Sin embargo, la idea no se perdió; llevó a Intel a introducir el modo 8086 virtual del 80386, permitiendo por fin la implementación de " cajas DOS " de una manera relativamente eficiente y documentada.
Debido a que LOADALL no realizó ninguna verificación sobre la validez de los datos cargados en los registros del procesador, fue posible cargar un estado del procesador al que normalmente no se podía ingresar, como usar el modo real (PE=0) junto con la paginación (PG=1) en CPU de clase 386. [2]
Un emulador en circuito (ICE) es una herramienta que se utiliza para la depuración de bajo nivel. En Intel 80386, al activar el pin no documentado en la ubicación B6, el microprocesador detiene la ejecución y entra en modo ICE. El microprocesador guarda todo su estado en un área de memoria aislada de la memoria normal del sistema. La disposición de esta área es adecuada para la instrucción LOADALL, y el código ICE utiliza esta instrucción para volver a la ejecución normal.
En procesadores posteriores, esto evolucionó al modo de administración del sistema (SMM). En SMM, la instrucción RSM se utiliza para cargar un estado completo de la CPU desde un área de memoria. El diseño de esta área de memoria es similar al utilizado por la instrucción LOADALL. [16] La instrucción LOADALL de estilo 386 también se puede ejecutar en 486, pero solo en modo SMM. En procesadores posteriores, la instrucción RSM, con una codificación diferente, asumió su papel.
Codeview 3.0 de Microsoft y Turbo Debugger 2.0 de Borland decodifican correctamente las instrucciones LOADALL 286 y 386. [1]
Como las dos instrucciones LOADALL nunca se documentaron y no existen en procesadores posteriores, los códigos de operación se reutilizaron en la arquitectura AMD64 . [17] El código de operación para la instrucción LOADALL 286, 0F05, se convirtió en la instrucción AMD64 SYSCALL; la instrucción LOADALL 386, 0F07, se convirtió en la instrucción SYSRET. Estas definiciones se implementaron incluso en las CPU Intel con la introducción de la implementación Intel 64 de AMD64. [18]
Código de operación 0F05. La instrucción lee datos de las direcciones 0x00800–0x00866, independientemente del contenido de los registros del segmento.
DIRECCIÓN | Número de bytes | registro | registro | registro | registro |
---|---|---|---|---|---|
00800 | 6 | No utilizado | |||
00806 | 2 | MSW, palabra de estado de la máquina | |||
00808 | 14 | No utilizado | |||
00816 | 2 | TR (registro de tareas) | |||
00818 | 2 | banderas | |||
0081A | 2 | IP (puntero de instrucción) | |||
0081C | 2 | LDTR, registro de tabla de descriptores locales | |||
0081E | 4×2 | DS ( segmento de datos ) | SS (segmento de pila) | CS (segmento de código) | ES (segmento extra) |
00826 | 4×2 | DI (índice de destino) | SI (índice de origen) | BP (puntero base) | SP (puntero de pila) |
0082E | 4×2 | BX | DX | CX | HACHA |
00836 | 4×6 | Descriptor de segmento ES | Descriptor de segmento CS | Descriptor de segmento SS | Descriptor de segmento DS |
0084E | 4×6 | GDT, tabla de descriptores globales | LDT, tabla de descriptores locales | IDT, tabla de descriptores de interrupciones | TSS, segmento de estado de tarea |
La instrucción LOADALL 80286 no se puede utilizar para cambiar del modo protegido al modo real [19] (no puede borrar el bit PE en el MSW). Sin embargo, el uso de la instrucción LOADALL puede evitar la necesidad de cambiar al modo protegido por completo.
Código de operación 0F07. La instrucción carga datos desde la dirección ES:EDI. En realidad, utiliza ES, no el descriptor ES.
DIRECCIÓN | Número de bytes | registro | registro | registro | registro |
---|---|---|---|---|---|
ES:EDI+00 | 4 | CR0, registro de control 0 | |||
ES:EDI+04 | 4 | BANDERAS | |||
ES:EDI+08 | 4 | EIP, puntero de instrucción | |||
ES:EDI+0C | 4×4 | EDI, índice de destino | ESI, índice de fuentes | EBP, puntero base | ESP, puntero de pila |
ES:EDI+1C | 4×4 | EBX | EDX | Extracción electrostática | EAX |
ES:EDI+2C | 2×4 | DR6 | DR7 | ||
ES:EDI+34 | 4 | TR, selector de estado de tarea | |||
ES:EDI+38 | 4 | LDTR, tabla de descriptores locales | |||
ES:EDI+3C | 4×2 | GS, segmento extra | No utilizado | FS, segmento adicional | No utilizado |
ES:EDI+44 | 4×2 | DS, segmento de datos | No utilizado | SS, segmento de pila | No utilizado |
ES:EDI+4C | 4×2 | CS, segmento de código | No utilizado | ES, segmento extra | No utilizado |
ES:EDI+54 | 4×12 | Descriptor TSS, selector de estado de tarea | Descriptor IDT, tabla de descriptores de interrupciones | Descriptor GDT, tabla de descriptores globales | Descriptor LDT, tabla de descriptores locales |
ES:EDI+84 | 4×12 | Descriptor de segmento GS | Descriptor de segmento FS | Descriptor de segmento DS | Descriptor de segmento SS |
ES:EDI+B4 | 2×12 | Descriptor de segmento CS | Descriptor de segmento ES |