Команда IT специалистов выполнит подготовку инфраструктуры для вашего бизнеса.
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
Пишем свой начальный загрузчик bootloader
Пишем свой начальный загрузчик bootloader
Предыдущую часть смотрите здесь
Сегодня мы напишим свой собственный начальный загрузчик
Который помимо вывода строк на монитор будет предоставлять
нам возможность выбора из списка. Я не стала эспериментировать
со свистоперделками, цветом и другой доступной из биоса
хренью, а ограничилась тем что нам может действительно
в дальнейшем пригодится. Практически в коде у нас получился
обычный переключатель switch(). Если вы знакомы с меню
загрузчика freebsd то наш результат будет выглядеть похоже.
Основными кирпичиками для работы с биосом мы определили функции
вывода символа на монитор и задержки, аналогичной тому что нам
предоставляет команда sleep в баше. Алгоритм работы нашего
загрузчика следующий:
Загрузчик начинает свою работу и через команду
прерывания int $0x10 отправляет для вывода на монитор
символ за символом в интервале 0,05 секунды пока на мониторе
полностью не отобразится меню загрузчика определенное
в переменной menu.
Интервал между выводами знаков мы так же передаем
биосу посредством прерывания int $0x15. Далее мы отправляем
биосу сигнал ожидания ввода символа с клавиатуры int $0x16.
При нажатии любой клавиши наш код определит и преключит
выполнение по одному из трех сценариев. Первый сценарий
осуществится если мы нажмем единицу, второй - двойку и
третий - дефолтный если мы нажмем любую другую отличную
от первых двух клавиш. Вот код нашего загрузчика:
[spoiler][/spoiler]
Функцию вывода на монитор единичного символа мы обернули
в цикл и при помощи команды lods организовали конвеерную
итерацию по перебору всего массива строки. Выход из цикла
осуществляется автоматически когда закончится строка и в
регистре %al появится занчение '\0'
Так как функции в asm вызываются без параметров
а нам просто необходимо задавать ей разные адреса
строк в регистр %si то вместо того что бы перед каждым
вызовом этой функции мы заносили адрес переменной
в регистр (lea var, %si),
мы скомбинируем функцию с макросом в котором мы можем
задавать параметры. Тоесть мы вызываем определенный макрос
с параметром а он в свою очередь воспользуется услугами
функции. В результате мы уложимся всего одной командой.
В нашей программе определены два макроса. Один вполне
самодостаточный, строки 14-18, посылает биосу сигнал
на выполнение задержки определенный параметром. У нас имеются
задержки между выводом строк в 0,5 секунды и в 3 секунды
перед перезагрузкой. Все хорошо видно в коде программы.
Так как я посчитала что интервал между выводом знаков
строчного массива определенного в макросе минимально
возможной величино в 0,1 секунды это слишком много то
в функции вывода строки я не использовала макрос задержки
а написала самостоятельный код и определила в нем
интервал в 0,05 секунды. Строки 34-37. На самом деле при
вызове задержки интервал определяется в двух регистрах,
значения старших разрядов числа заносятся в регистр %cx,
а младшие разряды в регистр %dx. Одно общее значение из этих
двух регистров %cx:%dx и определяет интевал в микросекундах.
Тоесть поместив в регистр %cx ноль а в регистр %dx 5000
мы определили задержку как раз в 0,05 секунды. В макросе
мы ограничились только регисром %cx у которого нижний предел
начинается с 0,1 секунды, нас это устраивает, а %dx в этом
случае мы обнуляем что бы при вызове макроса не приходилось
указывать два параметра. Собираем наш код как описано в
предыдущей статье и запускаем в гипервизоре qemu-kvm.
[album]454[/album]
Начальный загрузчик у нас получился простенький, без излишеств,
но в то же время достаточно симпатичный и функциональный.
В следующей статье мы научимся отлаживать наш код и настроим для
этого подходящий инструментарий.
Сегодня мы напишим свой собственный начальный загрузчик
Который помимо вывода строк на монитор будет предоставлять
нам возможность выбора из списка. Я не стала эспериментировать
со свистоперделками, цветом и другой доступной из биоса
хренью, а ограничилась тем что нам может действительно
в дальнейшем пригодится. Практически в коде у нас получился
обычный переключатель switch(). Если вы знакомы с меню
загрузчика freebsd то наш результат будет выглядеть похоже.
Основными кирпичиками для работы с биосом мы определили функции
вывода символа на монитор и задержки, аналогичной тому что нам
предоставляет команда sleep в баше. Алгоритм работы нашего
загрузчика следующий:
Загрузчик начинает свою работу и через команду
прерывания int $0x10 отправляет для вывода на монитор
символ за символом в интервале 0,05 секунды пока на мониторе
полностью не отобразится меню загрузчика определенное
в переменной menu.
Интервал между выводами знаков мы так же передаем
биосу посредством прерывания int $0x15. Далее мы отправляем
биосу сигнал ожидания ввода символа с клавиатуры int $0x16.
При нажатии любой клавиши наш код определит и преключит
выполнение по одному из трех сценариев. Первый сценарий
осуществится если мы нажмем единицу, второй - двойку и
третий - дефолтный если мы нажмем любую другую отличную
от первых двух клавиш. Вот код нашего загрузчика:
[spoiler]
Код: Выделить всё
.code16 #шеснадцати битный режим
.section .text #только одна секция
.globl _start;
#точка входа в программу
_start:
jmp _boot #прыгаем на метку _boot: в код выполнения
welcome: .asciz "Hello, World\n\r" #here we define the string
goodby: .asciz "This is normal level\r\nreboot will over 3 seconds\r\n"
menu: .asciz "choose level download:\r\n1 - nomal boot\r\n2 - fast reboot\r\n"
mistake: .asciz "Mistake, try again\r\nreboot now"
.macro mWait str
mov $0x86, %ah
mov \str, %cx
int $0x15
.endm
.macro mWritestr str
lea \str, %si
call Writestr
.endm
.func
Writestr:
1: lodsb
orb %al, %al #проверяем на ноль, определяем конец строки.
jz 1f
movb $0xe, %ah
int $0x10
# mWait $0x1
mov $0x86, %ah
mov $0x0, %cx
mov $0x5000, %dx
int $0x15
jmp 1b
1: ret
.endfunc
_boot:
mWritestr welcome
mWait $0x5
mWritestr menu
mov $0x00, %ah
int $0x16
cmp $0x02, %ah
je Exit
cmp $0x03, %ah
je reboot
mWritestr mistake
mWait $0x10
jmp reboot
Exit:
mWritestr goodby
mWait $0x30
reboot:
ljmp $0xffff, $0x0000
#Заполняем оставшееся место до сигнатуры нулями
.fill (510 - (. - _start)), 1, 0
.word 0xaa55
Функцию вывода на монитор единичного символа мы обернули
в цикл и при помощи команды lods организовали конвеерную
итерацию по перебору всего массива строки. Выход из цикла
осуществляется автоматически когда закончится строка и в
регистре %al появится занчение '\0'
Так как функции в asm вызываются без параметров
а нам просто необходимо задавать ей разные адреса
строк в регистр %si то вместо того что бы перед каждым
вызовом этой функции мы заносили адрес переменной
в регистр (lea var, %si),
мы скомбинируем функцию с макросом в котором мы можем
задавать параметры. Тоесть мы вызываем определенный макрос
с параметром а он в свою очередь воспользуется услугами
функции. В результате мы уложимся всего одной командой.
В нашей программе определены два макроса. Один вполне
самодостаточный, строки 14-18, посылает биосу сигнал
на выполнение задержки определенный параметром. У нас имеются
задержки между выводом строк в 0,5 секунды и в 3 секунды
перед перезагрузкой. Все хорошо видно в коде программы.
Так как я посчитала что интервал между выводом знаков
строчного массива определенного в макросе минимально
возможной величино в 0,1 секунды это слишком много то
в функции вывода строки я не использовала макрос задержки
а написала самостоятельный код и определила в нем
интервал в 0,05 секунды. Строки 34-37. На самом деле при
вызове задержки интервал определяется в двух регистрах,
значения старших разрядов числа заносятся в регистр %cx,
а младшие разряды в регистр %dx. Одно общее значение из этих
двух регистров %cx:%dx и определяет интевал в микросекундах.
Тоесть поместив в регистр %cx ноль а в регистр %dx 5000
мы определили задержку как раз в 0,05 секунды. В макросе
мы ограничились только регисром %cx у которого нижний предел
начинается с 0,1 секунды, нас это устраивает, а %dx в этом
случае мы обнуляем что бы при вызове макроса не приходилось
указывать два параметра. Собираем наш код как описано в
предыдущей статье и запускаем в гипервизоре qemu-kvm.
Код: Выделить всё
as -o bootloader.o bootloader.s
ld -Ttext 0x7c00 --oformat=binary -o bootloader.bin bootloader.o
qemu-kvm -fda bootloader.bin -boot a
Начальный загрузчик у нас получился простенький, без излишеств,
но в то же время достаточно симпатичный и функциональный.
В следующей статье мы научимся отлаживать наш код и настроим для
этого подходящий инструментарий.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: Пишем свой начальный загрузчик bootloader
/
- всё это будет работать только в реальном аппаратном режиме процессора x86 (с адресацией только до 640Kb RAM) ...
- который (режим) повторяет работу процессоров 8086/8088 - времени ... ранних 90-х
- все же программы в операционных системах в Windows, Linux, FreeBSD и во всех других операционных системах, когда они пишутся и на ассемблере - используют совсем другую мнемонику (некоторых) команд и схему адресации - защищёного режима (в который процессор переключается аппаратно)
- ... поэтому ассемблерный код реального режима невыполним в защищённом и наоборот
- (современные ОС в процессе загрузки переключает процессор из реального режима в защищённый)
- но в процессорах x86 существует, кроме реального и защищённого режимов, ещё один - иногда его называют нереальный, когда в режиме подобного реальному адресуется 4Gb памяти как в защищённом.
Зачем я сделал такое дополнение?
1. для общей эрудиции, тех кто заинтересуется тем, что в x86 (по недосмотру Intel) есть не 2, а 3 режима адресации.
2. очень интересно было бы все ваши эксперименты выполнять переведя процессор в нереальный режим адресации.
Если вы описываете это упражнение не только для себя, а ещё для кого-то, кто будет это читать, то нужно предупреждать:nezabudka писал(а): Загрузчик начинает свою работу и через команду
прерывания int $0x10 отправляет для вывода на монитор
символ за символом в интервале 0,05 секунды пока на мониторе
полностью не отобразится меню загрузчика определенное
в переменной menu.
- всё это будет работать только в реальном аппаратном режиме процессора x86 (с адресацией только до 640Kb RAM) ...
- который (режим) повторяет работу процессоров 8086/8088 - времени ... ранних 90-х
- все же программы в операционных системах в Windows, Linux, FreeBSD и во всех других операционных системах, когда они пишутся и на ассемблере - используют совсем другую мнемонику (некоторых) команд и схему адресации - защищёного режима (в который процессор переключается аппаратно)
- ... поэтому ассемблерный код реального режима невыполним в защищённом и наоборот
- (современные ОС в процессе загрузки переключает процессор из реального режима в защищённый)
- но в процессорах x86 существует, кроме реального и защищённого режимов, ещё один - иногда его называют нереальный, когда в режиме подобного реальному адресуется 4Gb памяти как в защищённом.
Зачем я сделал такое дополнение?
1. для общей эрудиции, тех кто заинтересуется тем, что в x86 (по недосмотру Intel) есть не 2, а 3 режима адресации.
2. очень интересно было бы все ваши эксперименты выполнять переведя процессор в нереальный режим адресации.
Re: Пишем свой начальный загрузчик bootloader
Olej Сперва повторюсь, это немного расширенный обзор по следам серии статей где и описано
все в подробных деталях. Здесь я хочу дополнить что уже опубликованно немного под другим взглядом.
Если выберите в интернете первый десяток публикаций по написанию начального загрузчика то
обнаружите копию своего текста. Думаю именно мой вариан будет неплохим дополнением к уже существующим. В любом случае большое спасибо за коментарии и может кому то будет лень ходить
в гости.
все в подробных деталях. Здесь я хочу дополнить что уже опубликованно немного под другим взглядом.
Если выберите в интернете первый десяток публикаций по написанию начального загрузчика то
обнаружите копию своего текста. Думаю именно мой вариан будет неплохим дополнением к уже существующим. В любом случае большое спасибо за коментарии и может кому то будет лень ходить
в гости.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay