ассемблер

Подписчиков: 1     Сообщений: 5     Рейтинг постов: 19.5

программирование 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 не даст вам того интимного, я бы сказал, понимания железа, на котором работает ваша ось, так что основная серия будет продолжена по старинке.


Нужны ли туторы по UEFI?
Да
84 (68.9%)
Нет
8 (6.6%)
Я не знаю, заебал свою гиковскую xуйню сюда постить, вали на гитxаб!
30 (24.6%)
Развернуть

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

Уроки ОСдева №2: схемы адресации и твоя первая программа на ассемблере

Если кто-то решил следовать этим туторам, самое время обзавестись необходимыми инструментами. Скачайте turbo assembler (TASM) или любой другой привычный вам. Установите виртуальную машину с Windows XP. Работать с большинством используемых программ проще в ней. Я бы посоветовал Oracle VirtualBox.


CHS


В прошлый раз мы выяснили несколько важных вещей:

- для того, чтобы загрузить ОС с дискеты, нам нужна программа-загрузчик.

- программа-загрузчик должна занимать ровно 512 байт, причём последние два байта должны содержать метку загрузчика (AA55h).

- программа-загрузчик должна располагаться в первом физическом секторе носителя.


Эта информация в свою очередь ставит перед нами новый вопрос: как поместить загрузчик на полагающееся ему место? Придётся разбираться в схемах адресации данных на цифровых носителях. Тема не очень простая, но необходимая, так что крепитесь.


geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор,OSDev,операционная система,разработка,программирование,ассемблер,песочница


На картине выше - структура дискового носителя. Это может быть жёсткий диск, дискета или CD, суть не поменяется. Головка, она же лицо, - это одна сторона поверхности носителя (пластины). У жёсткого диска на рисунке 4 двусторонних пластины, то есть 8 головок. Головка в свою очередь разбита на концентрические дорожки (они же цилиндры), а те - на одинакового размера (как правило 512 байт) секторы. Независимо от радиуса цилиндра в каждом из них одинаковое число секторов, что позволяет для доступа к любому конкретному сектору использовать трёхкомпонентную координату Цилиндр-Головка-Сектор (Cylinder-Head-Sector, CHS). Важно помнить, что в системе CHS цилиндры и головки нумеруются с 0, а секторы - с 1. То есть для доступа к первому физическому сектору носителя наши координаты будут иметь значения: 0(цилиндр), 0(головка), 1(сектор).


Проблема в том, что привычные нам файловые системы скрывают физическую геометрию носителей за набором абстракций вроде файлов и папок. К счастью, есть альтернативы. Например, в Windows есть команда debug. Выглядит так:


debug boot.bin(имя файла, загружается в память по адресу 100h)

-w(запись) 100(адрес загруженного файла) 0(номер привода) 0(номер первого сектора) 1(число секторов для загрузки)

-q(выход)


Я выше писал, что секторы нумеруются с 1, но debug закон не писан. Всё остальное время правило в силе.


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


LBA


Информацию из этого раздела мы пока использовать не будем, но позже она пригодится. Формат CHS на сегодняшний день устарел. Практически все устройства нативно поддерживают схему адресации под названием LBA (Linear Block Addressing), в которой к секторам обращаются просто по их порядковому номеру, без учёта геометрии носителя. Тем не менее, CHS поддерживается на уровне эмуляции и для работы с дискетами пользоваться мы будем именно ей.


boot.asm


Итак, мы разобрались, как поместить нашу программу в нужное место на дискете. Самое время приступать к написанию кода! Мы, конечно, не будем в этот раз писать полный загрузчик. Это будет просто небольшая вводная в турбо ассемблер. Она предназначена для людей без опыта в ассемблере и подразумевает, что вы будете пользоваться TASM. Если вы уже знаете x86 ассемблер и намерены пользоваться каким-то другим - смело пропускайте конец статьи.


Скачали TASM? Отлично, инсталлируйте его в какое-нибудь легкодоступное место на диске и в папке BIN/ создайте папки OS/boot/stage1/.


