Краткий обзор архитектуры IBM PC


RAM

В оперативной памяти хранятся инструкции для процессора, либо данные, к которым необходим быстрый доступ. При включении компьютера его оперативная память пуста и он не может производить никаких действий, поскольку их описание попросту отсутствует. Для инициализации системы в архитектуре IBM PC существует специальная микросхема BIOS, которая позволяет загружать произвольный код с устройства хранения информации (жесткий диск, флешка, дискета и т.д.).

BIOS

BIOS (Basic Input/Output System) - это встроенное программное обеспечение, которое находится на микросхеме ПЗУ и является неотъемлемой частью архитектуры IBM PC. Это ПО выполняет функцию инициализации всей системы в целом: в первую очередь происходит настройка оборудования, затем с загрузочного устройства в оперативную память по адрессу 0x7C00 записывается загрузочный сектор, который содержит программу называемую "bootloader".

Bootloader

Bootloader (загрузчик) - очень маленькая программа, которая находится в первом секторе загрузочного устройства. Её цель - загрузить ядро операционной системы и передать ему управление. Из-за аппаратных ограничений, в частности из-за маленького размера сектора (512 байт), загрузчик зачастую делится на две части, первая из которых загружает вторую, размер которой может быть больше одного сектора. Разработка bootloader'а заключается в написании низкоуровневого кода для взаимодейтсвия с BIOS. Вглянем на следующую таблицу, чтобы понять как BIOS размечает память:

Начало Конец Размер Тип Описание
0x00000000 0x000003FF 1 KiB RAM (SYS) Real Mode IVT (Interrupt Vector Table)
0x00000400 0x000004FF 256 Bytes RAM (BIOS) BDA (BIOS Data Area)
0x00000500 0x00007BFF 30 KiB RAM Conventional Memory
0x00007C00 0x00007DFF 512 Bytes RAM (SYS) OS Boot Sector
0x00007E00 0x0007FFFF 480.5 KiB RAM Conventional Memory
0x00080000 0x0009FBFF 120 KiB RAM Conventional Memory (если существует)
0x0009FC00 0x0009FFFF 1 KiB RAM (BIOS) EBDA (Extended BIOS Data Area)
0x000A0000 0x000AFFFF 64 KiB RAM (VIDEO) Video RAM for VGA Graphics Mode
0x000B0000 0x000B7FFF 32 KiB RAM (VIDEO) Video RAM for Monochrome Text Mode
0x000B8000 0x000BFFFF 32 KiB RAM (VIDEO) Video RAM for Color Text Mode
0x000C0000 0x000C7FFF 32 KiB RAM (VIDEO) Standard Video ROM
0x000C8000 0x000EFFFF 160 KiB ROM (HW)
0x000F0000 0x000FFFFD 64 KiB ROM (BIOS) BIOS
0x000FFFFE 0x000FFFFF 2 Bytes ROM System Identification (Model/Submodel)

Рассмотрим разработку собственного загрузчика с нуля. Хочется отдельно отметить, что существует спецификация "multiboot", цель которой - объявить стандарт заголовков для multiboot-совместимых операционных систем, который позволил бы разработчику ядра операционной системы не привязывать его к конкретному загрузчику, а пользователю операционной системы свободно делать выбор между различными реализациями загрузчиков. Однако, дабы не перегружать лишней информацией свою дипломную работу и разобраться в процессе загрузки досконально, я отказался от этого стандарта. В предоставленом коде используется синтаксис "AT&T", бинарный файл собирается при помощи GNU Assembler (GAS) из комплекта GNU Binutils.

Для большей ясности вспомним и разложим процесс запуска ОС по шагам:

  1. BIOS находит загрузочный диск
  2. BIOS загружает bootloader
    • С первого (загрузочного) сектора диска
    • В логический адресс 0000:7C00h
  3. BIOS Передает управление bootloader'у, сдвигая указатель инструкции (регистр IP) на начало его кода (0000:7C00h)

Для начала создадим каркас загрузчика:

# -----------------------------------------------------------------------------
.SECTION text
.CODE16                 # данной директивой говорим ассемблеру,
                        # что мы пишем 16-битный код


LJMP $0, $RM_ENTRY      # Выравниваем %CS:%EIP, делая "длинный прыжок"
                        # до точки входа в "реальный" режим

# Точка входа в "реальный" режим
RM_ENTRY:

# Сбрасываем сегментные регистры
# (в целях совместимости со старыми BIOS'ами)
MOVW %CS, %AX           # После загрузки регистр %CS всегда будет равен 0
MOVW %AX, %DS
MOVW %AX, %ES

# Настраиваем указатель стека
MOVW %AX, %SS
MOVW $0x7C00, %SP       # Стек будет расти вниз от 0x7C00 до 0x0000

.HALT:
HLT                     # Эта команда "остановит" процессор до тех пор,
                        # пока тот не получит прерывание.
JMP .HALT               # Вернём исполнение кода на метку .HALT,
                        # создав таким образом бесконечный цикл.

# -----------------------------------------------------------------------------
.SECTION .signature
.WORD 0xAA55                # Подпись bootloader'а