четвер, 4 серпня 2016 р.

Не дуже категоризоване - про сосну і PI.

Цей допис не про Core Uefi, а так, дещо типу щоденникового запису в цю історію. По-перше, нарешті до мене вчора приїала сосна64+, а по-друге - трохи хотів записати за ту частину, яку я для себе коротко називаю "стартовий код", тобто та частина, з якої власне починається робота системи, яку можна реально намагатися запускати на голому залізі, bitches! xD
Про сосну. Замовив я її ще в квітні, але в чуваків виникла явна запарка з бізнесом - вони явно не впорувались з напливом охочих спробувати їхню плату. Довелось трохи почекати. Трохи менше двох тижнів тому, прийшло сповіщення на е-пошту, шо нарешті, плата їхатиме. Ну і менше як за два тижні вона прихала. :) Я купив лише плату і USB дріт для живлення - на шось ще, грошей не маю. Купив 2-х гігабайтну версію. Тож, до мого парку додалася ще одна машина, і вона з восьмим армом, SoC Allwinner A64 4x 1.2GHz Cortex-A53. Тепер з першої хвилі, я маю п'ять машин - дві з сьомим армом, дві з восьмим, і одну з 32-бітним міпсом. Серед цих машин, маю два Allwinner'івські камінця - A20 і A64. Це певною мірою добре, бо периферія може бути та сама і програмувати другий буде легше після першого.
Тепер до "стартового коду". Uefi якби має нижню "скриту" (від стандарту) фазу. Получилось сказати якось загадашно, але насправді за цим скривається просто волокіта з найнижньорівневішою ініціалізацією, перед тим, як система могтиме ганяти повну Uefi з усіма її протоколами і сервісами. Так от, ті самі уефішні чуваки рішили стандартизувати і цю частину, але окремо від Uefi. Назвали вони це PI - Platform Initialization. Вийшло дуже плутано і криво. І неповно! Набагато важче, ніж Uefi. І, власне кажучи, - здається вони зробили те ПІ несумісним з Uefi, шо не може не "радувати". Я не хочу переказувати усе своє незадоволення, це зайве мабуть, я просто хотів сказати - воно мені не дуже подобається. Але, оскільки я абсолютний нубас, то мені все ж краще пристати на таку сяку стандартизовану і так сяк описану систему, ніж намагатися з'архітектити шось своє. Це виглядає логічніше. Тож я взявся за ПІ. Але моя мета - Uefi імплементація, і, як наслідок, - сумісність саме з цим стандартом. Щодо сумісности з ПІ, то я не збираюсь відхилятися заради відхиляння, але точно не імплементуватиму шось, шо не є сумісним з Uefi, і, можливо, шось ще, шо видасться мені абсолютною фігнею (це термін). Особливо карявою в плані сумісности з Uefi виглядає Dxe фаза. Це просто таки дуже цікавий підхід - обізвати це одночасно імплементацією Uefi, окремим стандартом, і надмножиною (несумісною ясно) над Uefi. Але, знову, може я шось недочитав, не робімо поспішних висновків. Тим паче, шо до Dxe - як до Києва рачки.
ПІ розбивається на кілька фаз і трохи апендиксів. Основний хребет іде так - SEC->PEI->DXE->BDS.
SEC - це ота сама сама макушка початку, яка отримує керування від ром-коду (в нашому армівсько-міпсівському SBC-шному випадку. Ром-код ми вважатимемо теж SEC фазою, такою собі SEC0 підфазою, на яку ми не маємо ніякого впливу), і яку власне ром-код грузить в SRAM як голий бінарник. безструктурна, неспецифікована, вона має робити най най першу свою ініціалізацію процесора, втілювати (ну а з ром-кодом - перебирати на себе) повноваження кореня довіри, в питаннях безпеки, ініціалізувати стек там, налаштовувати вектори для винятків, може, і, завантажувати-налаштовувати-передавати керування на точку входу в Pei фазу -  Pre Efi Initialization - ще одна перед-ініціалізація. Вона має, коротко кажучи, ініціалізувати процесор, чипсет і пам'ять - DRAM, і підготувавшись до цього, викликати точку входу в Dxe. Але там намудрували звичайно більше.
Ось оці дві фази і є те, над чим я парюсь зараз. Як видно, Dxe - Driver Execution Environment, я навіть не чіпав. Виглядає як Dxe є власне самим Uefi. Але з обмовками, шо в Dxe документаціях вона вдає з себе окремий стандарт і явно все норовить "покращувати". Як я вже казав, - це попередні висновки. Поки думатимемо про Dxe як про ранню Uefi фазу, яка нічого не "покращує", а просто робить те, шо від неї треба - приводить систему в стан, гожий для ганяння Uefi сервісів, які тоді використовуватимуться клієнтами - ОС лодарями, і іншими різними інструментами. Але все це діло є для вантаження ОС, - того ОС лодарями. Саме цю фазу, творці PI обізвали BDS - Boot Device Selection, і постійно повторюють, шо це там, де імплементується платформна політика завантаження (platform boot policy), а це власне - Uefi'шний Boot Manager - тож маємо трохи натяк як одне (PI) співвідноситься з іншим (Uefi). Взагалі, виглядає, шо PI - це до певної міри переробка Uefi і явно не в кращий бік. Хоча вона все ж сидить в іншій сфері - передініціалізація, тобто якби не претендує на витіснення Uefi, нема з її боку чітко визначеної межі, де вона закінчується, а де починається Uefi. От шо я хотів сказати, кажучи про "витісняє". Ця PI явно не знає, де вона закінчується, і явно залазить в Uefi, додаючи поверх останньої, ще якісь специфікації (якраз Dxe це особливо стосується). От і виглядає, шо з точки зору PI, UEFI - це всього одна BDS фаза. Не логічно. Позатим, це не так вже принципово, і я ж можу помилятися. Ми ж дивимося на PI саме як на PI - Platfotm Initialization. Саме ініціалізацію, за якою все готове для роботи Uefi.
Саме про це я читаю і саме над цим типу як працюю. Шоб зв'язати імплементацію сервісів, про які йшла мова в попередніх дописах, з стартовим кодом, шоб воно сходилося потихеньку. Це має робитися в паралель.
І наостанок, трохи додам обрисів як я бачу це на БББ - першій машині. Це може змінитися, я вже казав за це. Це лише ранні плани. Отже специфікація Pei постійно попереджає, шо вона - дуже рання фаза, і мовляв, краще робіть пізніше, в Dxe, а тут мовляв чудь чудь. Тим не менш, наварганили вони туди дуже багато вимог і архітектурних свистілок. Ядро Pei - це Pei Foundation, ядром якого є Pei Dispatcher. Ще є Peim'и - модулі, тобто драйвери Pei фази. І Pei сервіси - аналог Uefi Boot і Runtime сервісів - бібліотека для працівників. Якими є Peim'и, вони імплементують PPI - Peim to Peim Interfaces - аналог протоколів, так вони зв'язуються один з одним, використовуючи і надаючи фнкціонал, і так воно все крутиться. Фундація, в особі диспетчера, має витягати Peim'и з фірмварного тому, заносити їх у базу і виконувати їх по порядку. А значить має бути аналог бази даних цих інтерфейсів, з колбеками і нотифікаціями... В середовищі, де навіть пам'ять не ініціалізована (наприклад на міпсі криейторі, розмір tscm - SRAM'а - 16 KB, і ром-код грузе тільки 14KB навантаження)! Порядок виконання Peim'ів забезпечується спеціальною мовою залежностей - depex (dependency expressions). Свій депекс модуль кладе в окрему секцію свого файлу. Цей вираз залежности каже диспетчеру коли можна виконувати Peim'івську точку входу. Модуль повідомляє своїм виразом, які PPI (а значить Peim'и, які їх втілюють) потрібні для його роботи, і так диспетчер взнає, коли його запускати. Специфікатори PI вигадали "дуже" просту систему сховища для фірмварі - на один рівень ієрархії довшу, ніж у звичайних ФС. Бо окрім тому, файлової системи і файла, там виринає ще й секція! І шо більше - секції можуть бути вкладені. Тобто утворюють ієрархію самі по собі. І це тоді, коли вони уже використовують PE32+ формат, який і так уже має механізм секціонування і туди можна було б впхнути все, шо хочеш, навіть бітові карти кнопочок і іконок! Тим паче він би впорався з бінарним представленням депексів, з чим би завгодно впорався. Але нє, їм треба вткнути ще одну сутність в таку обмежену фазу. Ех. До речі, я серйозно розглядаю можливість знехтувати секціями фірмварних томів і використовувати саме PE секції, але ще треба подивитися, як воно відіб'ється на сумісності. Більше треба знати. Далі, в забезпеченні "ще більшої гнучкости", існує apriori файл на кожен фірмварний том, який з вищим пріоритетом, ніж депекси, тобто обчислення залежностей для Peim'ів, дає порядок виконання Peim'ів. Ояк "просто". Звичайно, це зроблено, шоб вгодити усім, на всі випадки. Ми не збираємося ігнорувати цю функціональність ядра Pei, але от виникає питання - чи потрібна у всіх випадках така аж занадто гнучка система? Наприклад на БББ, де є SoC від одного вендора, де всі Peim'и будуть написані однією людиною, чи треба роздрібнювати цю одну з найранніших фаз в таку надскладну систему з купою Peim'ів в кожному з складними залежностями від інших? Мабуть ні. Того я рішив на початках принаймні, оформити на БББ це дещо простіше, і це має виглядати так:
Отже ми маємо SEC фазу, це шматок стартового коду, який отримуватиме керування від ром-коду і передаватиме керування на Pei точку входу. Відповідно, він має розуміти інтерфейси з обох боків. Також "шось" там робитиме з процесором - ще уточнювати, шо саме. Також, можливо постачатиме свою таблицю векторів - обробляти винятки арма. Оскільки на Ситарі, ми НЕ в секуре моде, значить нам нічого робити з Монітором тут. Фізично SEC лежатиме там, де його може бачити ром-код. Спочатку ми беремо тільки SD картки, ані голий Nand, ані eMMC модулі ми не чіпаємо. Ми плануємо вкористовувати GPT партиціонування, отже нам треба змусити Ситарівський ром-код завантажувати в raw режимі, тобто не намагатися читати MBR/FAT. Тож або в кодовому блоці Protective MBR, принаймні частина, або - за PMBR і GPT заголовком. Це перший кілобайт на SD картках (бо сектор - 512 байтів). Тут виникає проблема, і вона переважно від дикої каші в описі того, шо ж насправді треба згодувати ром-коду в TI'шному TRM'і. Попри майже 5 тисяч (!) сторінок, ця надважлива частина задокументована жахливо. Курка лапою краще б задокументувала. Тож невідомо ще, чи взагалі зможемо ми згодувати йому пристрій з protective MBR, так, шоб він зрозумів, шо треба вантажити в сирому режимі. Очевидно, все мало бути просто - є спеціальний формат, який свідчить шо ось це воно, шо ти маєш вантажити в сирому режимі, і не пробувати читати МБР сигнатуру і тд. Він читає 4 місця, спершу 0 сектор. Там має бути TOC структура, а за нею GP заголовок в якому всього нічого - адреса і розмір куди і скільки треба вантажити, далі голий бінарник - наша SEC фаза. Ясно шо це мало якраз лежати в кодовому блоці захисного MBR. І влізло б! SEC фаза знала б, шо внутрі неї наcправді лежить MBR і GPT, і перестрибувала б куди треба трохи далі. Але. Почитайте в ТРМ'і, шо вони пишуть про той TOC. Там нічого не ясно - може чи не може бути він пустий. Тобто коротко кажучи вони в одному абзаці пишуть одне, в іншому протилежне. Але навіть вкупі - ця каша не дає і 10% потрібної інофрмації. Прийдеться питати в мейлинг листах. Там звичайно ніхто нічого не відповість, бо ті дрочуни тіке лінукс конпілірують, а далі виясняти методом тика. Не круто.
А от Pei фазу ми думаємо зробити так. Фізично це BFV (FV0) - Boot Firmware Volume. Лежатиме одразу за GPT заголовком, якшо не обліковуватимемо фірмварні томи як партції в GPT, або за Gpt partiotion array, в протилежному випадку. Це ще не вирішено. Але це релевантно лише для випадків, де системна партиція і фірмварне сховище лежать на одному носієві, тобто для SD карткового варіанту на етапі розробки і на випадки, де тільки так можна (в моїй класифікації - це другий тип плат, тип Raspbery Pi, Pine64, де все сховище - це витягувальний пристрій сховища, нема постійного на платі). Прикольно фірмварні томи (ФТ) мати зарахованими як партиції, це має свої зручності, але має й недолік - в цьому разі ром-код грузитиме в SRAM ще й таблицю партицій (бо вона має йти перед першою партицією, яку вона обліковує). Це не пагано само по собі, адже таблиця всеодно знадобиться пізніше. Пагано тим, шо це може не влізти в SRAM. Згадайте, на mips creator ci20 - це всього 14KB, точно не влізе. На Ситарі, - це 109 KB.
Гаразд, фізично - це наш BFV. Ми взагалі плануємо мати два ФТ - BFV і CFV. Другий - Core Firmware Volume - там лежатиме вся решта фірмварі. Таке розбиття пояснюється саме обмеженням на розмір SRAM і власне пов'язаним з ним - обмеженням на розмір скільки завантажує ром-код. На міпсі криейторі, нам очевидно прийдеться спочатку ініціалізувати пам'ять, і тільки потім завантажуватим CFV. Хоча, і на БББ так само, бо справа не лише в розмірі SRAM. Нам же вигідніше грузити основну фірмавю прямо в динамічну пам'ять. Шоб не копіювати потім. Хай який великий може бути срам, він всеодно маленький. :) Сама ж Pei планується складатися з двох PE32+ файлів. Pei.exe - Pei Foundation, Pei сервіси і інша стандартна логіка, і Pcr.sys, ім'я поки неостаточне - processor, chipset, ram інціалізація - Peim який робе важку роботу ініціалізації, навколо якої, власне вся волокіта. Перший є таким собі двигуном фази і є вельми платформно-незалежним. Наприклад, якшо я його навіть писатиму на асемблері, то можна очікувати, це буде той самий код для усіх сьомих армів. Хоч БББ, хоч КБ2 (муран, аргон). Другий очевидно дуже SoC залежний. Тож розділення вмотивоване і ясне. Тобто ми матимемо Peim'и, ми матимемо диспетчер їхнього виконання, але одразу видно - відпадає потреба в депексах як таких, і  апріорі файлі. теж. Власне, специфікація не зобов'язує мати апріорі файл обов'язково, так само депекс може бути нульовим для Peim'а. Ядро має підтримувати ці механізми, але вони можуть бути присутні а можуть не бути як такі на конкртеній інстанціації. Саме так ми і плануємо зробити - наша інстанціація PI на БББ не планує дробити Pei фазу в купу Peim'ів, лише один, і не планує використовувати ані апріорі файл, ані депекси. Хоча можливо апріорі файл можна зробити, в якому тривіально буде прописаний один цей Peim. Так ми зможемо почати з простого, і потім додавати складіншу функціональність в уже робочий двигун, який уже запускався і на скількись перевірений. Є одна обмовка, шо може Peim'ів буде два, а не один. Справді, Pei має завершувати свою роботу підготуванням до передавання керування на Dxe. Це робиться архітектурно-визначено - потрібно мати спеціальний PPI - Dxe IPL PPI - Dxe Initial Program Loader PPI. Це інтерфейс, і ніхто не сказав, шо його неможна імплементувати в Pei.exe, але, можливо, наприклад через обмеження на розмір BFV, його прийдеться виділити в окремий модуль. І це явно "шось" третє з точки зору концептуального розділення на два вищезгаданих компонента. Там перший - це логіка фази, платформно не дуже залежна. Другий - драйвер, модуль, ініціалізації найнижчих низів - дуже залежний платформно - типовий драйвер. А це третє - архітектурна річ, але явно драйверо-подібна - це власне завантажувач всієї решти фірмварі, і йому можливо прийдеться багато працювати для запуску тих дальших фаз. Тобто він як агент від пізніших фаз в цьому Pei середовищі, який возиться з їхньою логікою, породжуючи середовище для них - концептуально якась окремішня, третя річ. Тобто може бути три файли. Але це не вплине на депекси чи апріорі файл - цей Dxe IPL PPI Peim, якшо це Peim, порядок його виконання явно визначений в специфікації і не потребує нішого іншого - він виконується в самому кінці Pei фази і власне вже не вертає керування. Тобто підсумовуючи, наш BFV складатиметься з двох або трьох файлів (якшо апріорі файл використовуватиметься, то на один більше).
BFV: [apriori file], Pei.exe, Pcr.sys, [DxeIpl.sys].
Звичайно, це лише обриси, які треба уточнювати, деталізувати, і наповювати змістом.

Немає коментарів:

Дописати коментар