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