2015-04-01 16 views
6

Piszę sterownik jądra Linux i dla każdej funkcji, która wysyła dane do przestrzeni użytkownika lub czyta dane z przestrzeni użytkownika, używam copy_to_user() i copy_from_user(). Moje pytanie brzmi: czy muszę używać tych wywołań, jeśli właśnie kopiuję podstawowy typ danych, taki jak u32 lub int?copy_to_user() i copy_from_user() dla podstawowego typu danych

+0

Istnieje pewne zamieszanie związane z tym, o co prosisz. Pomocna byłaby funkcja deklaracji funkcji, pokazująca, czy przekazujesz 'int' lub wskaźnik do' int'. Dwie dotychczasowe odpowiedzi oparte są na dwóch różnych interpretacjach twojego pytania. –

Odpowiedz

7

Jeśli funkcja odbiera wskaźnik danych w przestrzeni użytkownika, trzeba użyć copy_from_user() skopiować wskazywanego przez nie danych z przestrzeni użytkownika do przestrzeni jądra (i vice versa).

pamiętać, że wartość wskaźnika sama jest przekazywane przez wartość (jak wszystkie parametry C), więc nie trzeba robić copy_from_user() do uzyskania wartości wskaźnika, zanim będzie można copy_from_user() dane to wskazuje.

Argumenty numeryczne działają tak samo, jak argumenty wskaźnika; w kategoriach C, oba są skalarami. Nie musisz używać copy_from_user(), aby skopiować wartość parametru; to już zostało skopiowane. Wystarczy użyć go do skopiowania danych wskazywanych przez przekazany wskaźnik. Jeśli masz parametr typu int, możesz go użyć bezpośrednio. Jeśli twój parametr wskazuje na int, to obiekt int będzie znajdować się w przestrzeni użytkownika i musisz użyć wartości copy_to_user, aby skopiować wartość tego obiektu do przestrzeni jądra.

+0

Nie zgadzam się z tobą. przypuszczam, że wskaźnik w przestrzeni użytkownika nie jest wyrównany do strony i musisz zmontować obie części wskaźnika, aby go skompletować? Jedyną rzeczą, jaką użytkownik otrzymuje od użytkownika już jako parametr do wywołania, jest wskaźnik użytkownika, ale jeśli wskazuje na inny wskaźnik użytkownika, wskaźnik ten musi zostać pozyskany za pomocą user_copy. W środowiskach 64-bitowych wskaźnik użytkownika ma szerokość 8 bajtów i może być podzielony na granicy strony, więc musisz uzyskać dostęp do wirtualnych tabel stron, aby przetłumaczyć je z przestrzeni użytkownika na jądro. Również strony przestrzeni użytkownika mogą zostać zamienione, więc bądź ostrożny z tym również. –

+0

Kiedy mówisz, że wskaźnik nie jest wyrównany do strony, masz na myśli, że sam obiekt wskaźnika jest źle wyrównany lub dane, na które wskazuje? Wskaźniki są skalarami i zawsze przekazywane są według wartości. Jeśli wywołanie systemowe ma, powiedzmy, parametr 'void *', funkcja jądra obsługująca wywołanie systemowe otrzymuje * kopię * wskaźnika; wyrównanie obiektu wskaźnika po stronie wywołującej jest nieistotne. –

+0

Dla wskaźników prostych typów danych (takich jak 'int *'), można także użyć 'put_user' i' get_user'. – holgac

2

Gdy użytkownik przekazuje dane do przestrzeni jądra, dane te można podzielić na kilka stron, a te strony mogą być nawet wymienione w zamienionej pamięci. W takich przypadkach musisz poczekać, aż jądro się zamieni na stronie i uzyskać dostęp do strony, na której znajdują się dane. W przypadku elementarnych typów danych (takich jak int lub pointers) prawdą jest również, że niektóre architektury (w szczególności x86 intel) nie zmuszają użytkownika do wyrównania danych, tak że nawet liczba całkowita może zostać podzielona wokół granicy strony. Możesz uzyskać dostęp do pierwszej części twojej liczby całkowitej, ale czekać na drugą, która zostanie zamieniona przez menedżera pamięci, zanim cała sprawa zostanie udostępniona.

Możesz zapisać niektóre obie wycieczki, umieszczając wszystkie dane użytkownika w strukturze, której wskaźnik jest przekazywany do jądra. Można copy_from_user go jako blok i zapisać dostępy (i działa na ryzyko bycia zablokowane kilka razy)

Tak, i jako zakończenie użyć funkcji nawet dla podstawowych typów, gdyż istnieje wiele z nich. Nie zakładaj nic o tym, gdzie mogą znajdować się dane użytkownika podczas pracy w trybie jądra. Masz do niego dostęp, ale adresy wirtualne jądra danych użytkownika nie mają nic wspólnego z wirtualnymi adresami widocznymi w trybie użytkownika.

+0

Luis: Myślę, że źle zinterpretowałeś PO. Wszystko, co OP stara się zrobić, to przekazanie pojedynczej wartości podstawowego typu danych. OP naprawdę pyta, czy możliwe jest przekazywanie podstawowych danych przez wartość, a nie przez odniesienie. Jak wskazywał @Keith, zwykle wskaźnik jest przekazywany, a wskaźnik IS jest przekazywany przez wartość, więc można uzyskać do niego bezpośredni dostęp. Jednak jeśli chcesz usunąć zaznaczenie wskaźnika użytkownika, musisz użyć funkcji copy_from_user() lub get_user(), gdy znajdujesz się w jądrze. –

+0

Przepraszam, ale jak mówi: * jeśli tylko kopiuję podstawowy typ danych, taki jak u32 lub int * oznacza kopiowanie, więc przypuszczam, że int jest przekazywane przez referencję (na przykład, aby zwrócić jakąś wartość) Oczywiście, że jeśli przekazuje wartość tylko do jądra (ale nie z powrotem do przestrzeni użytkownika), może to zrobić. Nie myślę o Ioctl's, gdzie to ma sens. Załóżmy, że próbuje "int a; write (fc, & a, sizeof a); '... –

+0

Oczywiście możesz ** użyć ** wskaźnika przekazanego do przestrzeni jądra w ** write (2) ** jako danych, ale bez większego sensu przy tworzeniu taki kierowca. Mówi * ... i dla każdej funkcji ... * –

Powiązane problemy