Dużo odlewów po prostu "działa dobrze". Jednak nie jest to bardzo surowe. Nic nie stoi na przeszkodzie, aby rzucić kod u32
na adres u32 *
i usunąć go, ale nie jest to zgodne z interfejsem API jądra i jest podatne na błędy.
__iomem
to plik cookie używany przez Sparse, narzędzie służące do wyszukiwania ewentualnych błędów kodowania w jądrze. Jeśli nie skompilujesz swojego kodu jądra przy włączonej funkcji Sparse, __iomem
i tak zostanie zignorowane.
Użyj Sparse, najpierw instalując go, a następnie dodając C=1
do swojego wywołania make. Na przykład, gdy buidling modułu za pomocą:
make -C $KPATH M=$PWD C=1 modules
__iomem
jest zdefiniowany w następujący sposób:
# define __iomem __attribute__((noderef, address_space(2)))
Dodawanie (i wymagające) ciastko jak __iomem
dla wszystkich I/O dostęp jest sposób być bardziej rygorystyczny i unikać błędów programowania. Nie chcesz odczytywać/zapisywać z/do regionów pamięci I/O z adresami bezwzględnymi, ponieważ zazwyczaj używasz pamięci wirtualnej. Zatem
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
nazywa się zwykle uzyskać wirtualny adres I/O adresu fizycznego offset
, na określonej długości size
w bajtach. ioremap()
zwraca wskaźnik z krytym __iomem
ciasteczka, więc może teraz być używane z funkcjami inline jak readl()
/writel()
(choć jest to teraz zaleca się stosowanie bardziej wyraźne makr ioread32()
/iowrite32()
, na przykład), które akceptują __iomem
adresy.
Ponadto, atrybut Sparse używa atrybutu noderef
, aby upewnić się, że nie zinterpretowano wskaźnika __iomem
. Dereferencje powinny działać w niektórych architekturach, w których wejścia/wyjścia są rzeczywiście mapowane na pamięć, ale inne architektury używają specjalnych instrukcji dostępu do operacji we/wy iw tym przypadku dereferencje nie będą działać. wygląd
Miejmy na przykład:
void *io = ioremap(42, 4);
Rzadki nie jest zadowolony:
warning: incorrect type in initializer (different address spaces)
expected void *io
got void [noderef] <asn:2>*
Lub:
u32 __iomem* io = ioremap(42, 4);
pr_info("%x\n", *io);
Rzadki nie jest zadowolony albo:
warning: dereference of noderef expression
W ostatnim przykładzie pierwsza linia jest poprawna, ponieważ ioremap()
zwraca jej wartość do zmiennej .Ale potem to oceniamy i nie powinniśmy.
To sprawia Sparse szczęśliwa:
void __iomem* io = ioremap(42, 4);
pr_info("%x\n", ioread32(io));
Konkluzja: zawsze używać __iomem
gdzie jest to wymagane (jako typ zwracany lub jako typ parametru) i używać Rzadki, aby upewnić się, że tak zrobiliśmy. Ponadto: nie usuwaj zaznaczenia wskaźnika __iomem
.
Edit: Oto wielki LWN article temat powstania __iomem
i funkcjami, używając go.