Теперь в stage1/ создайте пустой текстовый файл, переименуйте его в boot.asm и откройте текстовым редактором. В файле создайте следующий текст:


.386p

CSEG segment use16

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

begin:


CSEG ends

end begin


Сделали? Сохраните и давайте разбираться. Сразу скажу, что собственно программы здесь пока нет. Всё, что вы видите - набор инструкций для компилятора, в исполняемый файл они не попадут.


.386p - указание компилятору сверять инструкции с набором для 386 процессора в защищённом (protected, отсюда p) режиме. Соответственно, если компилятор встретит инструкцию, которую данный процессор не поддерживает, он выдаст ошибку.


CSEG - название сегмента, в котором будет содержаться код нашей программы.


Следующую строчку будет сложно объяснить, т.к. мы пока не касались устройства процессора, так что просто примите как есть: это указание компилятору считать, что все сегментные регистры процессора указывают на сегмент CSEG.


begin - метка начала программы. Отсюда будет начинаться собственно код.


CSEG ends - конец сегмента CSEG.


end begin - метка конца программы.


Скомпилировать программу в таком виде не выйдет, так как в ней нет ни одной инструкции. Давайте добавим парочку.


.386p

CSEG segment use16

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

begin:                    cli

                             hlt

CSEG ends

end begin

Мы добавили 2 команды: cli и hlt. Первая запрещает прерывания, то есть не даёт устройствам отправить сигнал процессору, а вторая останавливает сам процессор. Таким образом, сейчас наша программа при запуске просто "вешает" компьютер. Тем не менее, её уже можно превратить в исполняемый файл.


Откройте командную строку, перейдите в папку BIN/ и введите: tasm OS/boot/stage1/boot.asm. После нажатия enter в папке BIN/ появится файл BOOT.OBJ. Это ещё не конец. Файл .obj - это инструкция для линкера, так что пишите: tlink boot.obj. Теперь у вас добавились два новых файла, BOOT.MAP и BOOT.EXE, последний из которых - и есть исполняемый файл, который нам нужен! Незадача в том, что мы пишем не приложение под DOS, а операционную систему, которая должна будет работать на голом железе. exe-формат содержит таблицы релокации и всякие прочие данные, которые нам будут мешать. В нашем исполняемом файле должны быть только инструкции программы и больше ничего. К счастью, и тут есть готовое решение. Пишите в командной строке exe2bin boot.exe и жмите enter. Появился файл boot.bin. Проверьте его размер, он должен занимать ровно 2 байта, по одному байту на инструкции cli и hlt. Успех!


В качестве ДЗ предлагаю всем желающим самостоятельно загнать файл в первый сектор дискеты, вся нужная информация в тексте статьи есть.

Развернуть

геймдев Игры ассемблер олдфаги поймут roguelike 

Олдфажного геймдева пост номер 2

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


Для начала - о том, что есть сейчас. Бой проходит в пошаговом, разумеется, режиме. Врагов может быть до четырёх штук. Игрок выбирает цель, затем выводятся результаты раунда. Попал или не попал, если попал, то сколько нанёс урона и убита ли цель. То же самое для противников. Очередность действий участников определяется сравнением их Dexterity.


Не очень интересно, но это можно исправить введением таких вещей как: позиционирование, резисты, магия, разные типы атаки, обороны и оружия.


COMBAT! 1. dog skeleton aims at your throat 2. 3. 4. Attack Character,геймдев,Игры,ассемблер,олдфаги поймут,roguelike


С первым пунктом у меня достаточно просто. Враг может быть In melee range - доступен для атаки любым способом и может атаковать в ответ. Out of melee range - достать можно копьём, стрелой или магией, но и сам он атаковать может только дистанционно. Враги начинают бой в случайной позиции, но у каждого есть предпочтительное положение и в процессе боя он будет стараться занять именно его. Сблизиться на дистанцию ближнего боя с врагами в тылу можно только после того как будут убиты все "передние". Особняком стоят летучие враги - этих можно достать дистанционной, магической или контратакой, но нельзя обычной атакой копьём.


