Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (~/so2/linux/tools/labs
).
Pașii de rezolvare sunt următorii:
Scheletul de laborator este generat din sursele din directorul tools/labs/templates
. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda:
tools/labs $ make skels
Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu LABS
:
tools/labs $ make clean tools/labs $ LABS=<lab name> make skels
device_model
.
Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea <lab_name>/<task_name>
variabilei LABS
.
tools/labs/skels
.
Comanda make build
compilează toate modulele din directorul skels
.
student@eg106:~/so2/linux/tools/labs$ make build echo "# autogenerated, do not edit " > skels/Kbuild echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild for i in ./device_model; do echo "obj-m += $i/" >> skels/Kbuild; done ...
Putem copia modulele generate pe mașina virtuală folosind target-ul copy
al comenzii make, atunci când mașina virtuală este oprită.
student@eg106:~/so2/linux/tools/labs$ make copy student@eg106:~/so2/linux/tools/labs$ make boot
Alternativ, putem copia fișierele prin scp
, pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți Interacțiunea cu mașina virtuală.
Modulele generate sunt copiate pe mașina virtuală în directorul /home/root/skels/<lab_name>
.
root@qemux86:~/skels/device_model# ls bex.ko bex_misc.ko
După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în minicom
) pentru a încărca și descărca modulul de kernel:
root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko
Ctrl+Shift+t
. Cele trei tab-uri de terminal îndeplinesc următoarele roluri:
~/so2/linux/tools/labs
.~/so2/linux/
cu sursele nucleului unde putem folosi Vim și cscope pentru parcurgerea codului sursă.student@eg106-pc:~$ netcat -lup 6666
git pull --rebase
in directorul ~/so2/linux
, pentru a obține ultima versiune a scheletului de laborator.
Vă mulțumim! Găsiți definițiile următoarelor simboluri în nucleul Linux:
dev_name
, dev_set_name
.pnp_device_probe
, pnp_bus_match
, pnp_register_driver
și variabila pnp_bus_type
.Apreciem opinia voastră legată de activitățile cursului de SO2. Ne ajută să îmbunătățim cursul și să facem materia cât mai accesibilă și interesantă. Pentru această vă rugăm să completați formularul de feedback de pe cs.curs.pub.ro (trebuie să fiți autentificați și înrolați în cadrul cursului). Vă mulțumim!
Analizați conținutul fișierului bex.c
, care conține implementarea unui driver de magistrală. Urmăriți comentariile marcate cu TODO 1
pentru a implementa părțile ce lipsesc: înregistrați driverul de magistrală și adăugați un nou device, numit root
, cu tipul none
și versiunea 1
.
bex_add_dev()
.
bus_register()
și bus_unregister()
.
Compilați, copiați modulul pe mașina virtuală, încărcați-l în kernel și verificați faptul că dispozitivul de tip magistrală este vizibil în /sys/bus
. De asemenea, verificați că dispozitivul este vizibil în /sys/bus/bex/devices.
.
Eliminați modulul și observați că intrările din sysfs
sunt eliminate.
Adăugați două atribute read-only: type
și version
. Urmăriți comentariile marcate cu TODO 2
.
type
și version
în structura bex_dev_attrs
pe modelul:
&dev_attr_<insert-attribute-type-here>.attr,
Observați că cele două atribute noi sunt vizibile în /sys/bus/bex/devices/root
. Verificați conținutul acestor atribute.
O implementare pentru funcția de afișare de type este
static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bex_device *bex_dev = to_bex_device(dev); return sprintf(buf, "%s\n", bex_dev->type); } DEVICE_ATTR_RO(type);
Adăugați două atribute write-only, numite del
și add
. del
așteaptă un nume de device pentru a îl elimina, iar add
așteaptă numele, tipul și versiunea pentru a crea un device nou. Urmăriți comentariile marcate cu TODO 3
.
del
și add
în structura bex_bus_attr
pe modelul:
&bus_attr_<insert-attribute-name-here>.attr,
sscanf
pentru a parsa inputul de la sysfs
și bex_del_dev()
and bex_add_dev()
pentru a șterge și crea un device nou.
Un exemplu de funcție de tipul store
este:
static ssize_t add_store(struct bus_type *bt, const char *buf, size_t count) { char type[32], name[32]; int version; int ret; ret = sscanf(buf, "%31s %31s %d", name, type, &version); if (ret != 3) return -EINVAL; return bex_add_dev(name, type, version) ? : count; } BUS_ATTR(add, S_IWUSR, NULL, add_store);
Creați un device nou și verificați dacă este vizibil în /sys/bus/bex/devices
. Eliminați-l și verificați că a dispărut din sysfs
.
echo
pentru a scrie în atributele magistralei:
$ echo "name type 1" > /sys/bus/bex/add $ echo "name" > /sys/bus/bex/del
Modificați fișierul bex-misc.c
pentru a înregistra driver-ul la magistrala bex
.
Inserați modulul bex_misc.ko și creați un nou device de tip bex
din sysfs
, cu numele Test, tipul misc și versiunea 2. Urmăriți comentariile marcate cu TODO 4
.
Verificați dacă noul driver este vizibil în /sys/bus/bex/drivers
.
De ce nu este apelată funcția probe
?
match
pentru magistrală nu este implementată în bex.c
.
Implementați funcția pentru match în fișierul bex.c
. Urmăriți comentariile marcate cu TODO 5
.
Încercați din nou adăugarea unui dispozitiv de tip bex
și observați că de data aceasta funcția de probe
este apelată.
Modificați bex_misc.c
astfel încât operația probe
să eșueze dacă version > 1
. Înregistrați device-ul misc în funcția bex_misc_probe()
și deînregistrați-l în bex_misc_remove
. Urmăriți comentariile marcate cu TODO 6
.
misc_register()
and misc_deregister()
.
Creați un device nou cu numele test, tipul misc și versiunea 2 și verificați că operația probe
eșuează.
Creați un nou device cu numele test, tipul misc și versiunea 1 și verificați că operația se termină cu succes.
Verificați conținutul fișierului /sys/bus/bex/devices/test
și observați că există o nouă intrare. Identificați majorul și minorul pentru device-ul misc
, creați un device node de tip caracter pentru acest dispozitiv (Hint
: mknod) și încercați operații de citire și scriere pe fișierul creat, pentru a accesa buffer-ul dispozitivului.
major
și minor
sunt vizibili în atributul dev
al dispozitivului de tip misc
.
Folosiți comanda udevadm
și observați ce se întâmplă când:
bex.ko
and bex_misc.ko
sunt inserate