Уроки ОСдева №3: блок параметров BIOS / программирование :: OSDev :: разработка :: Операционная система :: ассемблер :: geek (Прикольные гаджеты. Научный, инженерный и айтишный юмор)

программирование geek ассемблер Операционная система разработка OSDev песочница 

Уроки ОСдева №3: блок параметров BIOS

В прошлый раз мы разобрались с физической геометрией дискеты и расположением данных. Кроме того, мы узнали, как записать программу-загрузчик в нулевой сектор носителя. Если кто-то из вас действительно пытался повторить мои действия и потом использовать дискету как загрузочную, то наверняка обнаружил два неприятных момента:


1. При попытке открыть образ дискеты Wndows говорит, что она не отформатирована.
2. BIOS не воспринимает дискету как загрузочную и пишет что-нибудь вроде "no bootable device found".

Давайте разбираться. Если помните, в конце прошлого поста наша будущая программа-загрузчик выглядела так:

.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                    cli

                             hlt

CSEG ends

end begin


По сути это просто заглушка, которая при запуске должна останавливать процессор. Причина ругани Виндоус в том, что в нулевом секторе на отформатированном носителе хранится важная структура данных - блок параметров BIOS (BPB). Записав туда же нашу программу, мы его пот+ёрли. Для того, чтобы этого избежать, нам придётся воссоздать BPB в тексте программы. Для этого нужно знать геометрию носителя. К счастью, в наше время сохранился только один тип дискет.


Непроверенный метод: возможно, если с помощью утилиты debug записать программу не в начало сектора, а со смещением, достаточным, чтобы пропустить оригинальный BPB, то он не пострадает, но я не проверял. По-моему, debug всё равно забьёт остатки сектора каким-то мусором.


Во-первых, измените программу вот так:


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop

execute:                 cli

                             hlt

CSEG ends

end begin


У нас появились две новые инструкции: jmp short и nop. Последняя - просто пустой оператор. Процессор пропускает его, не выполняя никаких действий. Занимает 1 байт. jmp - инструкция перехода. jmp short - переход в пределах 127 байт от текущего положения. Исполняется гораздо быстрее jmp, так что везде где возможно - используйте его. Занимает 2 байта. execute - название метки, на которую указывает инструкция jmp short.


Зачем всё это и зачем nop? BPB должен располагаться строго в трёх байтах от начала нулевого сектора. Эти три байта и занимают инструкции jmp short execute и nop. Таким образом, когда программа начнёт исполняться, первой инструкцией, которую выполнит процессор, будет пропустить BPB. В противном случае он бы попытался исполнить его как код, что привело бы к катастрофе.

Теперь давайте вставим сам блок параметров BIOS между nop и меткой execute.


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop


                BPB_OEMname          db    'BOOTDISK'

                BPB_bytespersec       dw    512

                BPB_secperclust        db     1

                BPB_reserved            dw    1

                BPB_numFATs           db     2

                BPB_RDentries          dw    224

                BPB_sectotal             dw    2880

                BPB_mediatype         db     0F0h

                BPB_FATsize             dw     9

                BPB_secpertrack        dw     18

                BPB_numheads         dw     2

                BPB_hiddensec          dd     0

                BPB_sectotal32          dd     0

                EBPB_drivenum         db     0

                EBPB_NTflags            db     0

                EBPB_extsign            db     29h

                EBPB_volID               dd     0

                EBPB_vollabel            db     'BOOTLOADER '

                EBPB_filesys              db     'FAT12   '


execute:                 cli

                             hlt


CSEG ends

end begin


BPB - это блок данных, и здесь мы впервые объявляем переменные. В TASM это выглядит так: BPB_OEMname (имя) -пробел- db, dw, dd или dq -пробел- 'BOOTDISK' (значение). Имени может и не быть, но тогда к переменной нужно будет обращаться по смещению, это не очень удобно. DB, DW, DD и DQ - сокращение от define byte (word, double word или quad word) - обозначают размер переменной. Соответственно, 1, 2, 4 или 8 байт. Инстркция этого типа позволяют объявлять целые серии значений через запятую: myvalue dw 2, 5, 165, 776. С помощью инструкции db можно объявлять строки: mytext db 'Allo, Yoba!' Обратите внимание, что в плоском бинарнике переменные при компиляции не выносятся в какую-то специальную область данных. В исполняемом файле они будут именно там, где вы их объявили в тексте программы. Ещё важный момент: имена переменных только для вашего личного пользования, в исполняемый файл они не попадут, так что вы не обязаны копировать названия у меня. Теперь давайте посмотрим, что за информация хранится в BPB.


