API jądra do obsługi przestrzeni użytkownika Co jest tematem tej prezentacji: Transport danych pomiędzy przestrzeniami użytkownika i jądra (asm/uaccess.h) Komunikacja modułu jądra z procesami użytkownika przez system plików /proc Przykład modułu korzystającego z oraz
asm/uaccess.h Służy do kopiowania danych pomiędzy przestrzenią użytkownika, a przestrzenią jądra systemu. Z tych funkcji możemy korzystać tylko będąc wewnątrz jądra. Jest to API dla modułów jądra. Dlaczego musimy specjalnie importować dane do pamięci jądra? Czyż jądro nie ma dostępu do całej pamięci od razu? Najważniejsze funkcje z : unsigned long copy_from_user (void* to, const void __user* from, unsigned long n) unsigned long copy_to_user (void __user* to, const void* from, unsigned long n) Analogicznie dla pojedyńczych zmiennych mamy zdefiniowane makra: get_user ( x, ptr ) put_user ( x, ptr )
Jak działa system plików /proc Zawartość plików w katalogu /proc generowana dynamicznie przez moduły jądra przy próbie odczytu. Nie należy się sugerować rozmiarem plików zwracanym przez stat, ls itp. Tak naprawdę zawartość pliku nie musi istnieć w żadnej z pamięci komputera. Możliwa komunikacja w obie strony kernel user
Struktura proc_dir_entry Każdy plik i katalog w systemie plików procfs ma swój egzemplarz struktury proc_dir_entry Wybrane składowe struktury proc_dir_entry: char* name – nazwa pliku/katalogu opisywanego przez daną strukturę mode_t mode – prawa dostępu do pliku(na przykład 644) read_proc_t* read_proc – wskaźnik na funkcję, która obsługuje odczyt pliku (przez użytkownika) write_proc_t* write_proc – wskaźnik na funkcję, która obsługuje zapis do pliku (dokonywany przez użytkownika)
API zawarte w pliku linux/proc_fs.h Funkcje, które trzeba znać: proc_dir_entry* create_proc_entry (name, mode, parent) proc_dir_entry* proc_mkdir (name, parent) void remove_proc_entry (name, parent) Typy argumentów powyższych funkcji: const char * name; mode_t mode; struct proc_dir_entry* parent; // można ustawić na NULL
Przykładowy moduł komunikujący się z przestrzenią użytkownika przez procfs cz. 1 #include int init(void) { struct proc_dir_entry *proc_test,*proc_test_hello; proc_test = proc_mkdir("test", NULL); proc_test_hello = create_proc_entry("test/hello",0777,NULL); proc_test_hello->read_proc=read_proc; proc_test_hello->write_proc=write_proc; return 0; } void cleanup(void) { remove_proc_entry("test/hello", NULL); remove_proc_entry("test", NULL); } module_init(init); module_exit(cleanup);
Funkcje read_proc oraz write_proc typedef int (read_proc_t)(char *buffer, char **start, off_t off, int count, int *eof, void *data); Interesują nas tylko argumenty buffer, count oraz offset. buffer - wskaźnik do bufora, do którego mamy wpisać zawartość naszego pliku użytkownikowi; Uwaga! Ten bufor nie jest w przestrzeni użytkownika, tylko w przestrzeni jądra. count – określa pojemność tego bufora off – pozycja w pliku od której użytkownik chce odczytywać dane wartość zwracana – oznacza ile bajtów umieściliśmy w buforze; Jeśli zwrócimy 0, to użytkownik dostanie informację o osiągnięciu końca pliku. typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data); Interesują nas tylko argumenty buffer oraz count. buffer - wskazuje na bufor w przestrzeni użytkownika, z którego mamy pobrać dane count – rozmiar tego bufora wartość zwracana – ile bajtów udało nam się zapisać do pliku; Jeśli będziemy zwracać cały czas 0 to program użytkownika wejdzie w nieskończoną pętlę.
Przykładowy moduł komunikujący się z przestrzenią użytkownika przez procfs cz. 2 char BUFOR[]="Witaj świecie!\n"; int read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data) { int to_copy = count>sizeof(BUFOR) ? sizeof(BUFOR) : count; if(off>0) return 0; memcpy(buffer,BUFOR,to_copy); return to_copy; } int write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) { int to_copy= count>sizeof(BUFOR) ? sizeof(BUFOR) : count; copy_from_user(BUFOR,buffer,to_copy); return to_copy; }
Bibliografia User Space Memory Access The Linux Kernel Module Programming Guide Chapter 5