Настройка и работа в Linux
adb5321d

Загрузочный сектор


Хватайте ваш любимый редактор и наберите следующее:

entry start start: mov ax,#0xb800 mov es,ax seg es mov [0],#0x41 seg es mov [1],#0x1f loop1: jmp loop1

Это понятный as86 диалект ассемблера. Первая инструкция описывает точку входа в программу. Мы объявляем, что управление первоначально должно быть передано на метку start. Вторая строка описывает расположение этой метки (не забудьте поставить ":" после "start"). Первая инструкция, которая должна быть выполнена в этой программе, расположена сразу после нее.

0xb800 -- это адрес сегмента видеопамяти в текстовом режиме. Символ # указывает на непосредственное значение. После выполнения команды

mov ax,#0xb800

регистр ax будет содержать значение 0xb800, это адрес расположения видеопамяти. Теперь мы копируем это значение в сегментный регистр es. Помните, что 8086 имеет сегментную архитектуру. У него четыре сегментных регистра, указывающих на: сегмент кода ( CS ), сегмент данных (DS), сегмент стека ( SS ) и дополнительный сегмент (ES ). Фактически, мы сделали видеопамять нашим дополнительным сегментом, так что все записанное в него, будет записано в видеопамять.

Для отображения любого символа на экране, вам нужно записать в видеопамять два байта. Первый -- это значение ascii-кода символа, который вы хотите вывести на экран. Второй -- атрибут символа. Атрибут содержит следующую информацию: цвет символа, цвет фона, мерцание. Инструкция seg es фактически является префиксом, указывающим относительно какого сегмента должна выполняться следующая операция. Итак, мы заносим в первый байт видеопамяти (адрес 0xb800:0) значение 0x41, которое соответствует ascii-коду символу "A" (большая английская A). Затем мы должны прописать значение атрибута символа в следующем байте видеопамяти. Сюда мы записываем значение 0x1f, соответствующее белому символу на синем фоне. (Чтобы понять, где что спрятано в байте атрибута, лучше преобразовать 0x1f в двоичное представление: 00011111. Здесь первые четыре бита [справа налево] -- цвет символа, следующие три -- цвет фона и последний 7-й бит [отсчет ведется с нуля] -- это признак мерцания. Из вышесказанного можно сделать следующий вывод: в текстовом режиме символ может иметь 16 цветов, фон -- 8. Прим.перев.) Теперь, если мы выполним эту программу, то получим белую "A" на синем фоне. В конце стоит программная "петля" (команда jmp указывающая на саму себя). Нам нужно, либо остановить выполнение кода после того, как отобразим символ, либо "намертво" замкнуть цикл. Сохраните файл как boot.s .

Идея с манипуляцией видеопамятью может быть не совсем понятна, поэтому позвольте мне объяснить на будущее. Предположим мы используем экран размером 80 на 25 (80 символов в строке и 25 строк). Для каждой строки нам нужно по 160 байт: 80 байт, содержащие коды символов и столько же, содержащие их атрибуты. Если нам нужно вывести 3-й символ в 1-й строке, то мы должны пропустить байты 0 и 1, как относящиеся к первому символу; байты 2-й и 3-й, как относящиеся ко второму символу и только после этого записать в 4-м байте ascii-код выводимого символа и в 5-м -- его атрибут.


Используя прерывание 0x13, код загрузочного сектора читает и копирует второй сектор флоппи-диска в память по адресу 0x5000 (сегментный адрес 0x500). Пример этого показан ниже. Сохраните его в файле bsect.s.

LOC1=0x500

entry start start: mov ax,#LOC1 mov es,ax mov bx,#0

mov dl,#0 mov dh,#0 mov ch,#0 mov cl,#2 mov al,#1

mov ah,#2

int 0x13

jmpi 0,#LOC1

Первая строка -- это макро-определение. Следующие две инструкции уже знакомы вам по предыдущей статье. Записать данные непосредственно в регистры сегментов нельзя, поэтому следующие две строки используются для загрузки в регистр es значения 0x500. Регистр bx содержит значение смещения в сегменте, по которому будут загружены данные.

Далее мы записываем...

  • номер устройства в регистр dl (принцип кодирования описан в пункте 1.3)
  • номер головки чтения/записи в регистр dh
  • номер цилиндра в регистр ch
  • номер сектора в регистр cl
  • количество загружаемых секторов в регистр al
  • Итак, мы загружаем второй сектор нулевой дорожки устройства номер 0 (что соответствует приводу флоппи-дисков на 1.44Мб) по адресу 0x500:0.

    Значение 2 в регистре ah указывает на номер функции прерывания. Мы выбираем функцию номер 2, которая используется для чтения данных с диска (жёсткого или гибкого).

    Теперь мы вызываем прерывание 0x13 и последней командой передаём управление коду, загруженному по адресу 0x500:0.



    Содержание раздела