Ответ 1
Множество отливок типа просто "хорошо работают". Однако это не очень строго. Ничто не мешает вам отбрасывать u32
в u32 *
и разыгрывать его, но это не соответствует API ядра и подвержено ошибкам.
__iomem
- это файл cookie, используемый Sparse, инструментом, используемым для поиска возможных ошибок кодирования в ядре. Если вы не скомпилируете код ядра с включенным Sparse, __iomem
все равно будет проигнорирован.
Используйте Sparse, предварительно установив его, а затем добавив C=1
в ваш вызов. Например, при создании модуля используйте:
make -C $KPATH M=$PWD C=1 modules
__iomem
определяется следующим образом:
# define __iomem __attribute__((noderef, address_space(2)))
Добавление (и требование) cookie типа __iomem
для всех доступов ввода/вывода - это способ быть более строгим и избегать ошибок программирования. Вы не хотите читать/записывать из/в области памяти ввода/вывода с абсолютными адресами, потому что вы обычно используете виртуальную память. Таким образом,
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
обычно вызывается для получения виртуального адреса физического адреса ввода-вывода offset
для указанной длины size
в байтах. ioremap()
возвращает указатель с cookie __iomem
, поэтому теперь его можно использовать с встроенными функциями, такими как readl()
/writel()
(хотя теперь предпочтительнее использовать более явные макросы ioread32()
/iowrite32()
, для пример), которые принимают адреса __iomem
.
Кроме того, атрибут noderef
используется Sparse, чтобы убедиться, что вы не разыгрываете указатель __iomem
. Разделение должно работать над некоторой архитектурой, где ввод-вывод действительно отображен в памяти, но другие архитектуры используют специальные инструкции для доступа к входам и выводам, и в этом случае разыменование не будет работать.
Посмотрим на пример:
void *io = ioremap(42, 4);
Разреженный не нравится:
warning: incorrect type in initializer (different address spaces)
expected void *io
got void [noderef] <asn:2>*
Или:
u32 __iomem* io = ioremap(42, 4);
pr_info("%x\n", *io);
Разреженный тоже не рад:
warning: dereference of noderef expression
В последнем примере первая строка верна, потому что ioremap()
возвращает свое значение переменной __iomem
. Но тогда мы это уважаем, и мы не должны этого делать.
Это облегчает работу Sparse:
void __iomem* io = ioremap(42, 4);
pr_info("%x\n", ioread32(io));
Нижняя строка: всегда используйте __iomem
, где это необходимо (как тип возврата или как тип параметра), и используйте Sparse, чтобы убедиться, что вы это сделали. Также: не разыщите указатель __iomem
.
Изменить. Здесь отличная статья LWN о начале __iomem
и ее использовании.