x86 (англ. Intel 80x86) — архитектура процессора и одноимённый набор команд, впервые реализованные в процессорах компании Intel.
Название образовано от двух цифр, которыми заканчивались названия процессоров Intel ранних моделей — 8086, 80186, 80286 (i286), 80386 (i386), 80486 (i486). За время своего существования набор команд постоянно расширялся, сохраняя совместимость с предыдущими поколениями.
Помимо Intel, набор команд x86 также реализован в процессорах других производителей: AMD, VIA, Transmeta, IDT, Zhaoxin[2], МЦСТ (в процессорах Эльбрус) и др. В настоящее время для 32-разрядной версии архитектуры существует ещё одно название — IA-32 (Intel Architecture — 32).
x86 — это CISC-архитектура. Доступ к памяти происходит по «словам». «Слова» размещаются по принципу little-endian, известному также как Intel-формат. Современные процессоры включают в себя декодеры команд x86 для преобразования их в упрощённый внутренний формат с последующим их выполнением.
Реальный режим — классический режим адресации, использованный в первых моделях семейства. Адрес ячейки памяти (для работы с данными или для загрузки исполняемой команды процессора) формируется из сегмента (содержимого сегментного регистра) и оффсета-смещения (константа, регистр, сумма регистра с константой или сумма двух регистров с константой); это записывается в виде SSSS:OOOO (Segment:Offset), где S и O — шестнадцатеричные цифры. Сам адрес вычисляется по формуле «Segment*16 + Offset».
Предельный адрес, к которому можно обратиться — это FFFF:FFFF, то есть FFFF0+FFFF=10FFEF или словами: «один мегабайт + 64 килобайта - 16 байт». Однако, у процессоров 8086, 8088 и 80186 адресная шина была всего 20 бит, и поэтому всё, что выходило за пределы одного мегабайта, оказывалось в начале памяти (в нулевом сегменте). Начиная с процессора 80286, можно было выбирать — работать в этом же режиме для совместимости или же при помощи драйвера HiMem задействовать дополнительный сегмент памяти, в котором можно было разместить DOS и резидентные программы. (Помимо DOS, на компьютере могли работать другие операционные системы. Информация о том, как они использовали верхнюю память, вряд ли сохранилась.)
Оперативная память при этом оказывалась как бы неоднородной — небольшие блоки данных можно было обрабатывать, манипулируя только регистрами оффсета, а для больших блоков данных приходилось манипулировать сегментными регистрами. Для описания этого были введены следующие термины:
(все блоки начинались с адреса, кратного их размеру).
Начиная с процессора 80386, при помощи драйвера DOS4GW появилась возможность использовать реальный режим с 32-битными регистрами и адресовать до четырёх гигабайт памяти. Сами сегменты тут фактически оказались не нужны.
Микропроцессоры 8086/8088, 80186/80188 и 80286 имели четыре сегментных регистра, т.е могли работать одновременно с четырьмя сегментами памяти, имеющими определённое назначение:
В 80386 добавили ещё два, не имеющих специального назначения:
Несмотря на то, что сегментные регистры имеют специальные назначения, архитектура допускает при некоторых обращениях к данным заменить один сегмент на любой другой. Сегменты кода, стека и получателя строк всегда используют регистры CS, SS и ES и не могут быть изменены.
Сегментный подход позволяет разделить всю память на 16 сегментов, начинающихся с адресов, кратных 64 Кбайт. Эти 16 сегментов называют страницами памяти. Обычно деление на страницы используется для совместного функционирования устройств, интерфейсы которых отображены на адресное пространство памяти; тогда каждое такое устройство использует одну страницу памяти, и адрес ячейки в адресном пространстве устройства будет совпадать со смещением в сегменте памяти компьютера. Так в компьютерах IBM PC адресное пространство распределялось таким образом:
Первые десять сегментов (640 Кбайт) адресного пространства содержат оперативную память, в которой размещаются:
Два сегмента отдавались под видеоадаптер — VideoBIOS и «окно» для отображения видеопамяти в адресное пространство процессора (для видеоадаптеров CGA, EGA, VGA и остальных способ отображения очень сильно различался).
Три сегмента использовались для размещения там разных вещей, например:
Последний сегмент первого мегабайта предназначался для размещения ПЗУ со стартовым BIOS. В частности, адрес FFFF:0000 — тот, на который передаётся управление при старте компьютера (то есть после аппаратной инициализации процессор начинает выполнение программы с этого адреса).
Первый сегмент за пределами первого мегабайта — HiMem, о котором говорилось выше.
В реальном режиме отсутствует защита памяти и разграничение прав доступа, поэтому он уже практически вышел из употребления. Однако, реальный режим является режимом по умолчанию для всех моделей процессоров семейства x86 — процессор начинает свою работу именно в реальном режиме, в котором выполняется BIOS, MBR, BR и начальная часть OS-Loader. Поэтому все операционные системы, работающие на процессорах x86, имеют в своём составе некоторое количество стартового кода для этого режима процессора.
Более совершенный режим, впервые появившийся в процессоре 80286 и в дальнейшем многократно улучшавшийся. Имеет большое количество подрежимов, по которым можно проследить эволюцию семейства ЦП. В этом режиме поддерживается защита памяти, контексты задач и средства для организации виртуальной памяти. Аналогично реальному режиму, тут также используется сегментированная модель памяти, однако уже организованная по другому принципу: деление на параграфы отсутствует, а расположение сегментов описывается специальными структурами (таблицами дескрипторов), расположенными в оперативной памяти. Помимо базового адреса сегмента дескрипторы содержат размер сегмента (точнее, максимально доступное смещение) и различные атрибуты сегментов, использующиеся для защиты памяти и определения прав доступа к сегменту для различных программных модулей. Существует два типа дескрипторных таблиц: глобальная и локальная. Глобальная таблица описывает сегменты операционной системы и разделяемых структур данных. Локальная таблица может быть определена для каждой конкретной задачи (процесса). Сегменты памяти также выбираются все теми же сегментными регистрами; однако вместо номера параграфа сегментный регистр содержит специальную структуру (селектор), содержащую индекс дескриптора в таблице. Сам же дескриптор загружается из памяти во внутренний программно недоступный регистр (кеш), привязанный к каждому сегментному регистру и автоматически загружаемый в момент его модификации.
Каждый программный модуль, выполняемый в защищённом режиме, определяется его сегментом кода, описываемым регистром CS, который и определяет его привилегии по доступу к данным и другим модулям. Существует 4 уровня привилегий (0, 1, 2 и 3), называемых кольцами защиты. Кольцо 0 наиболее привилегированное. Оно предназначено для модулей ядра операционной системы. Кольцо 3 — наименее привилегированное, и предназначено для пользовательских программ. Кольца 1 и 2 используются лишь некоторыми операционными системами. Сегменты данных также имеют атрибуты прав доступа, дающие доступ только коду, имеющему такие же или более высокие привилегии. Система колец позволяет гибко распределять доступ к коду и данным.
Процессор 80386, появившийся в 1985 году, в отличие от своих предшественников стал 32-битным. В нём появилась возможность адресовать до 4 гигабайт памяти, что позволило создавать сегменты памяти размером во всё адресное пространство. Поэтому новые операционные системы использовали вырождённую модель организации памяти, когда все сегменты начинаются с нулевого адреса. Такая модель получила название плоской (flat memory model), и адрес задаётся одним целым 32-разрядным числом (хотя по сути он является смещением внутри вырожденного сегмента), а сами сегменты используются исключительно для организации защиты по кольцам привилегий.
Сегментное MMU современных процессоров, несмотря на кардинальные различия двух его основных режимов, в обоих работает схожим образом. Это позволяет организовывать нестандартные режимы не описанные в официальной документации, но иногда очень полезные при написании программ. Поскольку известно, что внутренние кэши дескрипторов используются во всех режимах, и именно они используются для адресации памяти, при понимании логики их работы возможна загрузка в них нестандартных значений для текущего режима. В частности, можно создать дескрипторную таблицу в реальном режиме, установить флаг PE, загрузить сегментные регистры уже в защищенном режиме, а потом тут же сбросить флаг PE. До следующей перезагрузки сегментного регистра его кеш дескриптора будет содержать значение, соответствующее защищенному режиму, и если он был загружен должным образом, появится возможность адресации до 4 GiB памяти. Подобные нестандартные режимы получили общее название Unreal mode и активно используются BIOS'ами персональных компьютеров. В процессоре 80286 также была возможность загрузки нестандартных значений дескрипторного кеша при помощи недокументированной команды LOADALL; что было особенно актуально, поскольку процессор 80286 не позволял сбрасывать флаг PE (из защищённого режима выходили с помощью сброса процессора, что сказывалось на производительности).
В процессорах, начиная с 80386, появилось мощное MMU, позволяющее организовать отображение страниц памяти, что было ещё одним поводом перехода на плоскую модель с приходом 32-разрядных вычислений. Используя трансляцию страниц, операционная система может создать собственное линейное адресное пространство для каждого процесса; также каждая страница имеет атрибуты прав доступа. В отличие от сегментов, таких уровней существует только 2: пользователь и супервизор. Но для большинства современных операционных систем этого вполне достаточно. Страничное MMU доступно только в защищенном режиме.