]>
Commit | Line | Data |
---|---|---|
1497624f FV |
1 | .. include:: ../disclaimer-ita.rst |
2 | ||
3 | .. note:: Per leggere la documentazione originale in inglese: | |
4 | :ref:`Documentation/kernel-hacking/hacking.rst <kernel_hacking_hack>` | |
5 | ||
6 | :Original: :ref:`Documentation/kernel-hacking/hacking.rst <kernel_hacking_hack>` | |
7 | :Translator: Federico Vaga <federico.vaga@vaga.pv.it> | |
8 | ||
9 | .. _it_kernel_hacking_hack: | |
10 | ||
11 | ================================================= | |
12 | L'inaffidabile guida all'hacking del kernel Linux | |
13 | ================================================= | |
14 | ||
15 | :Author: Rusty Russell | |
16 | ||
17 | Introduzione | |
18 | ============ | |
19 | ||
20 | Benvenuto, gentile lettore, alla notevole ed inaffidabile guida all'hacking | |
21 | del kernel Linux ad opera di Rusty. Questo documento descrive le procedure | |
22 | più usate ed i concetti necessari per scrivere codice per il kernel: lo scopo | |
23 | è di fornire ai programmatori C più esperti un manuale di base per sviluppo. | |
24 | Eviterò dettagli implementativi: per questo abbiamo il codice, | |
25 | ed ignorerò intere parti di alcune procedure. | |
26 | ||
27 | Prima di leggere questa guida, sappiate che non ho mai voluto scriverla, | |
28 | essendo esageratamente sotto qualificato, ma ho sempre voluto leggere | |
29 | qualcosa di simile, e quindi questa era l'unica via. Spero che possa | |
30 | crescere e diventare un compendio di buone pratiche, punti di partenza | |
31 | e generiche informazioni. | |
32 | ||
33 | Gli attori | |
34 | ========== | |
35 | ||
36 | In qualsiasi momento ognuna delle CPU di un sistema può essere: | |
37 | ||
38 | - non associata ad alcun processo, servendo un'interruzione hardware; | |
39 | ||
40 | - non associata ad alcun processo, servendo un softirq o tasklet; | |
41 | ||
42 | - in esecuzione nello spazio kernel, associata ad un processo | |
43 | (contesto utente); | |
44 | ||
45 | - in esecuzione di un processo nello spazio utente; | |
46 | ||
47 | Esiste un ordine fra questi casi. Gli ultimi due possono avvicendarsi (preempt) | |
48 | l'un l'altro, ma a parte questo esiste una gerarchia rigida: ognuno di questi | |
49 | può avvicendarsi solo ad uno di quelli sottostanti. Per esempio, mentre un | |
50 | softirq è in esecuzione su d'una CPU, nessun altro softirq può avvicendarsi | |
51 | nell'esecuzione, ma un'interruzione hardware può. Ciò nonostante, le altre CPU | |
52 | del sistema operano indipendentemente. | |
53 | ||
54 | Più avanti vedremo alcuni modi in cui dal contesto utente è possibile bloccare | |
55 | le interruzioni, così da impedirne davvero il diritto di prelazione. | |
56 | ||
57 | Contesto utente | |
58 | --------------- | |
59 | ||
60 | Ci si trova nel contesto utente quando si arriva da una chiamata di sistema | |
61 | od altre eccezioni: come nello spazio utente, altre procedure più importanti, | |
62 | o le interruzioni, possono far valere il proprio diritto di prelazione sul | |
63 | vostro processo. Potete sospendere l'esecuzione chiamando :c:func:`schedule()`. | |
64 | ||
65 | .. note:: | |
66 | ||
67 | Si è sempre in contesto utente quando un modulo viene caricato o rimosso, | |
68 | e durante le operazioni nello strato dei dispositivi a blocchi | |
69 | (*block layer*). | |
70 | ||
71 | Nel contesto utente, il puntatore ``current`` (il quale indica il processo al | |
72 | momento in esecuzione) è valido, e :c:func:`in_interrupt()` | |
73 | (``include/linux/preempt.h``) è falsa. | |
74 | ||
75 | .. warning:: | |
76 | ||
77 | Attenzione che se avete la prelazione o i softirq disabilitati (vedere | |
78 | di seguito), :c:func:`in_interrupt()` ritornerà un falso positivo. | |
79 | ||
80 | Interruzioni hardware (Hard IRQs) | |
81 | --------------------------------- | |
82 | ||
83 | Temporizzatori, schede di rete e tastiere sono esempi di vero hardware | |
84 | che possono produrre interruzioni in un qualsiasi momento. Il kernel esegue | |
85 | i gestori d'interruzione che prestano un servizio all'hardware. Il kernel | |
86 | garantisce che questi gestori non vengano mai interrotti: se una stessa | |
87 | interruzione arriva, questa verrà accodata (o scartata). | |
88 | Dato che durante la loro esecuzione le interruzioni vengono disabilitate, | |
89 | i gestori d'interruzioni devono essere veloci: spesso si limitano | |
90 | esclusivamente a notificare la presa in carico dell'interruzione, | |
91 | programmare una 'interruzione software' per l'esecuzione e quindi terminare. | |
92 | ||
93 | Potete dire d'essere in una interruzione hardware perché :c:func:`in_irq()` | |
94 | ritorna vero. | |
95 | ||
96 | .. warning:: | |
97 | ||
98 | Attenzione, questa ritornerà un falso positivo se le interruzioni | |
99 | sono disabilitate (vedere di seguito). | |
100 | ||
101 | Contesto d'interruzione software: softirq e tasklet | |
102 | --------------------------------------------------- | |
103 | ||
104 | Quando una chiamata di sistema sta per tornare allo spazio utente, | |
105 | oppure un gestore d'interruzioni termina, qualsiasi 'interruzione software' | |
106 | marcata come pendente (solitamente da un'interruzione hardware) viene | |
107 | eseguita (``kernel/softirq.c``). | |
108 | ||
109 | La maggior parte del lavoro utile alla gestione di un'interruzione avviene qui. | |
110 | All'inizio della transizione ai sistemi multiprocessore, c'erano solo i | |
111 | cosiddetti 'bottom half' (BH), i quali non traevano alcun vantaggio da questi | |
112 | sistemi. Non appena abbandonammo i computer raffazzonati con fiammiferi e | |
113 | cicche, abbandonammo anche questa limitazione e migrammo alle interruzioni | |
114 | software 'softirqs'. | |
115 | ||
116 | Il file ``include/linux/interrupt.h`` elenca i differenti tipi di 'softirq'. | |
117 | Un tipo di softirq molto importante è il timer (``include/linux/timer.h``): | |
118 | potete programmarlo per far si che esegua funzioni dopo un determinato | |
119 | periodo di tempo. | |
120 | ||
121 | Dato che i softirq possono essere eseguiti simultaneamente su più di un | |
122 | processore, spesso diventa estenuante l'averci a che fare. Per questa ragione, | |
123 | i tasklet (``include/linux/interrupt.h``) vengo usati più di frequente: | |
124 | possono essere registrati dinamicamente (il che significa che potete averne | |
125 | quanti ne volete), e garantiscono che un qualsiasi tasklet verrà eseguito | |
126 | solo su un processore alla volta, sebbene diversi tasklet possono essere | |
127 | eseguiti simultaneamente. | |
128 | ||
129 | .. warning:: | |
130 | ||
131 | Il nome 'tasklet' è ingannevole: non hanno niente a che fare | |
132 | con i 'processi' ('tasks'), e probabilmente hanno più a che vedere | |
133 | con qualche pessima vodka che Alexey Kuznetsov si fece a quel tempo. | |
134 | ||
135 | Potete determinate se siete in un softirq (o tasklet) utilizzando la | |
136 | macro :c:func:`in_softirq()` (``include/linux/preempt.h``). | |
137 | ||
138 | .. warning:: | |
139 | ||
140 | State attenti che questa macro ritornerà un falso positivo | |
141 | se :ref:`botton half lock <it_local_bh_disable>` è bloccato. | |
142 | ||
143 | Alcune regole basilari | |
144 | ====================== | |
145 | ||
146 | Nessuna protezione della memoria | |
147 | Se corrompete la memoria, che sia in contesto utente o d'interruzione, | |
148 | la macchina si pianterà. Siete sicuri che quello che volete fare | |
149 | non possa essere fatto nello spazio utente? | |
150 | ||
151 | Nessun numero in virgola mobile o MMX | |
152 | Il contesto della FPU non è salvato; anche se siete in contesto utente | |
153 | lo stato dell'FPU probabilmente non corrisponde a quello del processo | |
154 | corrente: vi incasinerete con lo stato di qualche altro processo. Se | |
155 | volete davvero usare la virgola mobile, allora dovrete salvare e recuperare | |
156 | lo stato dell'FPU (ed evitare cambi di contesto). Generalmente è una | |
157 | cattiva idea; usate l'aritmetica a virgola fissa. | |
158 | ||
159 | Un limite rigido dello stack | |
160 | A seconda della configurazione del kernel lo stack è fra 3K e 6K per la | |
161 | maggior parte delle architetture a 32-bit; è di 14K per la maggior | |
162 | parte di quelle a 64-bit; e spesso è condiviso con le interruzioni, | |
163 | per cui non si può usare. | |
164 | Evitare profonde ricorsioni ad enormi array locali nello stack | |
165 | (allocateli dinamicamente). | |
166 | ||
167 | Il kernel Linux è portabile | |
168 | Quindi mantenetelo tale. Il vostro codice dovrebbe essere a 64-bit ed | |
169 | indipendente dall'ordine dei byte (endianess) di un processore. Inoltre, | |
170 | dovreste minimizzare il codice specifico per un processore; per esempio | |
171 | il codice assembly dovrebbe essere incapsulato in modo pulito e minimizzato | |
172 | per facilitarne la migrazione. Generalmente questo codice dovrebbe essere | |
173 | limitato alla parte di kernel specifica per un'architettura. | |
174 | ||
175 | ioctl: non scrivere nuove chiamate di sistema | |
176 | ============================================= | |
177 | ||
178 | Una chiamata di sistema, generalmente, è scritta così:: | |
179 | ||
180 | asmlinkage long sys_mycall(int arg) | |
181 | { | |
182 | return 0; | |
183 | } | |
184 | ||
185 | Primo, nella maggior parte dei casi non volete creare nuove chiamate di | |
186 | sistema. | |
187 | Create un dispositivo a caratteri ed implementate l'appropriata chiamata ioctl. | |
188 | Questo meccanismo è molto più flessibile delle chiamate di sistema: esso non | |
189 | dev'essere dichiarato in tutte le architetture nei file | |
190 | ``include/asm/unistd.h`` e ``arch/kernel/entry.S``; inoltre, è improbabile | |
191 | che questo venga accettato da Linus. | |
192 | ||
193 | Se tutto quello che il vostro codice fa è leggere o scrivere alcuni parametri, | |
194 | considerate l'implementazione di un'interfaccia :c:func:`sysfs()`. | |
195 | ||
196 | All'interno di una ioctl vi trovate nel contesto utente di un processo. Quando | |
197 | avviene un errore dovete ritornare un valore negativo di errno (consultate | |
198 | ``include/uapi/asm-generic/errno-base.h``, | |
199 | ``include/uapi/asm-generic/errno.h`` e ``include/linux/errno.h``), altrimenti | |
200 | ritornate 0. | |
201 | ||
202 | Dopo aver dormito dovreste verificare se ci sono stati dei segnali: il modo | |
203 | Unix/Linux di gestire un segnale è di uscire temporaneamente dalla chiamata | |
204 | di sistema con l'errore ``-ERESTARTSYS``. La chiamata di sistema ritornerà | |
205 | al contesto utente, eseguirà il gestore del segnale e poi la vostra chiamata | |
206 | di sistema riprenderà (a meno che l'utente non l'abbia disabilitata). Quindi, | |
207 | dovreste essere pronti per continuare l'esecuzione, per esempio nel mezzo | |
208 | della manipolazione di una struttura dati. | |
209 | ||
210 | :: | |
211 | ||
212 | if (signal_pending(current)) | |
213 | return -ERESTARTSYS; | |
214 | ||
215 | Se dovete eseguire dei calcoli molto lunghi: pensate allo spazio utente. | |
216 | Se **davvero** volete farlo nel kernel ricordatevi di verificare periodicamente | |
217 | se dovete *lasciare* il processore (ricordatevi che, per ogni processore, c'è | |
218 | un sistema multi-processo senza diritto di prelazione). | |
219 | Esempio:: | |
220 | ||
221 | cond_resched(); /* Will sleep */ | |
222 | ||
223 | Una breve nota sulla progettazione delle interfacce: il motto dei sistemi | |
224 | UNIX è "fornite meccanismi e non politiche" | |
225 | ||
226 | La ricetta per uno stallo | |
227 | ========================= | |
228 | ||
229 | Non è permesso invocare una procedura che potrebbe dormire, fanno eccezione | |
230 | i seguenti casi: | |
231 | ||
232 | - Siete in un contesto utente. | |
233 | ||
234 | - Non trattenete alcun spinlock. | |
235 | ||
236 | - Avete abilitato le interruzioni (in realtà, Andy Kleen dice che | |
237 | lo schedulatore le abiliterà per voi, ma probabilmente questo non è quello | |
238 | che volete). | |
239 | ||
240 | Da tener presente che alcune funzioni potrebbero dormire implicitamente: | |
241 | le più comuni sono quelle per l'accesso allo spazio utente (\*_user) e | |
242 | quelle per l'allocazione della memoria senza l'opzione ``GFP_ATOMIC`` | |
243 | ||
244 | Dovreste sempre compilare il kernel con l'opzione ``CONFIG_DEBUG_ATOMIC_SLEEP`` | |
245 | attiva, questa vi avviserà se infrangete una di queste regole. | |
246 | Se **infrangete** le regole, allora potreste bloccare il vostro scatolotto. | |
247 | ||
248 | Veramente. | |
249 | ||
250 | Alcune delle procedure più comuni | |
251 | ================================= | |
252 | ||
253 | :c:func:`printk()` | |
254 | ------------------ | |
255 | ||
256 | Definita in ``include/linux/printk.h`` | |
257 | ||
258 | :c:func:`printk()` fornisce messaggi alla console, dmesg, e al demone syslog. | |
259 | Essa è utile per il debugging o per la notifica di errori; può essere | |
260 | utilizzata anche all'interno del contesto d'interruzione, ma usatela con | |
261 | cautela: una macchina che ha la propria console inondata da messaggi diventa | |
262 | inutilizzabile. La funzione utilizza un formato stringa quasi compatibile con | |
263 | la printf ANSI C, e la concatenazione di una stringa C come primo argomento | |
264 | per indicare la "priorità":: | |
265 | ||
266 | printk(KERN_INFO "i = %u\n", i); | |
267 | ||
268 | Consultate ``include/linux/kern_levels.h`` per gli altri valori ``KERN_``; | |
269 | questi sono interpretati da syslog come livelli. Un caso speciale: | |
270 | per stampare un indirizzo IP usate:: | |
271 | ||
272 | __be32 ipaddress; | |
273 | printk(KERN_INFO "my ip: %pI4\n", &ipaddress); | |
274 | ||
275 | ||
276 | :c:func:`printk()` utilizza un buffer interno di 1K e non s'accorge di | |
277 | eventuali sforamenti. Accertatevi che vi basti. | |
278 | ||
279 | .. note:: | |
280 | ||
281 | Saprete di essere un vero hacker del kernel quando inizierete a digitare | |
282 | nei vostri programmi utenti le printf come se fossero printk :) | |
283 | ||
284 | .. note:: | |
285 | ||
286 | Un'altra nota a parte: la versione originale di Unix 6 aveva un commento | |
287 | sopra alla funzione printf: "Printf non dovrebbe essere usata per il | |
288 | chiacchiericcio". Dovreste seguire questo consiglio. | |
289 | ||
290 | :c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()` | |
291 | --------------------------------------------------------------------------------------------------- | |
292 | ||
293 | Definite in ``include/linux/uaccess.h`` / ``asm/uaccess.h`` | |
294 | ||
295 | **[DORMONO]** | |
296 | ||
297 | :c:func:`put_user()` e :c:func:`get_user()` sono usate per ricevere ed | |
298 | impostare singoli valori (come int, char, o long) da e verso lo spazio utente. | |
299 | Un puntatore nello spazio utente non dovrebbe mai essere dereferenziato: i dati | |
300 | dovrebbero essere copiati usando suddette procedure. Entrambe ritornano | |
301 | ``-EFAULT`` oppure 0. | |
302 | ||
303 | :c:func:`copy_to_user()` e :c:func:`copy_from_user()` sono più generiche: | |
304 | esse copiano una quantità arbitraria di dati da e verso lo spazio utente. | |
305 | ||
306 | .. warning:: | |
307 | ||
308 | Al contrario di:c:func:`put_user()` e :c:func:`get_user()`, queste | |
309 | funzioni ritornano la quantità di dati copiati (0 è comunque un successo). | |
310 | ||
311 | [Sì, questa stupida interfaccia mi imbarazza. La battaglia torna in auge anno | |
312 | dopo anno. --RR] | |
313 | ||
314 | Le funzioni potrebbero dormire implicitamente. Queste non dovrebbero mai essere | |
315 | invocate fuori dal contesto utente (non ha senso), con le interruzioni | |
316 | disabilitate, o con uno spinlock trattenuto. | |
317 | ||
318 | :c:func:`kmalloc()`/:c:func:`kfree()` | |
319 | ------------------------------------- | |
320 | ||
321 | Definite in ``include/linux/slab.h`` | |
322 | ||
323 | **[POTREBBERO DORMIRE: LEGGI SOTTO]** | |
324 | ||
325 | Queste procedure sono utilizzate per la richiesta dinamica di un puntatore ad | |
326 | un pezzo di memoria allineato, esattamente come malloc e free nello spazio | |
327 | utente, ma :c:func:`kmalloc()` ha un argomento aggiuntivo per indicare alcune | |
328 | opzioni. Le opzioni più importanti sono: | |
329 | ||
330 | ``GFP_KERNEL`` | |
331 | Potrebbe dormire per librarare della memoria. L'opzione fornisce il modo | |
332 | più affidabile per allocare memoria, ma il suo uso è strettamente limitato | |
333 | allo spazio utente. | |
334 | ||
335 | ``GFP_ATOMIC`` | |
336 | Non dorme. Meno affidabile di ``GFP_KERNEL``, ma può essere usata in un | |
337 | contesto d'interruzione. Dovreste avere **davvero** una buona strategia | |
338 | per la gestione degli errori in caso di mancanza di memoria. | |
339 | ||
340 | ``GFP_DMA`` | |
341 | Alloca memoria per il DMA sul bus ISA nello spazio d'indirizzamento | |
342 | inferiore ai 16MB. Se non sapete cos'è allora non vi serve. | |
343 | Molto inaffidabile. | |
344 | ||
345 | Se vedete un messaggio d'avviso per una funzione dormiente che viene chiamata | |
346 | da un contesto errato, allora probabilmente avete usato una funzione | |
347 | d'allocazione dormiente da un contesto d'interruzione senza ``GFP_ATOMIC``. | |
348 | Dovreste correggerlo. Sbrigatevi, non cincischiate. | |
349 | ||
350 | Se allocate almeno ``PAGE_SIZE``(``asm/page.h`` o ``asm/page_types.h``) byte, | |
351 | considerate l'uso di :c:func:`__get_free_pages()` (``include/linux/gfp.h``). | |
352 | Accetta un argomento che definisce l'ordine (0 per per la dimensione di una | |
353 | pagine, 1 per una doppia pagina, 2 per quattro pagine, eccetra) e le stesse | |
354 | opzioni d'allocazione viste precedentemente. | |
355 | ||
356 | Se state allocando un numero di byte notevolemnte superiore ad una pagina | |
357 | potete usare :c:func:`vmalloc()`. Essa allocherà memoria virtuale all'interno | |
358 | dello spazio kernel. Questo è un blocco di memoria fisica non contiguo, ma | |
359 | la MMU vi darà l'impressione che lo sia (quindi, sarà contiguo solo dal punto | |
360 | di vista dei processori, non dal punto di vista dei driver dei dispositivi | |
361 | esterni). | |
362 | Se per qualche strana ragione avete davvero bisogno di una grossa quantità di | |
363 | memoria fisica contigua, avete un problema: Linux non ha un buon supporto per | |
364 | questo caso d'uso perché, dopo un po' di tempo, la frammentazione della memoria | |
365 | rende l'operazione difficile. Il modo migliore per allocare un simile blocco | |
366 | all'inizio dell'avvio del sistema è attraverso la procedura | |
367 | :c:func:`alloc_bootmem()`. | |
368 | ||
369 | Prima di inventare la vostra cache per gli oggetti più usati, considerate | |
370 | l'uso di una cache slab disponibile in ``include/linux/slab.h``. | |
371 | ||
372 | :c:func:`current()` | |
373 | ------------------- | |
374 | ||
375 | Definita in ``include/asm/current.h`` | |
376 | ||
377 | Questa variabile globale (in realtà una macro) contiene un puntatore alla | |
378 | struttura del processo corrente, quindi è valido solo dal contesto utente. | |
379 | Per esempio, quando un processo esegue una chiamata di sistema, questo | |
380 | punterà alla struttura dati del processo chiamate. | |
381 | Nel contesto d'interruzione in suo valore **non è NULL**. | |
382 | ||
383 | :c:func:`mdelay()`/:c:func:`udelay()` | |
384 | ------------------------------------- | |
385 | ||
386 | Definite in ``include/asm/delay.h`` / ``include/linux/delay.h`` | |
387 | ||
388 | Le funzioni :c:func:`udelay()` e :c:func:`ndelay()` possono essere utilizzate | |
389 | per brevi pause. Non usate grandi valori perché rischiate d'avere un | |
390 | overflow - in questo contesto la funzione :c:func:`mdelay()` è utile, | |
391 | oppure considerate :c:func:`msleep()`. | |
392 | ||
393 | :c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()` | |
394 | ----------------------------------------------------------------------------------------------- | |
395 | ||
396 | Definite in ``include/asm/byteorder.h`` | |
397 | ||
398 | La famiglia di funzioni :c:func:`cpu_to_be32()` (dove "32" può essere | |
399 | sostituito da 64 o 16, e "be" con "le") forniscono un modo generico | |
400 | per fare conversioni sull'ordine dei byte (endianess): esse ritornano | |
401 | il valore convertito. Tutte le varianti supportano anche il processo inverso: | |
402 | :c:func:`be32_to_cpu()`, eccetera. | |
403 | ||
404 | Queste funzioni hanno principalmente due varianti: la variante per | |
405 | puntatori, come :c:func:`cpu_to_be32p(), che prende un puntatore | |
406 | ad un tipo, e ritorna il valore convertito. L'altra variante per | |
407 | la famiglia di conversioni "in-situ", come :c:func:`cpu_to_be32s()`, | |
408 | che convertono il valore puntato da un puntatore, e ritornano void. | |
409 | ||
410 | :c:func:`local_irq_save()`/:c:func:`local_irq_restore()` | |
411 | -------------------------------------------------------- | |
412 | ||
413 | Definite in ``include/linux/irqflags.h`` | |
414 | ||
415 | Queste funzioni abilitano e disabilitano le interruzioni hardware | |
416 | sul processore locale. Entrambe sono rientranti; esse salvano lo stato | |
417 | precedente nel proprio argomento ``unsigned long flags``. Se sapete | |
418 | che le interruzioni sono abilite, potete semplicemente utilizzare | |
419 | :c:func:`local_irq_disable()` e :c:func:`local_irq_enable()`. | |
420 | ||
421 | .. _it_local_bh_disable: | |
422 | ||
423 | :c:func:`local_bh_disable()`/:c:func:`local_bh_enable()` | |
424 | -------------------------------------------------------- | |
425 | ||
426 | Definite in ``include/linux/bottom_half.h`` | |
427 | ||
428 | ||
429 | Queste funzioni abilitano e disabilitano le interruzioni software | |
430 | sul processore locale. Entrambe sono rientranti; se le interruzioni | |
431 | software erano già state disabilitate in precedenza, rimarranno | |
432 | disabilitate anche dopo aver invocato questa coppia di funzioni. | |
433 | Lo scopo è di prevenire l'esecuzione di softirq e tasklet sul processore | |
434 | attuale. | |
435 | ||
436 | :c:func:`smp_processor_id()` | |
437 | ---------------------------- | |
438 | ||
439 | Definita in ``include/linux/smp.h`` | |
440 | ||
441 | :c:func:`get_cpu()` nega il diritto di prelazione (quindi non potete essere | |
442 | spostati su un altro processore all'improvviso) e ritorna il numero | |
443 | del processore attuale, fra 0 e ``NR_CPUS``. Da notare che non è detto | |
444 | che la numerazione dei processori sia continua. Quando avete terminato, | |
445 | ritornate allo stato precedente con :c:func:`put_cpu()`. | |
446 | ||
447 | Se sapete che non dovete essere interrotti da altri processi (per esempio, | |
448 | se siete in un contesto d'interruzione, o il diritto di prelazione | |
449 | è disabilitato) potete utilizzare smp_processor_id(). | |
450 | ||
451 | ||
452 | ``__init``/``__exit``/``__initdata`` | |
453 | ------------------------------------ | |
454 | ||
455 | Definite in ``include/linux/init.h`` | |
456 | ||
457 | Dopo l'avvio, il kernel libera una sezione speciale; le funzioni marcate | |
458 | con ``__init`` e le strutture dati marcate con ``__initdata`` vengono | |
459 | eliminate dopo il completamento dell'avvio: in modo simile i moduli eliminano | |
460 | questa memoria dopo l'inizializzazione. ``__exit`` viene utilizzato per | |
461 | dichiarare che una funzione verrà utilizzata solo in fase di rimozione: | |
462 | la detta funzione verrà eliminata quando il file che la contiene non è | |
463 | compilato come modulo. Guardate l'header file per informazioni. Da notare che | |
464 | non ha senso avere una funzione marcata come ``__init`` e al tempo stesso | |
465 | esportata ai moduli utilizzando :c:func:`EXPORT_SYMBOL()` o | |
466 | :c:func:`EXPORT_SYMBOL_GPL()` - non funzionerà. | |
467 | ||
468 | ||
469 | :c:func:`__initcall()`/:c:func:`module_init()` | |
470 | ---------------------------------------------- | |
471 | ||
472 | Definite in ``include/linux/init.h`` / ``include/linux/module.h`` | |
473 | ||
474 | Molte parti del kernel funzionano bene come moduli (componenti del kernel | |
475 | caricabili dinamicamente). L'utilizzo delle macro :c:func:`module_init()` | |
476 | e :c:func:`module_exit()` semplifica la scrittura di codice che può funzionare | |
477 | sia come modulo, sia come parte del kernel, senza l'ausilio di #ifdef. | |
478 | ||
479 | La macro :c:func:`module_init()` definisce quale funzione dev'essere | |
480 | chiamata quando il modulo viene inserito (se il file è stato compilato come | |
481 | tale), o in fase di avvio : se il file non è stato compilato come modulo la | |
482 | macro :c:func:`module_init()` diventa equivalente a :c:func:`__initcall()`, | |
483 | la quale, tramite qualche magia del linker, s'assicura che la funzione venga | |
484 | chiamata durante l'avvio. | |
485 | ||
486 | La funzione può ritornare un numero d'errore negativo per scatenare un | |
487 | fallimento del caricamento (sfortunatamente, questo non ha effetto se il | |
488 | modulo è compilato come parte integrante del kernel). Questa funzione è chiamata | |
489 | in contesto utente con le interruzioni abilitate, quindi potrebbe dormire. | |
490 | ||
491 | ||
492 | :c:func:`module_exit()` | |
493 | ----------------------- | |
494 | ||
495 | ||
496 | Definita in ``include/linux/module.h`` | |
497 | ||
498 | Questa macro definisce la funzione che dev'essere chiamata al momento della | |
499 | rimozione (o mai, nel caso in cui il file sia parte integrante del kernel). | |
500 | Essa verrà chiamata solo quando il contatore d'uso del modulo raggiunge lo | |
501 | zero. Questa funzione può anche dormire, ma non può fallire: tutto dev'essere | |
502 | ripulito prima che la funzione ritorni. | |
503 | ||
504 | Da notare che questa macro è opzionale: se non presente, il modulo non sarà | |
505 | removibile (a meno che non usiate 'rmmod -f' ). | |
506 | ||
507 | ||
508 | :c:func:`try_module_get()`/:c:func:`module_put()` | |
509 | ------------------------------------------------- | |
510 | ||
511 | Definite in ``include/linux/module.h`` | |
512 | ||
513 | Queste funzioni maneggiano il contatore d'uso del modulo per proteggerlo dalla | |
514 | rimozione (in aggiunta, un modulo non può essere rimosso se un altro modulo | |
515 | utilizzo uno dei sui simboli esportati: vedere di seguito). Prima di eseguire | |
516 | codice del modulo, dovreste chiamare :c:func:`try_module_get()` su quel modulo: | |
517 | se fallisce significa che il modulo è stato rimosso e dovete agire come se | |
518 | non fosse presente. Altrimenti, potete accedere al modulo in sicurezza, e | |
519 | chiamare :c:func:`module_put()` quando avete finito. | |
520 | ||
521 | La maggior parte delle strutture registrabili hanno un campo owner | |
522 | (proprietario), come nella struttura | |
523 | :c:type:`struct file_operations <file_operations>`. | |
524 | Impostate questo campo al valore della macro ``THIS_MODULE``. | |
525 | ||
526 | ||
527 | Code d'attesa ``include/linux/wait.h`` | |
528 | ====================================== | |
529 | ||
530 | **[DORMONO]** | |
531 | ||
532 | Una coda d'attesa è usata per aspettare che qualcuno vi attivi quando una | |
533 | certa condizione s'avvera. Per evitare corse critiche, devono essere usate | |
534 | con cautela. Dichiarate una :c:type:`wait_queue_head_t`, e poi i processi | |
535 | che vogliono attendere il verificarsi di quella condizione dichiareranno | |
536 | una :c:type:`wait_queue_entry_t` facendo riferimento a loro stessi, poi | |
537 | metteranno questa in coda. | |
538 | ||
539 | Dichiarazione | |
540 | ------------- | |
541 | ||
542 | Potere dichiarare una ``wait_queue_head_t`` utilizzando la macro | |
543 | :c:func:`DECLARE_WAIT_QUEUE_HEAD()` oppure utilizzando la procedura | |
544 | :c:func:`init_waitqueue_head()` nel vostro codice d'inizializzazione. | |
545 | ||
546 | Accodamento | |
547 | ----------- | |
548 | ||
549 | Mettersi in una coda d'attesa è piuttosto complesso, perché dovete | |
550 | mettervi in coda prima di verificare la condizione. Esiste una macro | |
551 | a questo scopo: :c:func:`wait_event_interruptible()` (``include/linux/wait.h``). | |
552 | Il primo argomento è la testa della coda d'attesa, e il secondo è | |
553 | un'espressione che dev'essere valutata; la macro ritorna 0 quando questa | |
554 | espressione è vera, altrimenti ``-ERESTARTSYS`` se è stato ricevuto un segnale. | |
555 | La versione :c:func:`wait_event()` ignora i segnali. | |
556 | ||
557 | Svegliare una procedura in coda | |
558 | ------------------------------- | |
559 | ||
560 | Chiamate :c:func:`wake_up()` (``include/linux/wait.h``); questa attiverà tutti | |
561 | i processi in coda. Ad eccezione se uno di questi è impostato come | |
562 | ``TASK_EXCLUSIVE``, in questo caso i rimanenti non verranno svegliati. | |
563 | Nello stesso header file esistono altre varianti di questa funzione. | |
564 | ||
565 | Operazioni atomiche | |
566 | =================== | |
567 | ||
568 | Certe operazioni sono garantite come atomiche su tutte le piattaforme. | |
569 | Il primo gruppo di operazioni utilizza :c:type:`atomic_t` | |
570 | (``include/asm/atomic.h``); questo contiene un intero con segno (minimo 32bit), | |
571 | e dovete utilizzare queste funzione per modificare o leggere variabili di tipo | |
572 | :c:type:`atomic_t`. :c:func:`atomic_read()` e :c:func:`atomic_set()` leggono ed | |
573 | impostano il contatore, :c:func:`atomic_add()`, :c:func:`atomic_sub()`, | |
574 | :c:func:`atomic_inc()`, :c:func:`atomic_dec()`, e | |
575 | :c:func:`atomic_dec_and_test()` (ritorna vero se raggiunge zero dopo essere | |
576 | stata decrementata). | |
577 | ||
578 | Sì. Ritorna vero (ovvero != 0) se la variabile atomica è zero. | |
579 | ||
580 | Da notare che queste funzioni sono più lente rispetto alla normale aritmetica, | |
581 | e quindi non dovrebbero essere usate a sproposito. | |
582 | ||
583 | Il secondo gruppo di operazioni atomiche sono definite in | |
584 | ``include/linux/bitops.h`` ed agiscono sui bit d'una variabile di tipo | |
585 | ``unsigned long``. Queste operazioni prendono come argomento un puntatore | |
586 | alla variabile, e un numero di bit dove 0 è quello meno significativo. | |
587 | :c:func:`set_bit()`, :c:func:`clear_bit()` e :c:func:`change_bit()` | |
588 | impostano, cancellano, ed invertono il bit indicato. | |
589 | :c:func:`test_and_set_bit()`, :c:func:`test_and_clear_bit()` e | |
590 | :c:func:`test_and_change_bit()` fanno la stessa cosa, ad eccezione che | |
591 | ritornano vero se il bit era impostato; queste sono particolarmente | |
592 | utili quando si vuole impostare atomicamente dei flag. | |
593 | ||
594 | Con queste operazioni è possibile utilizzare indici di bit che eccedono | |
595 | il valore ``BITS_PER_LONG``. Il comportamento è strano sulle piattaforme | |
596 | big-endian quindi è meglio evitarlo. | |
597 | ||
598 | Simboli | |
599 | ======= | |
600 | ||
601 | All'interno del kernel, si seguono le normali regole del linker (ovvero, | |
602 | a meno che un simbolo non venga dichiarato con visibilita limitata ad un | |
603 | file con la parola chiave ``static``, esso può essere utilizzato in qualsiasi | |
604 | parte del kernel). Nonostante ciò, per i moduli, esiste una tabella dei | |
605 | simboli esportati che limita i punti di accesso al kernel. Anche i moduli | |
606 | possono esportare simboli. | |
607 | ||
608 | :c:func:`EXPORT_SYMBOL()` | |
609 | ------------------------- | |
610 | ||
611 | Definita in ``include/linux/export.h`` | |
612 | ||
613 | Questo è il classico metodo per esportare un simbolo: i moduli caricati | |
614 | dinamicamente potranno utilizzare normalmente il simbolo. | |
615 | ||
616 | :c:func:`EXPORT_SYMBOL_GPL()` | |
617 | ----------------------------- | |
618 | ||
619 | Definita in ``include/linux/export.h`` | |
620 | ||
621 | Essa è simile a :c:func:`EXPORT_SYMBOL()` ad eccezione del fatto che i | |
622 | simboli esportati con :c:func:`EXPORT_SYMBOL_GPL()` possono essere | |
623 | utilizzati solo dai moduli che hanno dichiarato una licenza compatibile | |
624 | con la GPL attraverso :c:func:`MODULE_LICENSE()`. Questo implica che la | |
625 | funzione esportata è considerata interna, e non una vera e propria interfaccia. | |
626 | Alcuni manutentori e sviluppatori potrebbero comunque richiedere | |
627 | :c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o | |
628 | interfacce. | |
629 | ||
630 | Procedure e convenzioni | |
631 | ======================= | |
632 | ||
633 | Liste doppiamente concatenate ``include/linux/list.h`` | |
634 | ------------------------------------------------------ | |
635 | ||
636 | Un tempo negli header del kernel c'erano tre gruppi di funzioni per | |
637 | le liste concatenate, ma questa è stata la vincente. Se non avete particolari | |
638 | necessità per una semplice lista concatenata, allora questa è una buona scelta. | |
639 | ||
640 | In particolare, :c:func:`list_for_each_entry()` è utile. | |
641 | ||
642 | Convenzione dei valori di ritorno | |
643 | --------------------------------- | |
644 | ||
645 | Per codice chiamato in contesto utente, è molto comune sfidare le convenzioni | |
646 | C e ritornare 0 in caso di successo, ed un codice di errore negativo | |
647 | (eg. ``-EFAULT``) nei casi fallimentari. Questo potrebbe essere controintuitivo | |
648 | a prima vista, ma è abbastanza diffuso nel kernel. | |
649 | ||
650 | Utilizzate :c:func:`ERR_PTR()` (``include/linux/err.h``) per codificare | |
651 | un numero d'errore negativo in un puntatore, e :c:func:`IS_ERR()` e | |
652 | :c:func:`PTR_ERR()` per recuperarlo di nuovo: così si evita d'avere un | |
653 | puntatore dedicato per il numero d'errore. Da brividi, ma in senso positivo. | |
654 | ||
655 | Rompere la compilazione | |
656 | ----------------------- | |
657 | ||
658 | Linus e gli altri sviluppatori a volte cambiano i nomi delle funzioni e | |
659 | delle strutture nei kernel in sviluppo; questo non è solo per tenere | |
660 | tutti sulle spine: questo riflette cambiamenti fondamentati (eg. la funzione | |
661 | non può più essere chiamata con le funzioni attive, o fa controlli aggiuntivi, | |
662 | o non fa più controlli che venivano fatti in precedenza). Solitamente a questo | |
663 | s'accompagna un'adeguata e completa nota sulla lista di discussone | |
664 | linux-kernel; cercate negli archivi. | |
665 | Solitamente eseguire una semplice sostituzione su tutto un file rendere | |
666 | le cose **peggiori**. | |
667 | ||
668 | Inizializzazione dei campi d'una struttura | |
669 | ------------------------------------------ | |
670 | ||
671 | Il metodo preferito per l'inizializzazione delle strutture è quello | |
672 | di utilizzare gli inizializzatori designati, come definiti nello | |
673 | standard ISO C99, eg:: | |
674 | ||
675 | static struct block_device_operations opt_fops = { | |
676 | .open = opt_open, | |
677 | .release = opt_release, | |
678 | .ioctl = opt_ioctl, | |
679 | .check_media_change = opt_media_change, | |
680 | }; | |
681 | ||
682 | Questo rende più facile la ricerca con grep, e rende più chiaro quale campo | |
683 | viene impostato. Dovreste fare così perché si mostra meglio. | |
684 | ||
685 | Estensioni GNU | |
686 | -------------- | |
687 | ||
688 | Le estensioni GNU sono esplicitamente permesse nel kernel Linux. Da notare | |
689 | che alcune delle più complesse non sono ben supportate, per via dello scarso | |
690 | sviluppo, ma le seguenti sono da considerarsi la norma (per maggiori dettagli, | |
691 | leggete la sezione "C Extensions" nella pagina info di GCC - Sì, davvero | |
692 | la pagina info, la pagina man è solo un breve riassunto delle cose nella | |
693 | pagina info). | |
694 | ||
695 | - Funzioni inline | |
696 | ||
697 | - Istruzioni in espressioni (ie. il costrutto ({ and }) ). | |
698 | ||
699 | - Dichiarate attributi di una funzione / variabile / tipo | |
700 | (__attribute__) | |
701 | ||
702 | - typeof | |
703 | ||
704 | - Array con lunghezza zero | |
705 | ||
706 | - Macro varargs | |
707 | ||
708 | - Aritmentica sui puntatori void | |
709 | ||
710 | - Inizializzatori non costanti | |
711 | ||
712 | - Istruzioni assembler (non al di fuori di 'arch/' e 'include/asm/') | |
713 | ||
714 | - Nomi delle funzioni come stringhe (__func__). | |
715 | ||
716 | - __builtin_constant_p() | |
717 | ||
718 | Siate sospettosi quando utilizzate long long nel kernel, il codice generato | |
719 | da gcc è orribile ed anche peggio: le divisioni e le moltiplicazioni non | |
720 | funzionano sulle piattaforme i386 perché le rispettive funzioni di runtime | |
721 | di GCC non sono incluse nell'ambiente del kernel. | |
722 | ||
723 | C++ | |
724 | --- | |
725 | ||
726 | Solitamente utilizzare il C++ nel kernel è una cattiva idea perché | |
727 | il kernel non fornisce il necessario ambiente di runtime e gli header file | |
728 | non sono stati verificati. Rimane comunque possibile, ma non consigliato. | |
729 | Se davvero volete usarlo, almeno evitate le eccezioni. | |
730 | ||
731 | NUMif | |
732 | ----- | |
733 | ||
734 | Viene generalmente considerato più pulito l'uso delle macro negli header file | |
735 | (o all'inizio dei file .c) per astrarre funzioni piuttosto che utlizzare | |
736 | l'istruzione di pre-processore \`#if' all'interno del codice sorgente. | |
737 | ||
738 | Mettere le vostre cose nel kernel | |
739 | ================================= | |
740 | ||
741 | Al fine d'avere le vostre cose in ordine per l'inclusione ufficiale, o | |
742 | anche per avere patch pulite, c'è del lavoro amministrativo da fare: | |
743 | ||
744 | - Trovare di chi è lo stagno in cui state pisciando. Guardare in cima | |
745 | ai file sorgenti, all'interno del file ``MAINTAINERS``, ed alla fine | |
746 | di tutti nel file ``CREDITS``. Dovreste coordinarvi con queste persone | |
747 | per evitare di duplicare gli sforzi, o provare qualcosa che è già stato | |
748 | rigettato. | |
749 | ||
750 | Assicuratevi di mettere il vostro nome ed indirizzo email in cima a | |
751 | tutti i file che create o che mangeggiate significativamente. Questo è | |
752 | il primo posto dove le persone guarderanno quando troveranno un baco, | |
753 | o quando **loro** vorranno fare una modifica. | |
754 | ||
755 | - Solitamente vorrete un'opzione di configurazione per la vostra modifica | |
756 | al kernel. Modificate ``Kconfig`` nella cartella giusta. Il linguaggio | |
757 | Config è facile con copia ed incolla, e c'è una completa documentazione | |
cd238eff | 758 | nel file ``Documentation/kbuild/kconfig-language.rst``. |
1497624f FV |
759 | |
760 | Nella descrizione della vostra opzione, assicuratevi di parlare sia agli | |
761 | utenti esperti sia agli utente che non sanno nulla del vostro lavoro. | |
762 | Menzionate qui le incompatibilità ed i problemi. Chiaramente la | |
763 | descrizione deve terminare con “if in doubt, say N” (se siete in dubbio, | |
764 | dite N) (oppure, occasionalmente, \`Y'); questo è per le persone che non | |
765 | hanno idea di che cosa voi stiate parlando. | |
766 | ||
767 | - Modificate il file ``Makefile``: le variabili CONFIG sono esportate qui, | |
768 | quindi potete solitamente aggiungere una riga come la seguete | |
769 | "obj-$(CONFIG_xxx) += xxx.o". La sintassi è documentata nel file | |
cd238eff | 770 | ``Documentation/kbuild/makefiles.rst``. |
1497624f FV |
771 | |
772 | - Aggiungete voi stessi in ``CREDITS`` se avete fatto qualcosa di notevole, | |
773 | solitamente qualcosa che supera il singolo file (comunque il vostro nome | |
774 | dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa | |
775 | che volete essere consultati quando vengono fatte delle modifiche ad un | |
776 | sottosistema, e quando ci sono dei bachi; questo implica molto di più | |
777 | di un semplice impegno su una parte del codice. | |
778 | ||
779 | - Infine, non dimenticatevi di leggere | |
780 | ``Documentation/process/submitting-patches.rst`` e possibilmente anche | |
781 | ``Documentation/process/submitting-drivers.rst``. | |
782 | ||
783 | Trucchetti del kernel | |
784 | ===================== | |
785 | ||
786 | Dopo una rapida occhiata al codice, questi sono i preferiti. Sentitevi liberi | |
787 | di aggiungerne altri. | |
788 | ||
789 | ``arch/x86/include/asm/delay.h``:: | |
790 | ||
791 | #define ndelay(n) (__builtin_constant_p(n) ? \ | |
792 | ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ | |
793 | __ndelay(n)) | |
794 | ||
795 | ||
796 | ``include/linux/fs.h``:: | |
797 | ||
798 | /* | |
799 | * Kernel pointers have redundant information, so we can use a | |
800 | * scheme where we can return either an error code or a dentry | |
801 | * pointer with the same return value. | |
802 | * | |
803 | * This should be a per-architecture thing, to allow different | |
804 | * error and pointer decisions. | |
805 | */ | |
806 | #define ERR_PTR(err) ((void *)((long)(err))) | |
807 | #define PTR_ERR(ptr) ((long)(ptr)) | |
808 | #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) | |
809 | ||
810 | ``arch/x86/include/asm/uaccess_32.h:``:: | |
811 | ||
812 | #define copy_to_user(to,from,n) \ | |
813 | (__builtin_constant_p(n) ? \ | |
814 | __constant_copy_to_user((to),(from),(n)) : \ | |
815 | __generic_copy_to_user((to),(from),(n))) | |
816 | ||
817 | ||
818 | ``arch/sparc/kernel/head.S:``:: | |
819 | ||
820 | /* | |
821 | * Sun people can't spell worth damn. "compatability" indeed. | |
822 | * At least we *know* we can't spell, and use a spell-checker. | |
823 | */ | |
824 | ||
825 | /* Uh, actually Linus it is I who cannot spell. Too much murky | |
826 | * Sparc assembly will do this to ya. | |
827 | */ | |
828 | C_LABEL(cputypvar): | |
829 | .asciz "compatibility" | |
830 | ||
831 | /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ | |
832 | .align 4 | |
833 | C_LABEL(cputypvar_sun4m): | |
834 | .asciz "compatible" | |
835 | ||
836 | ||
837 | ``arch/sparc/lib/checksum.S:``:: | |
838 | ||
839 | /* Sun, you just can't beat me, you just can't. Stop trying, | |
840 | * give up. I'm serious, I am going to kick the living shit | |
841 | * out of you, game over, lights out. | |
842 | */ | |
843 | ||
844 | ||
845 | Ringraziamenti | |
846 | ============== | |
847 | ||
848 | Ringrazio Andi Kleen per le sue idee, le risposte alle mie domande, | |
849 | le correzioni dei miei errori, l'aggiunta di contenuti, eccetera. | |
850 | Philipp Rumpf per l'ortografia e per aver reso più chiaro il testo, e | |
851 | per alcuni eccellenti punti tutt'altro che ovvi. Werner Almesberger | |
852 | per avermi fornito un ottimo riassunto di :c:func:`disable_irq()`, | |
853 | e Jes Sorensen e Andrea Arcangeli per le precisazioni. Michael Elizabeth | |
854 | Chastain per aver verificato ed aggiunto la sezione configurazione. | |
855 | Telsa Gwynne per avermi insegnato DocBook. |