По-перше, це не має нічого спільного з оперативною пам’яттю. Тут ми говоримо про адресний простір - навіть якщо у вас є лише 16 МБ пам’яті, у вас 32-розрядний процесор все одно має повних 32 біт адресного простору.
Це вже дає відповідь на ваше перше запитання - на той час, коли це було розроблено, ПК у реальному світі не було ніде майже повним 4 Гб пам'яті; вони були більше в діапазоні 1-16 МіБ пам'яті. Адресний простір для всіх намірів і цілей був вільним.
Тепер, чому саме 0xFFFFFFF0 саме? Процесор не знає, скільки в ньому є BIOS. Деякі BIOS можуть зайняти лише кілька кілобайт, а інші можуть зайняти повні мегабайти пам'яті - і я навіть не потрапляю в різні додаткові оперативні пам'яті. Процесор повинен бути з'єднаний з якоюсь адресою, щоб почати роботу - немає жодної необхідності конфігурувати процесор. Але це лише відображення адресного простору - адреса відображається безпосередньо в мікросхемі BIOS ROM (так, це означає, що в цей момент ви не отримаєте доступ до повних 4 ГБ оперативної пам’яті, якщо у вас так багато - але це не щось особливе, багато пристроїв потребують власного діапазону в адресному просторі). У 32-розрядному процесорі ця адреса дає вам повних 16 байт, щоб зробити саму основну ініціалізацію - що достатньо для настройки ваших сегментів і, якщо потрібно, режиму адреси (пам’ятайте,реальна завантажувальна "процедура". На даний момент ви взагалі не використовуєте оперативну пам’ять - це всього лише відображений ПЗУ. Насправді оперативна пам’ять навіть не готова до використання до цього моменту - це одне із завдань BIOS POST! Тепер ви можете задуматися - як 16-бітний реальний режим отримує доступ до адреси 0xFFFFFFF0? Звичайно, є сегменти, тому у вас є 20-бітний адресний простір, але це все ще недостатньо добре. Ну, в цьому є хитрість - 12 високих бітів адреси встановлюються, поки ви не виконаєте свій перший стрибок у довжину, надаючи вам доступ до простору адрес з високою адресою (відхиляючи доступ до чого-небудь нижчого, ніж 0xFFF00000 - поки не виконаєте стрибок у довжину) .
Все це речі, які в основному приховані від програмістів (не кажучи вже про користувачів) на сучасних операційних системах. Зазвичай у вас немає доступу до чогось такого низького рівня - деякі речі вже виходять з ладу (ви не можете перемикати режими процесора мимоволі), деякі керуються виключно ядром ОС.
Тож приємніший вигляд відбувається із кодування старої школи на MS DOS. Іншим типовим прикладом пам'яті пристрою, безпосередньо нанесеного на адресний простір, є прямий доступ до відеопам'яті. Наприклад, якщо ви хотіли швидко писати текст на дисплей, ви писали безпосередньо на адресу B800:0000
(плюс зміщення - в текстовому режимі 80x25, це означало, (y * 80 + x) * 2
якщо моя пам'ять служить мені правильно - два байти на символ, рядок за рядком). Якщо ви хочете намалювати піксель на піксель, ви використовували графічний режим та адресу старту A000:0000
(як правило, 320x200 при 8 бітах на піксель). Зробити щось високоефективне, як правило, означало зануритися в посібники з пристроїв, щоб з'ясувати, як отримати доступ до них безпосередньо.
Це збережеться до наших днів - це просто приховано. У Windows ви можете побачити адреси пам’яті, відображені на пристроях у диспетчері пристроїв - просто відкрийте властивості чогось типу вашої мережевої карти, перейдіть на вкладку Ресурси - усі елементи діапазону пам’яті - це відображення пам’яті пристрою до основного адресного простору. І на 32-розрядному рівні ви побачите, що більшість цих пристроїв відображаються над позначкою 2 Гб (пізніше 3 ГБ) - знову ж таки, щоб мінімізувати конфлікти з користувацькою пам'яттю, хоча це насправді не проблема з віртуальною пам'яттю ( програми не знаходяться ніде поблизу реального, апаратного адресного простору - у них є власний віртуалізований фрагмент пам’яті, який може бути відображений, наприклад, в оперативній пам’яті, ПЗУ, пристроях або файлі сторінки).
Що стосується стека, ну, це повинно допомогти зрозуміти, що за замовчуванням стек росте зверху. Отже, якщо ви зробите це push
, новий покажчик стека буде на 0xFFFFFEC
- іншими словами, ви не намагаєтеся написати на адресу BIOS init :) Що, звичайно, означає, що підпрограми init для BIOS можуть безпечно використовувати стек, перш ніж перекомпонувати його десь корисніше. У програмах старої школи перед тим, як пейджинг став фактичним за замовчуванням, стек зазвичай починався в кінці оперативної пам’яті, і «переповнення стека» траплялося, коли ви починали перезаписувати пам'ять програми. Захист пам’яті багато цього змінив, але в цілому він максимально підтримує сумісність назад - зверніть увагу, як навіть найсучасніший процесор x86-64 ще може завантажувати MS DOS 5 - або як Windows все ще може запускати багато програм DOS, які не мають уявлення про підкачку.