Рассмотрим выполнение основного модуля. Нумерация пунктов данного описания
соответствует нумерации пунктов комментариев в исходном тексте -
файле WORK\smp.asm.
1) Контрольная точка 00h – начало выполнения программы. Вывод в порт 80h кода
00h.
2) Установка SS:SP для адресации стека.
3) Проверяем, что процессор в реальном режиме (MSW.0=0), иначе уходим на
генерацию сообщения об ошибке и выход.
4) Подготовка к 32-битной адресации. Это необходимо, так как регистры Local
APIC находятся в пространстве памяти (Memory-Mapped I/O).
4.1) Разрешаем линию A20. См. также комментарии к файлу WORK\a20.inc.
4.2) Разрешаем Big Real Mode (использование 32-битной адресации в реальном
режиме). См. также комментарии к файлу WORK\bigreal.inc.
4.3) Проверяем работу 32-битной адресации. Для этого считываем байт по адресу
FFFFFFF0h (ROM BIOS Reset Vector) и проверяем, что он равен EAh (код инструкции
JMP FAR).
Эта проверка использована автором для удобства отладки программы. Вместе с
тем, возможны нестандартные реализации ROM BIOS, у которых байт по указанному
адресу не будет равен EAh, поэтому проверку рекомендуется удалить после
завершения отладки.
5) Детектирование Local APIC и проверка его статуса.
5.1) Считываем регистр IA32_APIC_BASE MSR - адрес и статус контроллера Local
APIC. Проверяем статус и сохраняем адрес Local APIC для последующего
использования. Регистр IA32_APIC_BASE MSR описан в [8], [14].
5.2) Проверяем бит APIC Soft Enable в регистре Spurious Interrupt Vector
Register (SVR).Подробности в [8], [14].
5.3) Проверяем Local APIC Version. Подробности в [8], [14].
5.4) Проверяем Local APIC ID для Bootstrap Processor. Подробности в [8],
[14].
6) Начинаем взаимодействие с Application Processor. Генерируем Init IPI
(Initialization Inter-Processor Interrupt) для Application Processor. Для этого
используем запись соответствующей команды в регистр Interrupt Command Register
(ICR). Используем задержку для гарантированного выполнения операции. При
получении Init IP процессор AP перейдет по Reset Vector (FFFFFFF0h), и будет
остановлен в BIOS, так как BIOS допускает выполнение процедуры POST только
процессором BSP. Получение Init IPI аналогично получению аппаратного сигнала
INIT. Данная операция подготавливает процессор AP к получению следующих IPI.
Подробности в [8], [10], [14].
7) Продолжаем взаимодействие с Application Processor. Генерируем Startup IPI.
7.1) Подготовка переменных в оперативной памяти, которые затем будут
использованы процедурой обработки прерывания IPI, выполняемой на Application
Processor.
7.2) Подготавливаем в оперативной памяти (в сегменте стека), по адресу,
выровненному на 4KB, инструкцию межсегментного перехода (FAR JMP) на начало
процедуры обработки Startup IPI, которую будет выполнять Application Processor.
Транзитная инструкция JMP необходима, так как для Startup IPI, битовое поле
Vector используется не как вектор прерывания, а как часть физического адреса.
Если Vector=xxh, адрес перехода 000xx000h (align 4KB).
7.3) Генерируем Startup IPI для Application Processor. Для этого используем
запись соответствующей команды в регистр Interrupt Command Register (ICR).
Используем задержку для гарантированного выполнения операции. При получении
Startup IPI процессор AP перейдет по адресу 000xx000h, выполнит размещенную там
транзитную инструкцию JMP и перейдет к выполнению процедуры Routine_Startup,
которая проинициализирует AP, сохранит в памяти результаты работы, для контроля
со стороны BSP за работой AP. Затем AP будет остановлен с разрешенными
прерываниями. Процедура Routine_Startup описана в комментариях к файлу
WORK\handlers.inc.
7.4) Верификация результатов работы AP. Проверяем значения переменной
Flag_SIPI, сравниваем значения IA32_APIC_BASE MSR для BSP и AP.
7.5) Проверяем значение APIC ID процессора AP, сохраненное процедурой
Routine_Startup.
8) Продолжаем взаимодействие с Application Processor. Генерируем IPI для
обработки прерывания с номером вектора 80h. Номер вектора выбран произвольно при
отладке программы.
8.1) Перехватываем прерывание INT 80h, вектор устанавливаем на процедуру
Routine_INT80, описанную в комментариях к файлу WORK\handlers.inc. Исходное
значение вектора сохраняем.
8.2) Подготавливаем параметры для генерации INT 80h IPI. Устанавливаем
старшее 32-битное слово регистра ICR. Подробности в [8], [10], [14].
8.3) Генерируем INT 80h IPI для AP. Для этого используем запись
соответствующей команды в регистр Interrupt Command Register (ICR). Используем
задержку для гарантированного выполнения операции. При получении IPI процессор
AP перейдет на обработку процедуры Routine_INT80, загрузив из вектора INT 80h
значения CS:IP для реального режима. Операцию повторяем 2 раза (цикл по метке
Run_AP) для проверки работоспособности EOI. Процессор BSP контролирует
выполнение процессором AP процедуры Routine_INT80 с помощью переменной
Flag_INT80.
Подробности в [8], [10], [14].
8.4) Восстанавливаем вектор INT 80h.
9) Запрещаем работу AP. Для этого генерируем Init-IPI, AP начнет выполнение
по Reset Vector и будет остановлен в BIOS. Подробности в [8], [10], [14].
10) Восстанавливаем системный контекст.
10.1) Запрещаем Big Real Mode, подробности в комментариях к файлу
WORK\bigreal.inc.
10.2) Восстанавливаем исходное состояние адресной линии A20, подробности в
комментариях к файлу WORK\a20.inc.
11) Выдаем сообщение об успешном завершении программы и выходим в DOS с кодом
возврата 00h.
12) На этот пункт приходим, если выполняется выход с ошибкой из секции кода,
в которой INT 80h перехвачено. Восстанавливаем INT 80h.
13) На этот пункт приходим, если выполняется выход с ошибкой из секции кода,
в которой разрешен Big Real Mode и линия A20. Запрещаем Big Real Mode,
восстанавливаем состояние A20.
14) Выдаем сообщение об ошибке и выходим в DOS с кодом возврата 01h.
Модуль WORK\a20.inc содержит библиотеку для управления адресной линией A20. В
данной программе это требуется, так как регистры Local APIC адресуются, как
Memory-Mapped I/O и расположены выше 1MB. Из основного модуля вызываются три
подпрограммы этой библиотеки: Check_A20 проверяет состояние линии A20 путем
проверки раздельной адресации ячеек памяти с адресами 00000000h и 00100000h.
Enable_A20_use8042 разрешает линию A20, Disable_A20_use8042 запрещает.
Используется выходной порт контроллера клавиатуры 8042. Подробности в [8], [14],
[19], [22].
Модуль WORK\bigreal.inc содержит библиотеку для поддержки 32-битной адресации
в реальном режиме. В данной программе это требуется, так как регистры Local APIC
адресуются, как Memory-Mapped I/O и расположены выше 1MB. Из основного модуля
вызываются две подпрограммы этой библиотеки: Enable_Big_Real_Mode разрешает
использование 32-битной адресации, устанавливает лимиты сегментов 4GB.
Disable_Big_Real_Mode запрещает использование 32-битной адресации, устанавливает
лимиты сегментов 64KB. Для установки лимитов сегментов, процессор временно
переводится в защищенный режим, в сегментные регистры загружаются селекторы,
адресующие дескрипторы с установленным требуемым значением лимита сегмента.
После возврата в реальный режим процессор “помнит” значения лимитов сегментов.
Подробности в [8], [14], [19].
Модуль WORK\delay.inc содержит подпрограмму задержки Delay_Tick. Задержка
используется при ожидании запуска AP (Application Processor). В зависимости от
расположения во времени момента вызова данной подпрограммы относительно моментов
генерации прерываний системным таймером (IRQ0) обеспечивается задержка 1-2
периода IRQ0 (около 55-110 ms).
Это базовый вариант, примененный для отладки. При оптимизации программы, для
исключения непроизводительных задержек, данную процедуру можно модифицировать,
для более точной отработки интервалов.
Модуль WORK\handlers.inc содержит процедуры обработки прерываний IPI
(Inter-Processor Interrupts) выполняемые “вторым” процессором. Подпрограмма
Routine_INT80 сохраняет в переменной Flag_INT80 значение APIC ID процессора AP,
которое контролируется основной процедурой, выполняемой на процессоре BSP.
Подпрограмма Routine_Startup инициализирует процессор AP: устанавливает значение
SS:SP, разрешает Big Real Mode (так как для второго процессора это нужно сделать
отдельно), обновляет переменную Flag_SIPI, сохраняет значения IA32_APIC_BASE MSR
и APIC ID процессора AP, которые затем будут проконтролированы программой,
выполняемой на BSP. В регистр SVR процессора AP, записывается значение, ранее
прочитанное из регистра SVR процессора BSP. Для приема процессором AP
последующих IPI, важно, чтобы бит 8 регистра SVR (APIC Software Enable) был
установлен в “1”. Затем разрешаются прерывания и AP останавливается. В таком
состоянии процессор AP готов для приема IPI. Подробности в [8], [10], [14].
Модуль WORK\datasegs.inc содержит сегменты данных и стека. Нумерация пунктов
данного описания соответствует нумерации пунктов комментариев в исходном тексте
- файле WORK\datasegs.inc.
1) Сегмент переменных VARIABLES_DATA. Содержит переменные общего назначения,
переменные для обмена информацией между процессорами BSP и AP, а также таблицу
GDT для работы подпрограмм поддержки Big Real Mode.
2) Сегмент текстовых сообщений TEXT_DATA.
3) Сегмент стека для AP (то есть для “второго” процессора) AP_STACK.
4) “Обычный” сегмент стека STACK_16.
Источники информации
Электронные документы, доступные на сайте
developer.intel.com.
1) 64-bit Extension Technology Software Developer’s Guide. Volume 1 of 2.
Order Number 300834-001.
2) 64-bit Extension Technology Software Developer’s Guide. Volume 2 of 2. Order
Number 300835-001.
3) TLBs, Paging-Structure Caches, and Their Invalidation. Application Note.
Document Number 317080-001.
4) Intel 64 and IA-32 Architectures Optimization Reference Manual. Order Number
248966-015.
5) Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 1: Basic
Architecture. Order Number 253665-023US.
6) Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 2A:
Instruction Set Reference, A-M. Order Number 253666-023US.
7) Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 2B:
Instruction Set Reference, N-Z. Order Number 253667-023US.
8) Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 3A:
System Programming Guide, Part 1. Order Number 253668-023US.
9) Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 3B:
System Programming Guide, Part 2. Order Number 253669-023US.
10) Multiprocessor Specification. Version 1.4. Order Number 242016-006.
11) 82093AA I/O Advanced Programmable Interrupt Controller (IOAPIC). Order
Number 290566-001.
12) Introduction to Hyper-Threading Technology. Document Number 250008-002.
Электронные документы, доступные на сайте
developer.amd.com.
13) AMD64 Architecture Programmer’s Manual. Volume 1: Application
Programming. Publication No. 24592.
14) AMD64 Architecture Programmer’s Manual. Volume 2: System Programming.
Publication No. 24593.
15) AMD64 Architecture Programmer’s Manual. Volume 3: General-Purpose and System
Instructions. Publication No. 24594.
16) AMD64 Architecture Programmer’s Manual. Volume 4: 128-Bit Media
Instructions. Publication No. 26568.
17) AMD64 Architecture Programmer’s Manual. Volume 5: 64-Bit Media and x87
Floating-Point Instructions. Publication No. 26569.
Электронные документы, доступные на сайте
acpi.info.
18) Advanced Configuration and Power Interface Specification. Hewlett-Packard
Corporation, Intel Corporation, Microsoft Corporation, Phoenix Technologies
Ltd., Toshiba Corporation. Revision 3.0.
Книги
19) В.Л. Григорьев. Микропроцессор i486. Архитектура и программирование.
Москва ТОО “ГРАНАЛ” 1993.
20) В.Г. Артюхов, А.А. Будняк. В.Ю. Лапий. С.М. Молявко, А.И. Петренко.
Проектирование микропроцессорной электронно-вычислительной аппаратуры.
Справочник. Киев “Тэхника” 1988.
21) К. Г. Самофалов, О.В. Викторов. Микропроцессоры. Библиотека инженера. Киев
“Тэхника” 1989.
22) 2B ProGroup: В.А. Вегнер, А.Ю. Крутяков, В.В. Серегин, В.А. Сидоров, А.В.
Спесивцев. Аппаратура персональных компьютеров и ее программирование. IBM
PC/XT/AT и PS/2. Москва “Радио и связь” 1995.