Sé que el BIOS carga su primera instrucción desde 0xFFFFFFF0, pero ¿por qué esta dirección específica? Tengo un montón de preguntas y espero que me puedan ayudar con algunas de ellas, al menos.
Mis preguntas:
- ¿Por qué la primera instrucción de BIOS se encuentra en la "parte superior" de una RAM de 4 GB?
- ¿Qué pasaría si mi computadora solo tiene 1 GB de RAM?
- ¿Qué pasa con los sistemas con más de 4 GB de RAM (por ejemplo, 8 GB, 16 GB, etc.)?
- ¿Por qué la pila se inicializa con algún valor (en este caso, un valor ubicado en 0xFFFFFFF0)?
He leído sobre eso esta tarde, y todavía no lo entiendo.
Respuestas:
0xFFFFFFF0
es donde una CPU compatible con x86 comienza a ejecutar instrucciones cuando se enciende. Ese es un aspecto cableado e inmutable (sin hardware adicional) de la CPU y los diferentes tipos de CPU se comportan de manera diferente.Está ubicado en la "parte superior" del espacio de direcciones de 4 GB , y al encender el BIOS o la ROM UEFI está configurada para responder a las lecturas de esas direcciones.
Mi teoría sobre por qué esto es:
Casi todo en programación funciona mejor con direcciones contiguas. El diseñador de la CPU no sabe qué querrá hacer un creador de sistemas con la CPU, por lo tanto, es una mala idea que la CPU requiera direcciones justo en el medio del espacio para varios fines. Es mejor mantener eso "fuera del camino" en la parte superior o inferior del espacio de direcciones. Por supuesto, tenga en cuenta que esta decisión se tomó cuando el 8086 era nuevo y no tenía una MMU .
En el 8086, existían vectores de interrupción en la ubicación de memoria 0 y superior. Los vectores de interrupción deben estar en direcciones conocidas y se desea que estén en la RAM para mayor flexibilidad; sin embargo, no fue posible para el diseñador de la CPU saber cuánta RAM habría en un sistema. Entonces, comenzar desde 0 y trabajar tenía sentido para ellos (porque ningún sistema en 1978 cuando se inventó el 8086 tendría 4 Gbytes de RAM, por lo que esperar que la RAM estuviera en 0xFFFFFFF0 no era una buena idea), y luego ROM tendría que ser en el límite superior
Por supuesto, comenzando con al menos el 80286, los vectores de interrupción podrían moverse a una ubicación de inicio diferente a 0, pero las CPU modernas x86 de 64 bits todavía se inician en el modo 8086, por lo que todo funciona a la antigua usanza por compatibilidad (como ridículo como suena en 2015, todavía necesita su CPU x86 para poder ejecutar DOS).
Entonces, dado que los vectores de interrupción comienzan desde 0 y funcionan hacia arriba, la ROM debería comenzar desde arriba y trabajar hacia abajo.
Una CPU de 32 bits tiene 4.294.967.296 direcciones, numeradas del 0 (0x00000000) al 4294967295 (0xFFFFFFFF). La ROM puede vivir en algunas direcciones y la RAM puede vivir en otras. Con la MMU de la CPU, esto incluso se puede cambiar sobre la marcha. La RAM no tiene que vivir en todas las direcciones.
Con solo 1 GB de RAM, algunas direcciones no tendrán nada que responder cuando se leen o escriben. Esto puede hacer que se lean datos no válidos cuando se accede a dichas direcciones o se bloquea el sistema.
Manteniéndolo algo simple: las CPU de 64 bits tienen más direcciones (que es una de las cosas que las hace de 64 bits, por ejemplo, 0x0000000000000000 a 0xFFFFFFFFFFFFFFFF), por lo que la RAM adicional "encaja". Asumiendo que la CPU está en modo largo . Hasta entonces, la RAM está allí, simplemente no es direccionable.
No puedo encontrar nada inmediatamente sobre lo que x86 asigna el puntero de la pila al encenderlo, pero de todos modos, una rutina de inicialización tendrá que reasignarlo una vez que esa rutina descubra cuánta RAM hay en el sistema. (@Eric Towers en los comentarios a continuación informa que está configurado en cero en el encendido).
fuente
0xFFFFFFF0
se puede acceder a la dirección hasta que la CPU se haya cambiado al modo de 32 bits. La última vez que miré de cerca el código del BIOS, el punto de entrada estaba en0xFFFF0
.0xFFFF0
, pero en realidad, se asigna a0xFFFFFFF0
. Espero que esto se haya hecho para la compatibilidad con el 8086: tanto él como las CPU más modernas parecen usar0xFFFF0
, pero las CPU de 32 bits realmente acceden0xFFFFFFF0
(asignadas a la ROM del BIOS).No se encuentra en la parte superior de la RAM; está ubicado en una ROM cuya dirección está en la parte superior del espacio de direcciones de la memoria, junto con cualquier memoria en las tarjetas de expansión, como los controladores Ethernet. Está allí para que no entre en conflicto con la RAM, al menos hasta que tenga instalados 4 GB. Los sistemas que tienen 4 GB o más de RAM pueden hacer dos cosas para resolver el conflicto. Las placas base baratas simplemente ignoran las partes de RAM que entran en conflicto con la ubicación de la ROM. Los decentes reasignan esa RAM para que parezca tener una dirección por encima de la marca de 4 GB.
No estoy seguro de lo que estás preguntando sobre la pila. Ciertamente no está inicializado para estar en ROM. Cuando la CPU se reinicia, inicialmente está en "modo real", donde actúa igual que el 8086 original y utiliza un direccionamiento segmentado de 16 bits, lo que le permite acceder solo a 1 MB de memoria. El código del BIOS se encuentra en la parte superior de ese 1 MB. El BIOS selecciona en algún lugar de la RAM para configurar la pila y carga y ejecuta el primer sector de la primera unidad de arranque. Depende del sistema operativo cambiar al modo de 32 o 64 bits una vez que se haga cargo y configure sus propias pilas (una por tarea / subproceso).
fuente
Primero, esto no tiene nada que ver con RAM, realmente. Estamos hablando del espacio de direcciones aquí, incluso si solo tiene 16 MiB de memoria, todavía tiene los 32 bits completos de espacio de direcciones en una CPU de 32 bits.
Esto ya responde a su primera pregunta, realmente: en el momento en que esto fue diseñado, las PC del mundo real no tenían ni cerca de los 4 GiB de memoria; estaban más en el rango de 1-16 MiB de memoria. El espacio de direcciones era, para todos los efectos, gratuito.
Ahora, ¿por qué 0xFFFFFFF0 exactamente? La CPU no sabe qué cantidad de BIOS hay. Algunas BIOS solo pueden tomar unos pocos kilobytes, mientras que otras pueden tomar megabytes completos de memoria, y ni siquiera estoy entrando en las diversas RAM opcionales. La CPU debe estar conectada a alguna dirección para comenzar, no hay forma de configurar la CPU. Pero esto es solo una asignación del espacio de direcciones: la dirección se asigna directamente al chip ROM del BIOS (sí, esto significa que no tiene acceso a los 4 GiB completos de RAM en este punto si tiene tantos, pero eso no es nada especial, muchos dispositivos requieren su propio rango en el espacio de direcciones). En una CPU de 32 bits, esta dirección le proporciona 16 bytes completos para realizar la inicialización muy básica, que es suficiente para configurar sus segmentos y, si es necesario, el modo de dirección (recuerde,"procedimiento" de arranque real . En este punto, no usa RAM en absoluto; todo es solo ROM asignada. De hecho, la RAM ni siquiera está lista para usarse en este momento, ¡ese es uno de los trabajos de BIOS POST! Ahora, podría estar pensando: ¿cómo accede un modo real de 16 bits a la dirección 0xFFFFFFF0? Claro, hay segmentos, por lo que tiene un espacio de direcciones de 20 bits, pero eso todavía no es lo suficientemente bueno. Bueno, hay un truco: los 12 bits altos de la dirección se configuran hasta que ejecutas tu primer salto largo, dándote acceso al espacio de direcciones altas (mientras rechazas el acceso a cualquier cosa menor que 0xFFF00000, hasta que ejecutes un salto largo) .
Todo esto son las cosas que en su mayoría están ocultas para los programadores (sin mencionar a los usuarios) en los sistemas operativos modernos. Por lo general, no tiene acceso a nada de tan bajo nivel: algunas cosas ya están más allá de la recuperación (no puede cambiar los modos de la CPU de forma involuntaria), algunas son manejadas exclusivamente por el núcleo del sistema operativo.
Entonces, una mejor vista proviene de la codificación de la vieja escuela en MS DOS. Otro ejemplo típico de la memoria del dispositivo que se asigna directamente al espacio de direcciones es el acceso directo a la memoria de video. Por ejemplo, si desea escribir texto en la pantalla rápidamente, escribió directamente a la dirección
B800:0000
(más desplazamiento - en modo de texto 80x25, esto significa que(y * 80 + x) * 2
si mi memoria me sirve bien - dos bytes por carácter, línea por línea). Si deseaba dibujar píxel por píxel, utilizaba un modo gráfico y la dirección de inicioA000:0000
(normalmente, 320x200 a 8 bits por píxel). Hacer cualquier cosa de alto rendimiento generalmente significa sumergirse en los manuales del dispositivo, para descubrir cómo acceder a ellos directamente.Esto sobrevive hasta nuestros días, simplemente está oculto. En Windows, puede ver las direcciones de memoria asignadas a los dispositivos en el Administrador de dispositivos: solo abra las propiedades de algo como su tarjeta de red, vaya a la pestaña Recursos, todos los elementos del Rango de memoria son asignaciones de la memoria del dispositivo a su espacio de direcciones principal. Y en 32 bits, verá que la mayoría de esos dispositivos se asignan por encima de la marca de 2 GiB (más tarde 3 GiB), nuevamente, para minimizar los conflictos con la memoria utilizable por el usuario, aunque esto no es realmente un problema con la memoria virtual ( las aplicaciones no se acercan al espacio real de direcciones de hardware : tienen su propia porción de memoria virtualizada, que podría asignarse a RAM, ROM, dispositivos o al archivo de página, por ejemplo).
En cuanto a la pila, bueno, debería ayudar entender que, de manera predeterminada, la pila crece desde la parte superior. Entonces, si hace una
push
, el nuevo puntero de la pila estará en0xFFFFFEC
, en otras palabras, no está tratando de escribir en la dirección de inicio del BIOS :) Lo que, por supuesto, significa que las rutinas de inicio del BIOS pueden usar la pila de manera segura, antes de reasignarla En algún lugar más útil. En la programación de la vieja escuela, antes de que la paginación se convirtiera en el valor predeterminado de facto, la pila generalmente se iniciaba al final de la RAM y se producía un "desbordamiento de la pila" cuando comenzaba a sobrescribir la memoria de la aplicación. La protección de la memoria cambió mucho de esto, pero en general, mantiene la compatibilidad con versiones anteriores tanto como sea posible; tenga en cuenta que incluso la CPU x86-64 más moderna puede arrancar MS DOS 5 - o cómo Windows aún puede ejecutar muchas aplicaciones de DOS que no tienen idea de la paginación.fuente
0xFFFFFFEC
se asignaría). Esto significa no solo nopush
sino, por ejemplo,call
tampoco. Estos deben esperar hasta que la RAM esté lista.Además de los otros puntos mencionados, puede ser útil para entender lo que una dirección es . Si bien las arquitecturas más nuevas complican las cosas, históricamente una máquina generaría en cada ciclo de memoria la dirección deseada en 20 a 32 cables (dependiendo de la arquitectura, con algunos trucos especiales para observar si necesitaba un par o cuatro bytes simultáneamente); Varias partes del sistema de memoria examinarían el estado de esos cables y se activarían cuando vieran ciertas combinaciones de valores altos y bajos.
Si una máquina con 32 cables de dirección solo necesita usar 1 MB de RAM y 64 KB de ROM [bastante plausible para algunos controladores integrados], podría activar la RAM para todas las direcciones donde el cable de la dirección superior era bajo y la ROM para todas las direcciones donde estaba alto. Los 20 cables de dirección inferiores se vincularían a la RAM para seleccionar uno de 1,048,576 bytes y los 16 inferiores también se conectarían a la ROM, para seleccionar uno de 65,536 bytes. Los restantes 11 cables de dirección simplemente no estarían conectados a nada.
En tal máquina, los accesos a las direcciones 0x00100000-0x001FFFFF serían equivalentes a los accesos a las direcciones RAM 0x00000000-0x000FFFFF. Del mismo modo con las direcciones 0x000200000-0x0002FFFFF o 0x7FF00000-0x7FFFFFFFF. Las direcciones por encima de 0x80000000 leerían ROM, con un patrón de 64K que se repite en todo el espacio.
Aunque el procesador tiene un espacio de direcciones de 4,294,967,296 bytes, no es necesario que el hardware reconozca tantas direcciones distintas. Poner el vector de reinicio cerca de la parte superior del espacio de direcciones es un diseño que funcionará bien independientemente de la cantidad de RAM y ROM que tenga el sistema y evita la necesidad de decodificar completamente el espacio de direcciones.
fuente
Mi teoría es que porque estamos usando lógica negativa, la digital (1) no tiene tensión (O voltios) Solo tenemos que poner tensión en los últimos 4 bits en la inicialización para que el contador del programa (o el puntero de instrucción) se laquee en 1111 1111 1111 1111 1111 1111 1111 0000. No tenemos que direccionar los 28 bits superiores ya que la mayoría de las (antiguas) CPU) eran de 16 bits y los nibbles inferiores se pueden abordar con un solo chip de dirección en los viejos tiempos. Ahora, dado que tenemos 64 bits con compatibilidad de 32 bits y 32 bits a 16 bits, el hardware se ha mejorado, pero el método se mantiene. Además, las biosis no siempre están programadas en 64 o 32 bits. Mi opinión también es que los recuerdos no son siempre los mismos, la BIOS debe ubicarse en el mismo primer segmento. La forma en que vemos el BIOS abordado no es la dirección real todo el tiempo. Sólo un enseñado de mí ...
fuente
al RESTABLECER, una CPU compatible con 8088/8086 ejecuta las instrucciones en 0FFFF0, que es 16 bytes por debajo del límite de 1 megabyte. normalmente la ROM en esta ubicación (en implementaciones de PC) sería el BIOS, por lo que al final de la ROM del BIOS, hay un salto al inicio de la ROM del BIOS.
se muestra aquí: vector de inicio y firma de 'fecha' detrás de él, IBM 5150 PC 8KB eprom dump bios fecha: 19/10/1981
tenga en cuenta que el direccionamiento es de una rom de 8KB $ 2000, que coloca la dirección de inicio (el JMP lejano absoluto, a cualquier otra ubicación, en este caso dentro de la rom de 8KB, aunque no la dirección más baja posible dentro de esa rom) en $ FFFF: $ 0 segmentado o $ FFFF0 lineal.
en cuanto a compatibilidad: si algún procesador 'futuro' o actual 'espera' que tenga muchos más F delante de la dirección, eso no importa. Para la compatibilidad de los cpus más nuevos en los sistemas más antiguos, las líneas de dirección adicionales permanecen desconectadas y, por lo tanto, los datos en el bus de datos son exactamente los mismos. siempre y cuando los bits menos significativos permanezcan FFFF0.
(en un sistema con solo 1mb de ram y la rom colocada al final de ese ram, y nada más, felizmente 'pensará' que está hablando con la dirección más alta pero obtendrá exactamente los mismos datos, porque esas implementaciones nunca han oído hablar de líneas de dirección superiores a A19)
tenga en cuenta que el mundo no es solo 'pcs' ... la pc de ibm fue un 'accidente', estos procesadores nunca fueron diseñados específicamente para 'pcs' y abarcan muchas más cosas que solo pcs (como satélites, sistemas de armas, etc.). El modo protegido de 32 y 64 bits generalmente no se desea. (el modo virtual 8086 es mucho más interesante como una razón para elegir una versión más nueva (386+), por ejemplo). por lo tanto, hay mucho más en 'compatibilidad con versiones anteriores' que simplemente 'ejecutará dos'.
fuente
La placa base asegura que la instrucción en el vector de reinicio sea un salto a la ubicación de memoria asignada al punto de entrada del BIOS. Este salto borra implícitamente la dirección base oculta presente en el encendido. Todas estas ubicaciones de memoria tienen los contenidos correctos que necesita la CPU gracias al mapa de memoria que mantiene el chipset. Todos están asignados a la memoria flash que contiene el BIOS, ya que en este punto los módulos RAM tienen basura aleatoria.
fuente