BPB_OEMname - 8 байт: по идее здесь должно быть название производителя, но по факту вы можете писать что угодно, никто на это значение не смотрит.

BPB_bytespersec - 2 байта: размер сектора в байтах, для дискет как правило 512.

BPB_secperclust - 1 байт: число секторов в кластере. Про кластеры мы поговорим позже, но в случае с дискетами секторы и кластеры соответствуют друг другу.

BPB_reserved - 2 байта: число зарезервированных секторов, недоступных файловой системе. В нашем случае такой один, это наш загрузочный сектор.

BPB_numFATs - 1 байт: количество FAT (file allocation table), таблиц распределения файлов. Так как носители информации (особенно дискеты) подвержены порче, а FAT - очень важная часть файловой системы, для неё часто делается резервная копия.

BPB_RDentries - 2 байта: количество записей в корневой директории (Root Directory). Про корневую директорию тоже будем говорить в другой раз, но пока можете представить её как список файлов с указанием их физического расположения на носителе.

BPB_sectotal - 2 байта: число секторов на диске, если их не больше 65535. Если больше, здесь должен быть 0.

BPB_mediatype - 1 байт: тип носителя. F0 - код для 3,5-дюймовой дискеты с 18 секторами в дорожке.

BPB_FATsize - 2 байта: размер одной FAT в секторах.

BPB_secpertrack - 2 байта: число секторов в дорожке.

BPB_numheads - 2 байта: число головок.

BPB_hiddensec - 4 байта: количество скрытых секторов перед загрузочным, в нашем случае 0.

BPB_sectotal32 - 4 байта: число секторов, если их больше 65535. Если меньше, здесь должен быть 0.


Здесь стандартный BIOS Parameter Block заканчивается и начинается расширенный, который появился в поздних версиях DOS.


EBPB_drivenum - 1 байт: бесполезная переменная, хранящая номер привода, в который был вставлен носитель при форматировании.

EBPB_NTflags - 1 байт: флаги Вин НТ. Если установлен бит 0, необходимо проверить носитель на битые секторы. Значения других флагов не знаю.

EBPB_extsign - 1 байт: признак расширенного BPB. Для нашей версии должно быть 29h.

EBPB_volID - 4 байта: случайный номер, который присваивается при форматировании. В общем бесполезен.

EBPB_vollabel - 11 байт: имя носителя.

EBPB_filesys - 8 байт: имя файловой системы.


Если вы теперь заново скомпилируете программу и запишите на дискету, то она отлично откроется в Windows. Первая проблема решена, но осталась вторая: дискета всё ещё не опознаётся как загрузочная. Вспоминаем: для этого последние 2 байта загрузочного сектора должны иметь значения AAh и 55h. Добавим ещё две строчки в нашу программу:


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                     jmp short execute

                             nop


                BPB_OEMname          db    'BOOTDISK'

                BPB_bytespersec       dw    512

                BPB_secperclust        db     1

                BPB_reserved            dw    1

                BPB_numFATs           db     2

                BPB_RDentries          dw    224

                BPB_sectotal             dw    2880

                BPB_mediatype         db     0F0h

                BPB_FATsize             dw     9

                BPB_secpertrack        dw     18

                BPB_numheads         dw     2

                BPB_hiddensec          dd     0

                BPB_sectotal32          dd     0


                EBPB_drivenum         db     0

                EBPB_NTflags            db     0

                EBPB_extsign            db     29h

                EBPB_volID               dd     0

                EBPB_vollabel            db     'BOOTLOADER '

                EBPB_filesys              db     'FAT12   '


execute:                 cli

                             hlt


               org 510

                dw 0AA55h


CSEG ends

end begin


Команда org 510 заполнит нулями место от текущей позиции до 510 байта, а в последние два мы поместили метку загрузочного сектора. Вуаля, проблема 2 решена.


Выражалось мнение, что всё это ебучее легаси и современные пацаны предпочитают UEFI, но UEFI не даст вам того интимного, я бы сказал, понимания железа, на котором работает ваша ось, так что основная серия будет продолжена по старинке.



