Даже не пытайтесь основываться на каких-либо предположениях о порядке следования байтов при написании кода ядра (конечно, если код не предназначен для какой-либо конкретной аппаратной платформы). Операционная система Linux поддерживает аппаратные платформы с обоими порядками байтов, включая и те машины, на которых используемый порядок байтов можно сконфигурировать на этапе загрузки системы, а общий код должен быть совместим с любым порядком байтов.
На рис. 19.1 показан пример обратного порядка следования байтов, а на рис. 19.2 — прямого порядка следования байтов.
Рис. 19.1. Обратный (big-endian) порядок следования байтов
Рис. 19.2. Прямей (little-endian) порядок следования байтов
Аппаратная платформа i386 использует прямой (little-endian) порядок байтов. Большинство других аппаратных платформ обычно использует обратный (big-endian) порядок.
Рассмотрим, что эти типы кодирования обозначают на практике и как выглядит двоичное представление числа 1027, которое хранится в виде четырехбайтового целочисленного типа данных.
00000000 00000000 00000100 00000011
Внутренние представления этого числа в памяти при использовании прямого и обратного порядка байтов отличаются, как это показано в табл. 19.3.
Таблица 19.3. Расположение данных в памяти для разных порядков следования байтов
Адрес | Обратный порядок | Прямой порядок |
---|---|---|
0 | 00000000 | 00000011 |
1 | 00000000 | 00000100 |
2 | 00000100 | 00000000 |
3 | 00000011 | 00000000 |
Обратите внимание на то, что для аппаратной платформы с обратным порядком байтов самый старший байт записывается в самый минимальный адрес памяти.
И наконец, еще один пример — фрагмент кода, который позволяет определить порядок байтов для той аппаратной платформы, на которой он выполняется.
int x = 1;
if (*(char*)&x == 1)
/* прямой порядок */
else
/* обратный порядок */
Этот пример работает как в ядре, так и в пространстве пользователя.
История терминов big-endian и little-endian
Термины big-endian и little-endian заимствованы из сатирического романа Джонатана Свифта "Путешествие Гулливера", который был издан в 1726 году. В этом романс наиболее важной политической проблемой народа лилипутов была проблема, с какого конца следует разбивать яйцо: с тупого (big) или острого (little). Тех, кто предпочитал тупой конец называли "тупоконечниками" (big-endian), тех же, кто предпочитал острый конец, называли "остроконечниками" (little-endian).
Аналогия между дебатами лилипутов и спорами о том, какой порядок байтов лучше, говорит о том, что это вопрос больше политический, чем технический.
Порядок байтов в ядре
Для каждой аппаратной платформы, которая поддерживается ядром Linux, в файле
определена одна из двух констант __BIG_ENDIAN
или __LITTLE_ENDIAN
, в соответствии с используемым порядком байтов.
В этот заголовочный файл также включаются макросы из каталога include/linux/byteorder/
, которые помогают конвертировать один порядок байтов в другой. Ниже показаны наиболее часто используемые макросы.
u32 __cpu_to_be32(u32); /* преобразовать порядок байтов текущего
процессора в порядок big-endian */
u32 __cpu_to_le32(u32); /* преобразовать порядок байтов текущего
процессора в порядок little-endian */
u32 __be32_to_cpu(u32); /* преобразовать порядок байтов big-endian в
порядок байтов текущего процессора */
u32 __lе32_to_cpu(u32); /* преобразовать порядок байтов little-endian
в порядок байтов текущего процессора */
Эти макросы выполняют преобразование одного порядка байтов в другой. В случае когда порядки байтов, между которыми выполняется преобразование, одинаковы (например, если выполняется преобразование в обратный порядку байтов и процессор тоже использует такой же порядок), то эти макросы не делают ничего. В противном случае возвращается преобразованное значение.
Таймер
Никогда нельзя привязываться к какой-либо конкретной частоте генерации прерывания системного таймера и, соответственно, к тому, сколько раз в секунду изменяется переменная jiffies
. Всегда необходимо использовать константу HZ
, чтобы корректно определять интервалы времени. Это очень важно, потому что значение частоты системного таймера может отличаться не только для разных аппаратных платформ, но и для одной аппаратной платформы при использовании разных версий ядра.