Я читал книгу Роберта Лава «Разработка ядра Linux» и наткнулся на следующий отрывок:
Нет (простого) использования плавающей точки
Когда процесс пользовательского пространства использует инструкции с плавающей запятой, ядро управляет переходом из целочисленного режима в режим с плавающей запятой. Что должно делать ядро при использовании инструкций с плавающей запятой, зависит от архитектуры, но обычно ядро улавливает ловушку и затем инициирует переход из целочисленного режима в режим с плавающей запятой.
В отличие от пользовательского пространства, ядро не имеет возможности бесшовной поддержки плавающей запятой, поскольку оно не может легко перехватить само себя. Использование плавающей запятой внутри ядра требует ручного сохранения и восстановления регистров с плавающей запятой, помимо других возможных рутинных операций. Короткий ответ: не делайте этого! За исключением редких случаев, в ядре нет операций с плавающей запятой.
Я никогда не слышал об этих режимах «целое число» и «с плавающей запятой». Что они собой представляют и зачем они нужны? Существует ли это различие в основных аппаратных архитектурах (например, x86) или оно характерно для некоторых более экзотических сред? Что именно влечет за собой переход от целочисленного режима к режиму с плавающей запятой, как с точки зрения процесса, так и с точки зрения ядра?
kernel_fpu_begin()
/kernel_fpu_end()
до / после вашего кода, чтобы убедиться, что состояние FPU в пользовательском пространстве не повреждено. Это то, чтоmd
делает код Linux для RAID5 / RAID6.Ответы:
Потому как...
... ядро ОС может просто выключить FPU. Presto, нет состояния для сохранения и восстановления, и, следовательно, более быстрое переключение контекста. (Это то, что имел в виду режим , это просто означало, что FPU был включен.)
Если программа попытается выполнить операцию FPU, программа попадет в ядро, ядро включит FPU, восстановит любое сохраненное состояние, которое может уже существовать, а затем вернется, чтобы повторно выполнить операцию FPU.
Во время переключения контекста он знает, что нужно выполнить логику сохранения состояния. (А затем он может снова выключить FPU.)
Кстати, я считаю, что объяснение в книге причины, по которой ядра (и не только Linux) избегают операций FPU, ... не совсем точное. 1
Ядро может замкнуться в себе и делает это для многих вещей. (Таймеры, сбои страниц, прерывания устройств и т. Д.) Настоящая причина в том, что ядру не особенно нужны операции FPU, а также оно должно работать на архитектурах без FPU вообще. Следовательно, он просто избегает сложности и времени выполнения, необходимых для управления его собственным контекстом FPU, не выполняя операций, для которых всегда есть другие программные решения.
Интересно отметить, как часто состояние FPU нужно было бы сохранять, если бы ядро хотело использовать FP . . . каждый системный вызов, каждое прерывание, каждое переключение между потоками ядра. Даже если время от времени требовалось ядро FP, 2 вероятно , было бы быстрее сделать это в программном обеспечении.
1. То есть коренная ошибка.
2. Я знаю несколько случаев, когда программное обеспечение ядра содержит арифметическую реализацию с плавающей запятой . Некоторые архитектуры реализуют традиционные операции FPU на аппаратном уровне, но оставляют некоторые сложные операции IEEE FP программному обеспечению. (Подумайте: денормальная арифметика.) Когда случается какой-то странный угловой случай IEEE, они перехватывают программное обеспечение, которое содержит педантично правильную эмуляцию операций, которые могут перехватывать.
источник
В некоторых конструкциях ядра регистры с плавающей запятой не сохраняются при переключении задачи «ядра» или «системы». (Это связано с тем, что регистры FP имеют большой размер и для их сохранения требуется как время, так и пространство.) Поэтому, если вы попытаетесь использовать FP, значения будут случайным образом изменяться "пуф".
Вдобавок некоторые аппаратные схемы с плавающей запятой полагаются на ядро для обработки «необычных» ситуаций (например, деление нуля) через ловушку, и требуемый механизм ловушки может быть на более высоком «уровне», чем задача ядра, выполняемая в настоящее время.
По этим причинам (и еще нескольким) некоторые аппаратные схемы FP будут перехватывать, когда вы впервые используете инструкцию FP в задаче. Если вам разрешено использовать FP, то в задаче включен флаг с плавающей запятой, если нет, вас расстреляют.
источник
kernel_fpu_begin()
/kernel_fpu_end()
до / после вашего кода, чтобы запустить сохранение / восстановление состояния FPU в пользовательском пространстве (и я предполагаю, что состояние FPU вашего ядра против упреждения).