Подробнее
программирование,geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор,ассемблер,Операционная система,разработка,OSDev,песочница
Нужны ли туторы по UEFI?
Да
88 (69.3%)
Нет
8 (6.3%)
Я не знаю, заебал свою гиковскую xуйню сюда постить, вали на гитxаб!
31 (24.4%)
Еще на тему
Развернуть
Лет сто назад писал машинными кодами, пока не узнал, что есть ассемблер.
Увожение
обхохочешься...
а если серьёзно, зачем здесь перепечатка какого-то учебника?
какие нахер дискеты? треть реактора их в жизни не видело, а остальные не видели лет 15.
хочешь в ассемблер - микроконтроллеры же есть, там это хоть немного актуально.
теме посвящено дохрена толстых книг, есть куча поделок, что должно двигать человеком чтоб он побежал за флопиком?
Да и на микроконтроллерах не особо то и актуален ассемблер. Этот код же надо потом поддерживать. А поддерживать ассемблерный код - так себе удовольствие. Хотя знать его полезно.
дааа, на микроконтроллерах не особо то и актуален, то ли дело на ПК...
Я, может, крамольную вещь скажу, но писать свои загрузчики в 2019 году, когда есть EFI в каждом утюге, немного извращение. Достаточно сделать ваше ядро EFI-приложением, настроить EFI и можно будет будет загружать ядро прямо из boot-меню вашей материнской платы. Linux так умеет делать. Гуглится по запросу EFISTUB.
Бля, я немного жопой читаю, не прочитал самый конец, где как раз говорилось про EFI. Ну, вообще программировать под EFI тоже весело.
Для меня с самого начала побудительным мотивом к написанию ОС было разобраться в работе железа, так что я всегда старался работать на самом низком уровне. Только без шуток про машинные коды, все взрослые люди, да? EFI - более современная и удобная теxнология, не спорю, но написать свой драйвер-то более познавательно.
Книжка Э. Танненбаум по ОСями всё ещё актуальна. Ты прав полностью в своём интересе - если хочешь понять, необходимо пройти этот путь. Писать саму ОС не обязательно, но интересно, если время позволяет.
Было время, когда сам интересовался, но сразу отпустило, когда узнал, что это, по-сути, тупое дёрганье функций BIOS, помноженное на ОГРОМНОЕ количество времени!
Книжка супер, давно читал, а пару месяцев назад обновлённое издание купил и перечитываю. Дёргать функции BIOS совсем не обязательно, а после переключения в 32- или 64-битный режим и вовсе проблематично. Я вот ими пользуюсь только до переключения в защищённый режим. Благо большая часть устройств сейчас уже имеет более-менее стандартизированный базовый функционал. Можно без проблем запилить свою таблицу прерываний, драйверы клавиатуры, дисков, VGA и библиотеку вывода. Кстати про VGA есть отличная книга Майкла Абраша. Забыл название. Zen of VGA programming или что-то такое.
Теоритически можно даже в современном x86_64 компьютере подкинуть микросхему памяти с записанными инструкциями проца по нужному адресу и он будет их выполнять.
Поясни. Ты имеешь в виду вместо нормальной плашки RAM засунуть такую, где прописана твоя программа? Она должна быть защищена от записи, иначе на место твоей программы будет скопирован код загрузчика или операционки. А если она будет защищена от записи, то BIOS ее забракует на этапе предзагрузочного тестирования, как я это понимаю.
Или я не про то думаю?
Мне вот не нравится x86, он страшно переусложненный сейчас. И просто загрузиться - уже целая история. Intel Software Developer Manual на стопицот страниц. Куда больше в плане пробования своих сил в OS dev'е мне нравится ARM. В принципе, можно взять какой-нибудь ARM с MMU (ту же расбери), куда проще. И консоль сделать в UART, а не на экран. Хотя, x86 тоже в юарт выводят.
Только зарегистрированные и активированные пользователи могут добавлять комментарии.
Похожие темы

Похожие посты
Programmers in Enterprise Company
Programmers in Startup Company
Programmers in Government 		i-^ * TI □
<r
r/AskReddit
Posted by u/Elastic_Quatsch •
10h
1 Д 57 & 57 @ 51 $ 69
Тебя похитили. Через 30 минут похититель тебя бросает на улице, потому что ты, не замолкая, говоришь о...?
^ 61.4к	СР 33.Ok	< Share £+)
Ú BEST COMMENTS -
CapitanFlama 9h
0*	0 11 Awards
О том, что линукс самая крутая
подробнее»

geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор it-юмор Linux Операционная система

□ <r r/AskReddit Posted by u/Elastic_Quatsch • 10h 1 Д 57 & 57 @ 51 $ 69 Тебя похитили. Через 30 минут похититель тебя бросает на улице, потому что ты, не замолкая, говоришь о...? ^ 61.4к СР 33.Ok < Share £+) Ú BEST COMMENTS - CapitanFlama 9h 0* 0 11 Awards О том, что линукс самая крутая