0xFFFFFFF0
- это то место, где x86-совместимый процессор начинает выполнять инструкции при включении. Это аппаратный, неизменяемый (без дополнительного оборудования) аспект ЦП, и разные типы ЦП ведут себя по-разному.
Почему первая инструкция BIOS находится в верхней части 4 ГБ ОЗУ?
Он расположен в верхней части 4 ГБ адресного пространства - и при включении BIOS или ПЗУ UEFI настроено реагировать на чтение этих адресов.
Моя теория о том, почему это так:
Почти все в программировании лучше работает с непрерывными адресами. Разработчик ЦП не знает, что системный сборщик захочет делать с ЦП, поэтому для ЦП плохая идея требовать, чтобы адреса попали в середину пространства, необходимого для различных целей. Лучше держать это "в стороне" вверху или внизу адресного пространства. Конечно, имейте в виду, что это решение было принято, когда 8086 был новым, у которого не было MMU.
В 8086 году векторы прерывания существовали в ячейке памяти 0 и выше. Векторы прерываний должны располагаться по известным адресам, и было желательно, чтобы они были в оперативной памяти для обеспечения гибкости, однако разработчик ЦП не мог знать, сколько ОЗУ будет в системе. Так что начинать с 0 и работать имело смысл для них (потому что ни одна система в 1978 году, когда был изобретен 8086, не имела бы 4 Гбайт ОЗУ - поэтому ожидать, что ОЗУ будет иметь значение 0xFFFFFFF0, было не очень хорошей идеей), и тогда ПЗУ должно было быть на верхней границе.
Конечно, начиная, по крайней мере, с 80286, векторы прерываний можно было бы переместить в другое начальное местоположение, отличное от 0, но современные 64-битные процессоры x86 по-прежнему загружаются в режиме 8086, поэтому для совместимости все по-прежнему работает по-старому (как это ни смешно) как это звучит в 2015 году, вам все еще нужен ваш процессор x86 для запуска DOS).
Таким образом, поскольку векторы прерываний начинаются с 0 и работают вверх, ПЗУ должно начинаться сверху и работать вниз.
Что произойдет, если на моем компьютере будет только 1 ГБ ОЗУ?
32-разрядный ЦП имеет 4 294 967 296 адресов, пронумерованных от 0 (0x00000000) до 4294967295 (0xFFFFFFFF). ROM может жить по одним адресам, а RAM - по другим. С MMU процессора это можно даже переключать на лету. Оперативная память не должна жить по всем адресам.
При наличии только 1 ГБ ОЗУ некоторые адреса не будут отвечать на запросы при чтении или записи. Это может привести к чтению неверных данных при обращении к таким адресам или к блокировке системы.
А как насчет систем с объемом оперативной памяти более 4 ГБ (например, 8 ГБ, 16 ГБ и т.д.)?
Сохраняя это несколько простым: например, 64-разрядные процессоры имеют больше адресов (что делает их 64-разрядными, например, от 0x0000000000000000 до 0xFFFFFFFFFFFFFFFF), поэтому дополнительная оперативная память "подходит". Предполагая, что процессор находится в длинном режиме. До этого ОЗУ есть, просто не адресуется.
Почему стек инициализируется некоторым значением (в этом случае значением, расположенным в 0xFFFFFFF0)?
Я не могу сразу найти что-то о том, что x86 назначает указатель стека при включении питания, но в любом случае он должен был бы быть переназначен подпрограммой инициализации, как только эта подпрограмма узнает, сколько ОЗУ находится в системе. (@Eric Towers в комментариях ниже сообщает, что при включении питания он равен нулю.)