Разные типы оружия тоже добавляют тактический элемент: мечи наносят хороший урон и имеют средний штраф к скорости; кинжалы не имеют штрафа к скорости вообще; дубинки дают вероятность оглушить; молоты/топоры/клевцы имеют самый большой штраф к скорости, но разрушают вражескую броню, а копья позволяют атаковать врагов из заднего ряда.


ROUND RESULTS You take a mighty suing at dog skeleton dog skeleton takes 22 points of physical damage dog skeleton dies,геймдев,Игры,ассемблер,олдфаги поймут,roguelike


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


Фуx. Это ещё не все запланированные боевые возможности, но для одного раза достаточно. Пы сы: из этого поста можно заключить, что бои - это основная, если не единственная, часть игры, но нет. Я сторонник идеи, что игроку нужно давать свободу двигаться к цели тем способом, который ему нравится, поэтому игру можно будет пройти скрытно или за счёт дипломатии.

Развернуть

TIS-100 geek программирование Игры ассемблер 

TIS-100, Tessellated Intelligence System

Наткнулся недавно на игрушку (странно, что не нашёл её упоминания на реакторе) - паззл по программированию на ассемблере.
Суть такова: у нас есть задание, например, сложить два числа из узлов ввода, а результат записать в узел вывода, и есть определённый набор этих самых доступных узлов, каждый из которых имеет один регистр хранения данных (не считая дополнительного регистра сохранения). Узлы могут обмениваться данными с соседними узлами. Каждый узел можно запрограммировать индивидуально (набор инструкций весьма краток и прост) для обработки поступаемых данных. Игрушка выполнена в стилистике олдскульных терминалов. Задания варьируются по сложности, голову зачастую приходится изрядно поломать. Корованы грабить нельзя, зато можно профилировать производительность, улучшая/ухудшая показатели в зависимости от реализации алгоритма.

- DIFFERENTIAL CONUERTER -
CREATE NEU PROCRAM
1
COPY
UNTITLED PROGRAM
279 CYCLES / 8 NODES / 19 INSTR
CREATE NEU PROGRAM
COPY
OPEN SAUE DIRECTORY
CYCLE COUNT STATISTICS
NODE COUNT STATISTICS
INSTRUCTION COUNT STATISTICS
19 ▼
TIS-100 SEGMENT
SEGMENT 00150
SELF-TEST
DIAGNOSTIC
-


- SIGNAL AMPLIFIER -
MOU UP, DOWN
	
COMMUNICATION FAILURE	
	
MOU UP, ACC	ACC
1 ADD ACC ||	14
MOU ACC, DOWN	
	BAK <0>
	LAST N/A
	MODE RUN
	IDLE 4*
MOU UP, ACC ADD ACC
MOU LEFT, DOWN	ACC
MOU UP, DOWN	0
	BAK <0>
	LAST N/A
	MODE WRTE
	IDLE 13/.
OUT. A | 144,TIS-100,geek,Прикольные



Развернуть

кино Elysium Элизиум ассемблер песочница 

Смотрю тут Элизиум, чувак кодит "споилер" для Элизиума и тут я замечаю! У них год 2154, они роботов клепают, а пишут все так же на ассемблере. Лол!
1694
1695
1696
1697
1698
MOV 0V0R0 PTR (COX)*4, 0 MOV OVORO PTR (COX)*8. II NCA*J>ROTO.J.O MOV OVORO PTR (COX)»12. UNCAft_PROTOJII MOV T£MP_GOT_*cr*1<fc. fabl*_!1n«ar. COX MOV TCMP_60T_icr«f<K	15
08 66H
LGOT TCMP_G0T_itra1ch
, enter protected node
MOV COX. CR
, RAM_START • lize
Развернуть
В этом разделе мы собираем самые смешные приколы (комиксы и картинки) по теме ассемблер (+5 картинок, рейтинг 19.5 - ассемблер)