Краткий обзор архитектуры 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.
Для большей ясности вспомним и разложим процесс запуска ОС по шагам:
- BIOS находит загрузочный диск
- BIOS загружает bootloader
- С первого (загрузочного) сектора диска
- В логический адресс 0000:7C00h
- 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'а