Использование инструкции cpuid
Аннотация
Целью второй лабораторной работы является
исследование возможностей инструкции cpuid, моделирование ветвлений, использование битовой логики, а также использование ассемблерных вставок в коде программ на языке высокого уровня.
Ход работы
- Перейдите в каталог для файлов лабораторных работ по курсу "Архитектура современных ЭВМ".
- Создайте каталог для файлов данной лабораторной работы.
- Скопируйте текст программы в новый файл testcpuid.S.
- Выполните ассемблирование и сборку программы.
- Запустите программу, убедитесь, что на экране напечатан идентификатор производителя процессора (GenuineIntel, AuthenticAMD или иной).
- Изучите реализацию механизма проверки наличия инструкции cpuid, которая основана на возможности изменения на противоположное значение 21 бита регистра флагов:
- через стек (так как инструкции прямого копирования регистра флагов в другой регистр не предусмотрено) копируем флаги в EAX;
- создаем копию исходного значения регистра флагов в регистре EBX;
- меняем 21 бит в EAX на противоположный;
- возвращаем модифицированное значение EAX на регистр флагов;
- снова вытаскиваем флаги в EAX;
- сравниваем с сохраненной в EBX копией;
- если они не отличаются, переходим на фрагмент кода, печатающий сообщение о недоступности cpuid.
- Изучите реализацию механизма получения идентификатора производителя процессора:
- в EAX устанавливаем номер функции cpuid для получения данных о производителе (функция 0);
- выполняем инструкцию cpuid;
- 12-байтовый идентификатор получаем в регистрах EBX, EDX, ECX;
- в EAX получаем максимально допустимый номер поддерживаемой данным процессором функции cpuid.
- Реализуйте проверку доступности фукнции 1 инструкции cpuid:
- проанализируйте значение регистра EAX, полученное в результате выполнения функции 0 инструкции cpuid (см. шаг 7.4);
- если функция 1 недоступна, программа должна выводить диагностическое сообщение и корректно завершаться;
- убедитесь, что при недоступности функции 1 инструкции cpuid программа отрабатывает корректно, для этого, выполняя программу в отладчике, вручную обнулите (подмените) значение регистра EAX перед проверкой доступности.
- Реализуйте проверку наличия математического сопроцессора (x87 FPU on Chip) и подсистемы MMX с помощью cpuid:
- в EAX устанавливаем номер функции для получения feature information процессора (функция 1);
- вызываем cpuid;
- убеждаемся, что нужный бит регистра EDX (туда будет записана информация о наличии и отсутствии подсистем) равен 1. Для FPU это бит 0, для MMX - 23. Для тестирования битов самостоятельно изучите команду test, а также использование команды je в связке с арифметической или логической инструкцией (пример использования je имеется в данной программе).
- Реализуйте небольшую статическую библиотеку на языке программирования C для проверки наличия математического сопроцессора и программу для проверки функций библиотеки. Функции библиотеки (может быть, единственная функция) должны использовать ассемблерные вставки для вызова инструкции cpuid и получения результата проверки.
/**
* cpuid.S -- печатает сведения о подсистемах процессора
*
* Copyright (c) 2022 Petrozavodsk State University
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*/
/* Секция данных */
.data
errmess:
.string "CPUID is not supported\n"
/* Секция команд процессора */
.text
.global _start # точка входа - глобальная метка
_start:
/* Подготавливаем стек к работе с локальными переменными */
pushl %ebp # сохраняем текущий контекст стека
movl %esp, %ebp
subl $16, %esp # резервируем 16 байт для локального
# буфера
/* Анализируем, доступна ли инструкция cpuid */
pushfl # получаем содержимое регистра флагов
popl %eax # в регистре eax
movl %eax, %ebx # сохраняем копию регистра флагов
xorl $0x00200000, %eax # меняем бит 21 на противоположный
pushl %eax # сохраняем измененное значение
popfl # в регистре флагов
pushfl # снова получаем регистр флагов
popl %eax
xorl %ebx, %eax # если бит не сохранился
je no_cpuid # cpuid не поддерживается
/* Получим идентификатор производителя процессора */
movl $0, %eax # загружаем код функции регистр eax
cpuid # получаем строку производителя
movl %ebx, -16(%ebp) # в регистрах ebx, edx, ecx
movl %edx, -12(%ebp) # сохранаем в буфер
movl %ecx, -8(%ebp)
movb $10, -4(%ebp) # помещаем символ перевода строки в
# в конец буфера
/* Выводим идентификационную строку производителя ЦП на экран */
movl $4, %eax # помещаем номер системного вызова
# write в регистр eax
movl $1, %ebx # помещаем номер стандартного потока
# вывода (stdout) в ebx
movl %ebp, %ecx # помещаем адрес начала буфера выводе
subl $16, %ecx # в ecx
movl $13, %edx # помещаем длину строки в edx
int $0x80 # обращаемся к ОС для выполнения
# системного вызова (вывода строки)
/*** Дополнительные проверки - РЕАЛИЗУЙТЕ САМОСТОЯТЕЛЬНО ПО ЗАДАНИЮ */
/*** */
jmp done
/* Обработка ситуации, если cpuid отсутствует (80386) */
no_cpuid:
movl $4, %eax # помещаем номер системного вызова
# write в регистр eax
movl $1, %ebx # помещаем номер стандартного потока
# вывода (stdout) в ebx
leal errmess, %ecx # помещаем адрес начала буфера вывода
movl $24, %edx # помещаем длину строки в edx
int $0x80 # обращаемся к ОС для выполнения
# системного вызова (вывода строки)
/* Организуем корректное завершение программы */
done:
mov %ebp, %esp # восстанавливаем контекст стека
popl %ebp
movl $1, %eax # загружаем в eax номер вызова exit
movl $0, %ebx # загружаем в ebx код возврата 0
int $0x80 # выполняем обращение к ОС для
# выполнения системного вызова
.end # последняя строка исходного текста