Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

Най-четени

Даниел Десподов
Даниел Десподов
Новинар. Увличам се от съвременни технологии, информационна безопасност, спорт, наука и изкуствен интелект.

Оригиналът е на mjg59

Централните процесори (CPU) не могат нищо да започнат да правят, ако не им се каже какво да правят. Очевидният проблем е как да изобщо да накараме централния процесор да започне да прави каквото и да било. Мнозина централни процесори решават този проблем, като използват вектор за нулиране – твърдо записан в CPU адрес, от който да започнат да се четат командите, когато бъде подадено захранването. Адресът, към който сочи векторът за нулиране, обикновено е някаква ROM или флаш памет, която процесорът може да прочете, дори ако все още не е конфигуриран никакъв друг хардуер. Това позволява на производителя на системата да създаде код, който ще се изпълни веднага след включване на захранването, ще конфигурира целия друг хардуер и постепенно ще приведе системата в състояние, в което тя може да изпълнява потребителския код.

Конкретната реализация на вектора за нулиране в x86 системите се е променяла с времето, но по същество той винаги е бил 16 байта под горната част на адресното пространство, т.е. 0xffff0 при 20-битовия 8086, 0xfffff0 при 24-битовия 80286 и 0xfffffff0 при 32-битовия 80386. Стандартно в x86 системите оперативната памет започва от адрес 0, така че горната част на адресното пространство може да се използва за разполагане на вектора за нулиране с минимален шанс за конфликт с оперативната памет.

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Най-забележителното за x86 тук обаче е, че когато започне да изпълнява кода от вектора за нулиране, той е в реален режим. Реалният режим на x86 е остатък от една много по-ранна компютърна епоха. Адресите не са абсолютни (т.е. когато осъществявате достъп до 32-битов адрес, съхранявате целия адрес в 32-битов регистър или в регистър с по-голям размер), те са 16-битови отмествания, добавени към стойността, съхранена в „сегментен регистър“.

Кодът, данните и стекът имат свои собствени сегментни регистри, така че един 16-битов адрес може да се отнася до различни реални адреси в зависимост от това как се интерпретира: преминаването към 16-битов адрес ще доведе до добавянето на този адрес към сегментния регистър на кода, четенето от 16-битов адрес ще доведе до добавянето на този адрес към сегментния регистър на данните и т.н. Всичко това е направено с цел да се запази съвместимостта с по-старите чипове, и то чак дотам, че дори 64-битовият x86 процесор работи в real mode (реален режим) със сегментите и всичко останало (и също така започва първоначалното изпълнение на командите на адрес 0xfffffff0вместо на 0xfffffffffffffff0 – 64-битовият режим не поддържа real mode, така че 64-битовият физически адрес няма  как да бъде зададен с помощта на сегментни регистри и всичко все още започва на адреса точно под 4-те GB, въпреки че е налично много по-голямо адресно пространство).

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Хайде, нали всички знаят това. В съвременните системи UEFI фърмуерът, стартиран от вектора за нулиране, препрограмира процесора в подходящ режим (т.е. без всички тези неща със сегментирането) и прави най-различни неща, като например конфигуриране контролера на паметта, така че да може да се получи достъп до оперативната памет (този процес използва кеша на процесора като оперативна памет, тъй като програмирането на контролера на паметта е доста сложно, защото трябва да се съхранява повече информация за състоянието, отколкото ще се побере в регистрите, тоест необходима е оперативна памет, но ние нямаме оперативна памет, докато не заработи контролерът на паметта; за щастие, процесорът има много собствени мегабайти памет, така че може спокойно да си поемем дъх). Това е доста криво, но такива са последствията от лесните и добре разбираеми наследени (legacy) решения.

Това обаче не е точно така. Съвременният Intel x86 процесор работи по по-различен начин. Всичко е много по-странно и сложно. Да, на пръв поглед изглежда, че процесорът прави точно това, но зад кулисите се случват и много други неща. Нека да поговорим за сигурността на стартирането. Принципът на всеки вид верифицирано стартиране (като UEFI Secure Boot) е, че сигнатурата на следващия модул във веригата на стартиране се валидира, преди модулът да бъде изпълнен. Но кой или какво проверява първия компонент във веригата? Не можете просто да поискате от BIOS сам да се провери – ако нападателят може да замени BIOS, неговата версия на BIOS просто ще излъже, че е направила всичко това. Intel е решила този проблем със системата Boot Guard.

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Но преди да пристъпим към Boot Guard, трябва да се уверим, че процесорът работи възможно най-безпроблемно и без бъгове. Ето защо, когато процесорът се стартира, той преглежда системната флаш памет и търси заглавие на блок, показващ, че микрокодът на процесора е бил актуализиран. Процесорът на Intel има вграден микрокод, но той често е стар и с грешки, така че системният фърмуер може да реши да включи копие, което е достатъчно ново, за да работи надеждно. Образът на микрокода се копира от флаш паметта, сигнатурата се проверява и новият микрокод започва да работи. Това е вярно както при използване на Boot Guard, така и без него.

