Разработка ядра Linux - Роберт Лав
Шрифт:
Интервал:
Закладка:
Порядок следования байтов
Порядок следования байтов (byte ordering) — это порядок, согласно которому байты расположены в машинном слове. Для разных процессоров может использоваться один из двух типов нумерации байтов в машинном слове: наименее значимый (самый младший) байт является либо самым первым (самым левым, left-most), либо самым последним (самым правым, right-most) в слове. Порядок байтов называется обратным (big-endian), если наиболее значимый (самый старший) байт хранится первым, а за ним идут байты в порядке убывания значимости. Порядок байтов называется прямым (little-endian), если наименее значимый (самый младший) байт хранится первым, а за ним следуют байты в порядке возрастания значимости.
Даже не пытайтесь основываться на каких-либо предположениях о порядке следования байтов при написании кода ядра (конечно, если код не предназначен для какой-либо конкретной аппаратной платформы). Операционная система 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, в файле <asm/byteorder.h> определена одна из двух констант __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, чтобы корректно определять интервалы времени. Это очень важно, потому что значение частоты системного таймера может отличаться не только для разных аппаратных платформ, но и для одной аппаратной платформы при использовании разных версий ядра.
Например, константа HZ для аппаратной платформы x86 сейчас равна 1000. Это значит, что прерывание таймера возникает 1000 раз в секунду, или каждую миллисекунду. Однако до серии ядер 2.6 для аппаратной платформы x86 значение константы HZ было равно 100. Для разных аппаратных платформ эти значения отличаются: для аппаратной платформы alpha константа HZ равна 1024, а для платформы ARM — 100.
Никогда нельзя сравнивать значение переменной jiffies с числом, таким как 1000, и думать, что это всегда будет означать одно и то же. Для получения интервалов времени необходимо всегда умножать или делить на константу HZ, как в следующем примере.
HZ /* одна секунда */
(2*HZ) /* две секунды */
(HZ/2) /* полсекунды */
(HZ/100) /* 10 мс */
(2*HZ/100) /* 20 мс */
Константа HZ определена в файле <asm/param.h>. Об этом подробно рассказано в главе 10, "Таймеры и управление временем".
Размер страницы памяти
При работе со страницами памяти никогда нельзя привязываться к конкретному размеру страницы. Программисты, которые разрабатывают для аппаратной платформы x86, часто делают ошибку, считая, что размер страницы всегда равен 4 Кбайта. Хотя это справедливо для платформы x86, для других аппаратных платформ размер станицы может быть другим. Некоторые аппаратные платформы поддерживают несколько размеров страниц! В табл. 19.1 приведен список размеров страниц памяти для всех поддерживаемых аппаратных платформ.
Таблица 19.4. Размеры страниц памяти для разных аппаратных платформ
Аппаратная платформа Значение PAGE_SHIFT Значение PAGE_SIZE alpha 13 8 Кбайт arm 12, 14, 15 4 Кбайт, 16 Кбайт, 32 Кбайт cris 13 8 Кбайт h8300 12 4 Кбайт i386 12 4 Кбайт ia64 12, 13, 14, 16 4 Кбайт, 8 Кбайт, 32 Кбайт, 64 Кбайт m68k 12, 13 4 Кбайт, 8 Кбайт m86knommu 12 4 Кбайт mips 12 4 Кбайт mips64 12 4 Кбайт parisc 12 4 Кбайт ppc 12 4 Кбайт ppc64 12 4 Кбайт s390 12 4 Кбайт sh 12 4 Кбайт spare 12,13 4 Кбайт, 8 Кбайт sparc64 13 8 Кбайт v850 12 4 Кбайт x86_64 12 4 КбайтПри работе со страницами памяти необходимо использовать константу PAGE_SIZE, которая содержит размер страницы памяти в байтах.