пʼятниця, 19 серпня 2016 р.

Структура сховища і потік виконання перших фаз. перші спроби й обриси.

В продовження попереднього допису, опишемо трохи фізичну конструкцію нашого стартового коду, як він планується бути оформлений і яка послідовність виконання. Це все дуже поверхнево і неостаточно і це саме для BBB.
Вивчаючи інтерфейс ром коду на Sitar'і, як і слід було очікувати, виникли суперечності між документацією і реальною поведінкою. А також вияснилося, шо принаймні в частині опису ініціалізації, цей 5000-но сторінковий TRM - це каша каша каша. Шо ж, довелося таки питати в мейлинг-листах, я наче вже писав за це, шо прийдеться, ну а там мене перенаправили на питайте-можливо-відповімо сайт самого TI. Ну от чекаю тепер. Просто як нотатка, прикол такий - ситарин ром-код каже, шо на вбудованій пам'яті, тобто eMMC в нашому випадку, а також може бути NAND, ну і як зовсім екзотичний і мною ніколи не бачений варіант - eSD, він не робитиме MBR/FAT завантаження, а робитиме сирий режим - просто читатиме перший сектор, оцінюватиме чи є там образ і вантажитиме той образ прямо, і прямо на нього передаватиме керування. На картках же, він ще може робити MBR/FAT. Виявилось, шо на мурановому eMMC, нема нічого крім нулів в першій половині MBR (а саме - в BootCode блоку), де тільки й міг би лежати той голий образ для сирого режиму. Зато є файл MLO в корені FAT16 партиції, шо натякає, шо ром код на мурані таки робе файловосистемне завантаження. Точно навпаки як написано в документації. Круто!
Гаразд. Думаннями, ми надумали нарешті, як виглядатиме наш пристрій сховища структурно. Розкрій так би мовити. Той, шо англійською - layout. Розкрій мені подобається. Це первинно так. Далі уточнюватимемо (згадки за певні уточнення сюди додані, оскільки цей блог дає можливість редаґувати статтю).
Отже спочатку словесно, а потім мабуть ще картинку потворну намалюємо для іллюстрації. Розмір сектора 512 байтів тут.
Захисна MBR (Protective MBR)
Розміром в один сектор. Ця структура служить для зворотньої сумісности і для захисту GPT структур і партицій від нетямущих старих утиліт. Вона описує увесь наявний простір за собою (включно з рештою GPT метаданих) як одну неактивну партицію. Оті перші 440 байтів MBR, BootCode блок не використовуються UEFI, але нашою Sec фазою таки будуть використовуватися (не будуть, дивись уточнення нижче), по-перше цьому нема альтернативи, а по-друге, тут, на армівських і міпсівських ОПК, це не створить ніяких проблем (сумісности), того а чого власне не використаовувати цей простір? Ром код не розуміє GPT партиціонування, того ми можемо лише використовувати сирий режим. А в ньому, ром код диктує, де і як має лежати навантаження. І це майже завсіди - найперший сектор (а також якісь наперед визначені дуплікативні місця, як наприклад сектор #256, #512, #768 у випадку з ситариним ром кодом, але це майже ніким і ніколи не використовується (додане пізніше: так, майже "ніким", яка іронія, саме ці місця і доведеться використовувати див. нижче)). Тобто очевидно, ром код очікує GP заголовок (а це два 32-бітні поля для розміру і адреси куди вантажити), і сам образ в секторі #0 і далі (важливе уточнення: в секторі #0 він очікує лише маркер сирого режиму - CH, а сам образ - очікує в наступному секторі). Ми умисно оминаємо проблему з CH, бо як я писав вище - треба почекати на відповідь, але суть шанси, шо він не потрібен, і от з таким оптимістичним варіантом ми і йдемо - у нас GP заголовок і сам образ1. Така схема не конфліктує з PMBR і GPTH - вони маленькі і можуть бути якби включені в Sec шматок. Вони будуть завантажені, вони нам всеодно потрібні, все нормально. Навіть на міпсі криейторі (йод), такі об'єми влізуть (там 14КБ макс. розмір навантаження). Отже наша Sec фаза (в нашій термінології це Sec1) фізично розбивається на дві частини - Sec1.0 та, шо лежить в BootCode блоку, і потім перестрибує через решту PMBR і GPTH на Sec1.1 - решту, шо не влізло в BootCode блок. Цю другу частину я вирішив поки шо зробити 2 сектори в розмірі - 1024 байти. Тобто первинно ми вибрали Sec1 фазу в розмірі максимум 1456 байтів:
(1024 (Sec1.1) + 440 (BootCode) - 8 (GPH)). Це 364 армівські (і міпсівські теж) інструкції. Не мало, якшо не роздувати чортівні.
GPT Заголовок (GPTH)
Ну заголовок як заголовок. Все як написано в специфікації на GPT. Не переказуватиму. Він має фіксовану позицію - сектор #1, і розмір в секторах - один сектор, тобто 512 байтів в нашому випадку.
Sec1.1+BFV
Далі іде вже згадана нами друга частина Sec фази, визначена в два сектори розміром. І - BFV - Boot Firmware Volume. Фірмварний завантажувальний том. Той, де лежить Pei з Peim'ами. Ми визначили його розмір в 16КБ. Керувались тим, шо рівнятися треба на той випадок, який обмежує в розмірах. Шоб ця фаза була однакового набору функціональности на всіх наших машинах. А обмежує в розмірах нас міпс криейтор. В якого максимум навантаження - 14КБ. У мурана 109КБ. А в аргона точно не знаю, але виглядає, шо десь посередині - шось типу як 48КБ орієнтир. Також з метою ефективности. Нам не треба розганяти апетити. В цих 16КБ буде лежати код, який зрештою ініціалізує центральну логіку і пам'ять. І запускає завантажувач решти ФВ. Як я вже казав, ми маємо два ФТ - BFV і CFV. Не пам'ятаю чи казав я за облік їх в GPT, наче казав. Так от. Я якось спочатку узівав, шо можна ж якісь обліковувати, а якісь ні. Спершу я думав, за принципом - або обліковувати всі або ніякі. Але потім стало ясно, шо нам лише BFV треба покласти найближче до початку, тобто перед масивом партицій, який має йти перед будь якою облікованою ним партицією і має бути шонайменше 16КБ в розмірі. Ясно, шо ми не можемо його вантажити в SRAM - не влізе. Значить BFV не попадає в GPT облікування, але CFV нічого не заважає туди попасти. Отже так і буде - CFV йтиме як перша партиція в GPT. А вертаючись до нашої сув'язи SEC+BFV, ми маємо 17КБ в розмірі.
Масив партицій GPT (GPTPA)
Знову як і заголовком - все як у стандарті. Ми вибираємо йому 16КБ того мінімуму, який вимагається. Бо цей мінімум і так величезний для сховищ нашого діапазону. Справді, маючи, шо кожен запис в цій таблиці бере 128 байтів (може більше, але ми не робитимемо цього, це просто не треба), ми маємо потенційно 128 партицій! Першою карткою я обрав 16GB-ну, - це більш, ніж досить для неї. Насправді 128 партицій - це більш, ніж досить для будь якого нині сущого пристрою сховища.
А які ж партиції я вирішив створити?
CFV
Я писав уже, шо це таке. Це власне вся фірмваря крім, BFV і системної партиції з ОС лодарями і картинками. Тут таке - чим далі в ліс, тим гладкіші партизани. менше визначености тобто. Який розмір? Я вибрав 128КБ. Думаю цього має вистачити. Ми хочемо робити ефективно. Без отого роздування. Для коду всієї фірмварі, цього має вистачити.
Системна партиція FAT тип
Далі іде архітектурна штука - системна партиція. Куди кластимуться певні речі від фірмварі і головно, - куди сторонні розробники драйверів і лодарів кластимуть свої поробки. Не знаю який саме FAT вибрати. Але напевно або FAT16 або FAT32. Розмір. А хто його зна? Якшо тут кластимуть якісь бітові карти для графічного інтерфейса і логотипів, то це вже мегабайти. Тож це ще треба уточнювати.
А далі ідуть просто користувацькі партиції. В рамках тренування, і для цікавости, я планую створити кілька FAT партицій, шоб же подивитися, як Віндовс (та й решта) сприйме SD картку з наприклад п'ятьма партиціями і GPT схемою! Це до біса цікаво. Але треба вже зараз вивчити FAT будову. Воно того варте.
Звичайно, в кінці диску, мають іти дзеркальні копії GPTH GPTPA - але знову, - це стандратно. Треба ще навчитися запитувати точний розмір пристрою, шоб не губити жодного сектора, а поки я не знаю як це робити, ми кладемо логічну 2-х гігабайтну картку в фізичну 16-ти гігабайтну. Взнаємо як читати розмір картки, розширимо схему, і пересунемо дзеркальні структури в справжній край. (додано пізніше: я вже знаю як взнавати розмір пристрою, дякуючи простій і ясній кодовій базі відомої утиліти Win32DiskImager, і всемогутньому MSDN'у. Ключова функція в цій справі, - DeviceIoControl(), ну й іо контроли звичайно).
Далі ще треба покласти ілюстрацію вищеописаного (ілюстрація нижче).
А в кінці, - невеликий підсумок кодової послідовности на цьому етапі. Отже ром код вантажить нашу sec1 фазу. Вона в SRAM'і має відображений BFV (mmbfv), вона налаштовує потрібні структури, встановлює стек. Шось може налаштовує в процесорі. Наприклад, ситарин ромкод лишає вимкненими армівські предиктор галуження, кеші даних і коду, першого рівня, шо там уже казати за другий, вимкнена ясно й MMU. Але я не знаю, де я це налаштовуватиму - тут, в sec1, чи вже в Pcr.sys. А от ще там годинники (в смислі не таймери, чи ГРЧ а саме тактові сигнали, clock, всі оті APPLS і APLLLJ) можливо треба тут буде налаiтовувати. Watchdog таймер також. Ну і обробники винятків архітектурні армівські. Навіть якшо спочатку можна покластися на ром код, так же як і з тактовою логікою, це лише на перших кроках - адже багато чого не налаштовоано ром кодом як з PLL - не всі вони налаштовані і не всі так як треба саме на цьому етапі, а лише ті, які йому потрібні. По мінімуму. І з векторами - вони трівіальні, в повнофункціональній системі, фірмваря має перебирати на себе цю роль і налаштовувати ці речі так, як треба їй і подальшим фазам. Тож є шо робити. А ще скільки всього не відомо.
Потім, sec1, з mmbfv, завантажує Pei.exe (завантажує як виконуваний образ), якому як ми казали, не треба робити релокацію (в нормі, єдиний варіант відхилення від якої, який я зараз можу вигадати, - це коли сторінка за адресою бази Pei.exe може виявитися "паганою" апаратно, для цього ми лишаємо релокаційну інформацію в образі Pei.exe і маємо вміти в sec1 робити релокацію. Але це не важко в PE.). І передає на нього керування і аргументи визначені в специфікації. Адреси в SRAM'і, де Pei може розгорнутися. Адреси стека тощо. Далі Pei робитиме так само свою роботу, серед якої завантажить з mmbfv Pcr.sys, який ініціалізує процесор, чипсет і па'мять (DRAM). Це останнє - значна подія. Мало я ще уявляю, шо там за робота, але уявляю, шо її багато. Нарешті в кінці запуститься Dxe Ipl, чи то як окремий драйвер, чи як частина Pei.exe. І він робитиме, шо там специфікація йому велить. А також завантажуватиме з сховища CFV, тобто робитиме shadowing тому, роблячи його відображеним в пам'ять - породжуватиме mmcfv. Шоб усі подальші фази, звертались саме сюди, коли їм треба прочитати з фірмварного сховища. Це ж вам і кешування. Лише оновлення фірмварі писатиме в том на пристрій. А також збереження всяких змінних і конфігурацій в нелетке сховище. Після роботи цього модуля (Dxe Ipl), ми маємо мати розгорнуту повну Uefi Core, готову до виконання. Це вже інші етапи, які ще не вивчені і не пророблені зовсім. З точки зору їхньої ініціалізації і детального розуміння їхньої роботи, бо я маю навіть певні сервіси написані. :) Але це одне й друге - ще дуууже далеко одне від одного. От треба наближати їх.
Додано 24.08.2016
Круто, написав вчора сюди трохи уточнень, оскільки вже не було часу перевіряти описки, повернув допис в чернетки, приходю сьогодні доробити, додати малюнок, а редаґування як вітром здуло. Круто! Зато оновлює автоматично текст разів десять за хвилину. Обожнюю таке.
Гаразд, напишемо знову.
Я писав вище, шо спитав на форумі TI і чекаю на уточнення. Ну от мені відповіли і відповіли змістовно. І, тепер, треба вносити поправки в структуру. Але я вирішив не змінювати вже написане, а дописати, - у нас не посібник, а щоденник. Це відображає хід роботи.
Отже, на eMMC БББ, ром код таки робить MBR/FAT читання. Просто TRM каже неправду, шо він не робить такого на вбудованій пам'яті. Далі, ром код таки вимагає CH в першому секторі (на чотирьох позиціях, дивись нижче) якшо ти хочеш сирий режим. Ті структури, які він вимагає, влазять в BootCode блок, вони десь 288 байтів (так, 288 бісових байтів, шоб просигналити, шо тут є валідний образ). Але хоч той CH і влазе в BootCode блок і ще трохи місця лишає, нам це не допоможе поєднати це все з GPT, бо ром код очікує образ на початку наступного сектору, бо він, бач, хоче, шоб образ був вирівняним на сектор (нашось). Шо найцікавіше, про це ні слова в TRM'і. Дійсно, така дрібниця. Того, BootCode блок ми не можемо використовувати. Більше того, в наступному секторі у нас іде фіксована структура - GPT заголовок, і ми ніяк не можемо сумістити це з кладінням сюди образу (ромкод хоче там GP заголовок і передає керування на перше слово за заголовокм). Халепа. Але вихід є. І він полягає в тому, і це продовження нових знань отриманих з відповідей, шо ромкод для сирого режиму впевнено робить всі чотири спроби читання в секторах 0, 256, 512, 768, і лише тоді, коли не знаходить в жодному вказівки на гожий образ, іде до MBR/FAT завантаження. Це важливо, бо я не мав такої впевнености (наприклад я думав, шо хто зна, а може він не знайшовши валідного сирого образу в першому місці, але побачивши там MBR сигнатуру, стрибне в MBR/FAT режим. Дійсно, а шо його думати, коли все так паскудно задокументовано, і ще й явно поведінка розходиться з тим, шо написано). Тобто, ми можемо покласти все майже як збирались спочатку, але в сектор #256, пропустивши 256-34=222 сектори (34 сектори - це PMBR, GPTH, GPTPA). Це марнує 111КБ місця, проте дає можливість не розбивати sec1 на два шматки і також - обліковувати BFV як партицію (без необхідности завантажувати GPTPA в SRAM). Але головне - це не наша вина, це вимога ром коду. Суть і інші варіанти, але вони гірші. Наприклад ми можемо покласти в це пусте місце якусь іншу партицію, а далі BFV. Але це і небезпечно і незручно. Дані, які вантажаться на таких ранніх стадіях і які містять фірмварю, - це особливі дані, і спокійніше, коли вони лежать десь на переді, або взагалі на своєму пристрої. Мати якусь фіксовану точку, десь всередині сховища для фірмварі, між довільними даними - це не те. Або є так звана гібридна MBR - найсправжнісінькі костилі. Вона поєднує в собі захисну MBR і також дублює облік кількох GPT партицій (згадаймо, PMBR з чотирьох записів в таблиці записів, використовує лише один - для захисної партиції - якою покривається увесь простір за PMBR, решта записів мають мати нулі, але гібридна схема має там записи, шо дублюють інформацію про якісь вже обліковані GPT партиції. В цьому і є весь трюк - потім код, який не розуміє GPT (як от наш ром код), може використовувати інформацію за партиції з цих записів, для якого вони суть звичайні MBR записи). Але це взагалі ахтунг. Це добре коли такий код лише читає. Як ром код. Можна лише уявити, чим це все може закінчитись, якшо там влізе хтось модифікувати ті партиції. Ані одна ані інша сторона не поважатимуть один одного. Дві хазяйки на одній кухні детектед. І це звичайно суперечить GPT специфікації, це вже не GPT. Отже, просто зсовуємось на 256 секторів вперед. А облишене місце ми можемо використовувати для чогось ще - таке навіть GPT специфікація дозволяє. На відміну від гібридної MBR. Шо саме ми там можемо зберігати? Поки не знаю. Але от варіанти - логотипові картинки, користувацького інтерфейсу картинки. Або сховище для змінних і іншої конфігурації, яка вимагає нелеткого сховища.
Ці новини змінюють наш розкрій дещо. Як вже сказано, ми не розбиваємо sec1, і тепер вона суцільна, один бінарник, який лежатиме на LBA #257 одразу за сектором, який показує ром коду, шо тут лежить потрібний образ. Все як він хоче. Який розмір sec1 фази? Це ще не відомо, але тоді в нас було коло 1.5 КБ, тож можемо вибрати 4 сектори, закруглючи так би мовити. Це може змінитися. Але як перший варіант хай буде 4 сектори. Далі BFV в 16КБ (32 сектори), далі CFV 128КБ (256 секторів), далі системна партиція (SYSP) неясно ще в скільки КБ. Попри те, шо тут BFV і CFV лежать бік о бік і не рознесені як в першому варіанті, ми не поєднуємо їх в один том. Бо для цього суть купа причин. Головна - BFV відображається і його вміст працює в SRAM, CFV - в DRAM. Різним кодом і в різні фази, з різними можливостями. Набагато більше вигід в таких реаліях мати два томи, ніж об'єднувати їх. А додаткові дані на облік, які це розбиття забере - всього пара сотень байтів. Ну і це лише на БББ так. Наприклад на аргоні (кб2), там свої будуть причуди у ромкода (бром він у них називається), я ще мало знаю за нього, але там можливо підійде та первинна схема, з розбитою надвоє sec1 фазою, BFV поза обліком і CFV як партиція. Головне - таке розділення обумовлене архітектурою сучасних машин, коли спочатку в доступі є лише маленький SRAM, а потім значно більший DRAM. Код в BFV працює в першому, код CFV - вся фірмваря, працює в другому. Це насправді оптимізація мати це розбиття. От наприклад, уявіть, Pei ядру треба завантажити Pcr.sys. Шоб ініціалізувати ту ж динамічну пам'ять. Так вона шукатиме його в маленькому BFV томі, там всього кілька файлів, а з одним томом їй би прийшлось перевертати значно більший том з значно більшою кількістю файлів. Враховуючи просту пласку структуру фірмварних томів, без папок, з файлами які ідуть один за одним - це важливий фактор. Мати маленький том в обмеженій фазі, це вигідно. І по часі і по простору.
На хід виконання ранніх фаз ці зміни майже не вплинуть. sec1 фаза тепер нікуди не перестрибуватиме. Також не буде в SRAM'і GPTH. І нам треба його самим завантажувати, коли він знадобиться. Це ясно шо не страшно. Власне так навіть трохи чіткіше виходить. Шкода лише, шо місце марнується.
А це іллюстрація з врахуванням змін.
Додано 24.10.2016: На малюнку все правильно, крім кількох моментів. Створюючи першу картку з цим розкроєм, ми зсунули SYSP на LBA #512, таким чином CFV став трохи менше за 128 КБ (на розмір CH+SEC+BFV, тобто на 37 секторів, 18.5 КБ). Розмір SYSP теж вибрано було так, шоб юзерська партиція лежала на рівній адресі (LBA #40000h), SYSP відтак іде трохи менше за 128МБ.

четвер, 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].
Звичайно, це лише обриси, які треба уточнювати, деталізувати, і наповювати змістом.