При Boot Guard обаче микрокодът в процесора прочита модула за удостоверен код (ACM) от флаш паметта и проверява неговата сигнатура спрямо записания от Intel ключ, преди да премине към вектора за нулиране. Ако те съвпадат, той започва да изпълнява ACM. Тук трябва да се има предвид, че процесорът не може просто да провери ACM и след това да го изпълни директно от флаш паметта: ако го направи, флаш паметта може да го разпознае, да подаде удостоверения ACM за проверка и след това да подаде други инструкции на процесора, когато той ги прочете отново за изпълнение (това е добре познатата в наши дни уязвимост Time of Check vs Time of Use или TOCTOU). Това означава, че ACM трябва да бъде копиран в процесора, преди да може да бъде проверен и изпълнен, което означава, че се нуждаем от RAM, което пък означава, че процесорът вече трябва да знае как да конфигурира кеша си, за да може да го използва като RAM.

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Както и да е. Вече изтеглихме и проверихме ACM, след което той може да бъде спокойно изпълнен. ACM прави различни неща, но най-важното от гледна точка на Boot Guard е, че чете набор от защитни блокове с еднократен запис в чипсета на дънната платка, представляващи публичния ключ SHA256. След това той прочита първия блок на фърмуера (Initial Boot Block, или IBB) в оперативната памет (по-точно, както беше споменато по-горе, в кеша на процесора) и го анализира. В него има блок, съдържащ публичен ключ – той хешира този ключ и проверява дали той съвпада с SHA256 на защитните блокове. След това използва този ключ, за да потвърди подписа на IBB. Ако всичко е правилно, той изпълнява IBB и всичко започва да прилича на красивия опростен модел, за който говорихме по-горе.

Само че, не ви ли се струва, че целият този код е изключително труден за изпълнение в реален режим? И да, извършването на всички тези изчисления на съвременната криптография само с 16-битови регистри би било много мъчителна задача. Ето защо това не се прави по този начин. Всичко това се случва в напълно логичния и разумен 32-битов режим, а след това процесорът всъщност превключва на една ужасна конфигурация, за да запази съвместимостта с 80386, излязъл през 1986 г. „Добрата“ новина е, че поне фърмуерът може да открие, че процесорът вече е конфигурирал кеша като оперативна памет и може да не прави това самостоятелно.

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Тук прескачам няколко стъпки – ACM всъщност изпълнява и други задачи: проверява фърмуера в TPM и конфигурира TXT за тези, които се нуждаят от DRTM, но накратко, процесорът се привежда в състояние, в което работи като модерен процесор, и след това умишлено отново се деактивират куп полезни функции, преди да започне изпълнението на фърмуера. Пропускам и факта, че целият този процес започва едва след като Management Engine го разреши, което означава, че чакаме напълно независимият x86 да стартира цялата операционна система, преди процесорът поне да започне да се преструва, че изпълнява системния фърмуер.

Разбира се, както бе споменато по-горе, в съвременните системи фърмуерът ще препрограмира процесора в нещо по-смислено, така че разработчиците на операционни системи вече не трябва да се притесняват за това. Това означава, че сме прескачали между няколко състояния само заради вероятността някой да иска да стартира legacy – много стар BIOS и след това да зареди DOS на процесор, който има пет порядъка повече транзистори от 8086.

Ето как се осъществява първоначалното стартиране при съвременните процесори на Intel

 

Големият ми въпрос е защо моят съвременен х86 процесор не може да се събуди директно във вградения в него защитен режим (protected mode)? Само на мен ли ми омръзнаха тези тлъсти legacy програмни слоеве?

Допълнения

  • Само с ACPI ще пропуснем по-голямата част от кода за конфигуриране на фърмуера, така че трябва да стартираме процесора в 16-битов режим, защото suspend/resume  – тоест, спирането/възстановяването по същество е един изключително дълъг цикъл на рестартиране
  • А, да, и защото е твърде вероятно процесорът ви да има няколко ядра: лошата новина за това състояние е, че повечето ядра не се стартират от фърмуера при стартирането на операционната система, така че те ще бъдат в 16-битов реален режим, дори ако работещият процесор вече е в 64-битов защитен режим; малко по-различна кошмарна ситуация възниква, ако сте използвали TXT. По-точно, такъв беше случаят и преди, но ACPI 6.4 (издаден през 2021 г.) има механизъм, който дава възможност на операционната система да поиска от фърмуера да събуди процесора, така че той да е невидим за нея, но в този случай фърмуерът така или иначе пак ще трябва да изпълнява много сложни задачи

Да си припомним, че процесорът Intel 8088 излезе през далечната 1979 година и това е чипът включил компанията в престижния рейтинг топ Fortune 500. Процесорът Intel 8088 е чипът, който IBM избра за своята продуктова гама PC, което доведе до доминирането на 8088 на пазара. По ирония на съдбата, чипът който стана прародителят на х86 архитектурата, не завършва на „86“. Процесорът 8088 бе просто леко модифициран 8086 и първият 16-битов процесор на Intel. 

Но оттогава измина твърде много време и е може би вече трябва да се откажем от наследените от това далечно минало похвати и методи.

АбонаментВсичко важно от света на технологиите, директно в пощата ти.

С абонирането приемате нашите Условия и Политика за поверителност. Може да се отпишете с един клик по всяко време.


Коментирайте статията в нашите Форуми. За да научите първи най-важното, харесайте страницата ни във Facebook, и ни последвайте в Google Новини, TikTok, Telegram и Viber или изтеглете приложението на Kaldata.com за Android, iPhone, Huawei, Google Chrome, Microsoft Edge и Opera!

2 Коментара
стари
нови оценка

Нови ревюта

Подобни новини