Ich möchte die Programmierung des Linux-Kernels lernen.
Was wären die Ausgangspunkte dafür? Was könnten einige der einfacheren Probleme sein, die man angehen könnte?
Ich möchte die Programmierung des Linux-Kernels lernen.
Was wären die Ausgangspunkte dafür? Was könnten einige der einfacheren Probleme sein, die man angehen könnte?
**TODO** +editPic: Linux Kernel Developer -> (Ring Layer 0)
+addSection: Kernel Virtualization Engine
KERN_WARN_CODING_STYLE: Do not Loop unless you absolutely have to.
*Empfohlene Bücher für die _Uninitialisiert `void i`_**
"Die Menschen verstehen Bücher erst, wenn sie ein gewisses Maß an Leben haben, oder jedenfalls versteht kein Mensch ein tiefes Buch, bevor er nicht wenigstens einen Teil seines Inhalts gesehen und gelebt hat". -Ezra Pound
Eine Reise der tausend code-miles muss mit einem einzigen Schritt beginnen. Wenn Sie sich nicht sicher sind, mit welchem der folgenden Bücher Sie beginnen sollen, dann suchen Sie sich eines Ihrer Wahl aus. Nicht alle, die wandern, sind verloren. Wie alle Straßen sind letztlich mit der Autobahn verbunden werden Sie auf Ihrer Kernel-Reise im Laufe der Seiten neue Dinge entdecken, ohne auf Sackgassen zu stoßen, und sich schließlich mit dem code-set
. Lesen Sie mit wachem Geist und erinnern Sie sich: Code ist keine Literatur .
Was übrig bleibt, ist weder eine Sache, noch ein Gefühl, noch ein Bild, noch eine Erinnerung, noch eine Idee. Es ist eine Funktion. Ein Prozess irgendeiner Art. Ein Aspekt des Lebens, den man als eine Funktion von etwas "Größerem" beschreiben könnte. Und daher scheint es, dass es nicht wirklich "getrennt" von diesem Etwas ist anderem. So wie die Funktion eines Messers - etwas zu schneiden - nicht wirklich vom Messer selbst getrennt ist. von dem Messer selbst. Die Funktion kann im Moment in Gebrauch sein oder nicht, aber sie ist potenziell NIEMALS getrennt.
Solovay Strassen Derandomisierter Algorithmus für die Primzahlprüfung :
Lies nicht, um zu widersprechen und zu widerlegen; nicht, um zu glauben und für selbstverständlich zu halten; nicht, um zu reden und zu diskutieren; sondern um abzuwägen und zu überlegen. Einige Bücher sollen gekostet, andere geschluckt und einige wenige gekaut und verdaut werden: das heißt, einige Bücher sollen nur in Teilen gelesen werden, andere sollen gelesen werden, aber nicht neugierig, und einige wenige sollen ganz und mit Fleiß und Aufmerksamkeit gelesen werden.
static void tasklet_hi_action(struct softirq_action *a)
{
struct tasklet_struct *list;
local_irq_disable();
list = __this_cpu_read(tasklet_hi_vec.head);
__this_cpu_write(tasklet_hi_vec.head, NULL);
__this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head));
local_irq_enable();
while (list) {
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) {
if (!atomic_read(&t->count)) {
if (!test_and_clear_bit(TASKLET_STATE_SCHED,
&t->state))
BUG();
t->func(t->data);
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
}
local_irq_disable();
t->next = NULL;
*__this_cpu_read(tasklet_hi_vec.tail) = t;
__this_cpu_write(tasklet_hi_vec.tail, &(t->next));
__raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
}
}
Kern-Linux ( 5 -> 1 -> 3 -> 2 -> 7 -> 4 -> 6 )
"Die Natur hat weder Kern noch Schale; sie ist alles zugleich" -- Johann Wolfgang von Goethe
Der Leser sollte sich gut auskennen mit Betriebssystem-Konzepte ein angemessenes Verständnis von lang laufenden Prozessen und deren Unterschieden zu Prozessen mit kurzen Ausführungsintervallen; Fehlertoleranz bei gleichzeitiger Einhaltung weicher und harter Echtzeitbeschränkungen. Beim Lesen ist es wichtig zu verstehen und n/ack
die vom Linux-Kernel-Quellcode getroffenen Design-Entscheidungen in den Kern-Subsystemen.
Fäden [und] Signale [sind] eine plattformabhängige Spur von Elend, Verzweiflung, Schrecken und Wahnsinn (~Anthony Baxte). Bevor Sie sich in den Kernel stürzen, sollten Sie also ein selbstbewusster C-Experte sein. Sie sollten auch gute Erfahrungen mit Linked Lists, Stacks, Queues, Red Blacks Trees, Hash Functions, et al. haben.
volatile int i;
int main(void)
{
int c;
for (i=0; i<3; i++) {
c = i&&&i;
printf("%d\n", c); /* find c */
}
return 0;
}
Die Schönheit und Kunst des Linux-Kernel-Quelltextes liegt in der absichtlichen Code-Verschleierung. Dies ist oft notwendig, um die rechnerische Bedeutung von zwei oder mehr Operationen auf saubere und elegante Weise zu vermitteln. Dies gilt insbesondere für das Schreiben von Code für Multicore-Architekturen.
Video-Vorlesungen zu Echtzeitsystemen , Aufgabenplanung , Speicherkomprimierung , Gedächtnis-Barrieren , SMP
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
Linux Gerätetreiber ( 1 -> 2 -> 4 -> 3 -> 8 -> ... )
"Die Musik trägt einen nicht mit. Du musst sie ausschließlich durch deine Fähigkeit mitreißen, dich auf diesen kleinen Kern von Emotion oder Geschichte zu konzentrieren". -- Debbie Harry
Ihre Aufgabe besteht im Wesentlichen darin, eine Hochgeschwindigkeits-Kommunikationsschnittstelle zwischen dem Hardware-Gerät und dem Software-Kernel einzurichten. Sie sollten das Datenblatt/Handbuch der Hardware-Referenz lesen, um das Verhalten des Geräts und seine Kontroll- und Datenzustände sowie die zur Verfügung stehenden physikalischen Kanäle zu verstehen. Assembler-Kenntnisse für Ihre spezielle Architektur und gute Kenntnisse von VLSI-Hardwarebeschreibungssprachen wie VHDL oder Verilog werden Ihnen langfristig helfen.
Q : Aber warum muss ich die technischen Daten der Hardware lesen?
A : Denn: "Es gibt eine Kluft zwischen Kohlenstoff und Silizium, die die Software nicht überbrücken kann" - Rahul Sonnad
Dies stellt jedoch kein Problem dar für Berechnungsalgorithmen ( Treiber-Code - _Verarbeitung der unteren Hälfte_ ), da sie vollständig auf einem Computer simuliert werden kann. Universal-Turing-Maschine . Wenn das berechnete Ergebnis in der mathematisches Gebiet ist es sicher, dass dies auch für die physische Domäne .
Video-Vorlesungen zu Linux-Gerätetreibern (Lekt. 17 & 18), Anatomie eines eingebetteten KMS-Treibers , Pin-Steuerung und GPIO-Update , Gemeinsamer Taktrahmen , Einen echten Linux-Treiber schreiben - Greg KH
static irqreturn_t phy_interrupt(int irq, void *phy_dat)
{
struct phy_device *phydev = phy_dat;
if (PHY_HALTED == phydev->state)
return IRQ_NONE; /* It can't be ours. */
/* The MDIO bus is not allowed to be written in interrupt
* context, so we need to disable the irq here. A work
* queue will write the PHY to disable and clear the
* interrupt, and then reenable the irq line.
*/
disable_irq_nosync(irq);
atomic_inc(&phydev->irq_disable);
queue_work(system_power_efficient_wq, &phydev->phy_queue);
return IRQ_HANDLED;
}
Kernel-Vernetzung ( 1 -> 2 -> 3 -> ... )
"Nennt es einen Clan, nennt es ein Netzwerk, nennt es einen Stamm, nennt es eine Familie: Wie auch immer Sie es nennen, wer auch immer Sie sind, Sie brauchen eine." - Jane Howard
Das Verständnis eines Paketdurchlaufs im Kernel ist ein Schlüssel zum Verständnis von Kernel-Netzwerken. Es ist ein Muss, wenn wir die Interna von Netfilter oder IPSec und mehr verstehen wollen. Die beiden wichtigsten Strukturen der Linux-Kernel-Netzwerkschicht sind: struct sk_buff
y struct net_device
static inline int sk_hashed(const struct sock *sk)
{
return !sk_unhashed(sk);
}
Kernel-Debugging ( 1 -> 4 -> 9 -> ... )
Wenn man nicht genau sagt, was man meint, wenn man mit ihr kommuniziert, ist Ärger vorprogrammiert. ~Alan Turing, über Computer
Brian W. Kernighan sagte in seinem Aufsatz Unix für Anfänger (1979): "Das effektivste Werkzeug zur Fehlersuche ist immer noch sorgfältiges Nachdenken, gepaart mit sinnvoll platzierten Druckanweisungen". Wenn Sie wissen, was Sie sammeln müssen, können Sie schnell die richtigen Daten für eine schnelle Diagnose erhalten. Der große Informatiker Edsger Dijkstra sagte einmal, dass Tests das Vorhandensein von Fehlern nachweisen können, aber nicht deren Abwesenheit. Gute Untersuchungsmethoden sollten ein Gleichgewicht zwischen der Notwendigkeit, Probleme schnell zu lösen, der Notwendigkeit, die eigenen Fähigkeiten auszubauen, und dem effektiven Einsatz von Fachleuten herstellen.
Es gibt Zeiten, in denen man am Tiefpunkt angelangt ist, nichts mehr zu funktionieren scheint und einem alle Möglichkeiten ausgehen. Dann beginnt die eigentliche Fehlersuche. Ein Fehler kann der Auslöser dafür sein, dass Sie sich von der Fixierung auf eine unwirksame Lösung lösen.
Video-Vorlesungen zu Kernel-Debugging und Profiling , Kerndump-Analyse , Multicore-Debugging mit GDB , Kontrolle von Multi-Core-Rennbedingungen , Fehlersuche in der Elektronik
/* Buggy Code -- Stack frame problem
* If you require information, do not free memory containing the information
*/
char *initialize() {
char string[80];
char* ptr = string;
return ptr;
}
int main() {
char *myval = initialize();
do_something_with(myval);
}
/* “When debugging, novices insert corrective code; experts remove defective code.”
* – Richard Pattis
#if DEBUG
printk("The above can be considered as Development and Review in Industrial Practises");
#endif
*/
Dateisysteme ( 1 -> 2 -> 6 -> ... )
"Ich wollte virtuellen Speicher haben, zumindest in Verbindung mit einem Dateisystem. -- Ken Thompson
Auf einem UNIX-System ist alles eine Datei; wenn etwas keine Datei ist, ist es ein Prozess, mit Ausnahme von benannten Pipes und Sockets. In einem Dateisystem wird eine Datei durch ein inode
eine Art Seriennummer, die Informationen über die tatsächlichen Daten enthält, aus denen die Datei besteht. Das virtuelle Dateisystem von Linux VFS
speichert Informationen von jedem Dateisystem im Speicher, wenn es eingehängt und verwendet wird. Es muss sehr darauf geachtet werden, dass das Dateisystem korrekt aktualisiert wird, da sich die Daten in diesen Caches ändern, wenn Dateien und Verzeichnisse erstellt, beschrieben und gelöscht werden. Der wichtigste dieser Caches ist der Buffer Cache, der in die Art und Weise integriert ist, wie die einzelnen Dateisysteme auf ihre zugrunde liegenden Blockspeichergeräte zugreifen.
Video-Vorlesungen zu Speichersystemen , Flash-freundliches Dateisystem
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int fd = build_open_flags(flags, mode, &op);
struct filename *tmp;
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
Sicherheit ( 1 -> 2 -> 8 -> 4 -> 3 -> ... )
"UNIX wurde nicht entwickelt, um seine Benutzer davon abzuhalten, dumme Dinge zu tun, denn das würde sie auch davon abhalten, kluge Dinge zu tun". - Doug Gwyn
Keine Technik funktioniert, wenn sie nicht angewandt wird. Die Ethik ändert sich mit der Technologie.
" F × S = k "Das Produkt aus Freiheit und Sicherheit ist eine Konstante. - Nivens Gesetze
Die Kryptographie bildet die Grundlage für das Vertrauen im Internet. Hacking ist das Ausnutzen von Sicherheitskontrollen entweder in einem technischen, physischen oder menschlichen Element. Der Schutz des Kernels vor anderen laufenden Programmen ist ein erster Schritt auf dem Weg zu einem sicheren und stabilen System, aber das reicht natürlich nicht aus: Ein gewisses Maß an Schutz muss auch zwischen den verschiedenen Anwendungen im Benutzerland bestehen. Exploits können auf lokale oder entfernte Dienste abzielen.
"Du kannst dein Schicksal nicht mit roher Gewalt hacken... du brauchst eine Hintertür, einen Seitenkanal ins Leben." Clyde Dsouza
Computer lösen keine Probleme, sie führen Lösungen aus. Hinter jeder nicht-deterministisch algorithmischen Code, gibt es eine bestimmt Geist. -- /var/log/dmesg
Video-Vorlesungen über Kryptographie und Netzsicherheit , Namespaces für Sicherheit , Schutz vor Fernangriffen , Sicheres eingebettetes Linux
env x='() { :;}; echo vulnerable' bash -c "echo this is a test for Shellsock"
Kernel-Quelle ( 0.11 -> 2.4 -> 2.6 -> 3.18 )
"Wie Wein reift auch die Beherrschung der Kernelprogrammierung mit der Zeit. Aber im Gegensatz zum Wein wird sie im Laufe der Zeit süßer. --Lawrence Mucheka
Man mag nicht denken, dass Programmierer Künstler sind, aber Programmieren ist ein äußerst kreativer Beruf. Es ist eine logikbasierte Kreativität. Eine Ausbildung in Informatik kann niemanden zu einem erfahrenen Programmierer machen, genauso wenig wie das Studium von Pinseln und Pigmenten jemanden zu einem erfahrenen Maler machen kann. Wie Sie bereits wissen, gibt es einen Unterschied zwischen dem Kennen des Weges und dem Gehen des Weges; es ist von größter Wichtigkeit, die Ärmel hochzukrempeln und sich die Hände mit dem Kernel-Quellcode schmutzig zu machen. Schließlich, mit Ihrem so gewonnenen Kernel Wissen wo auch immer Sie hingehen, Sie werden glänzen .
Unreife Coder imitieren; reife Coder stehlen; schlechte Coder verunstalten, was sie nehmen, und gute Coder machen daraus etwas Besseres oder zumindest etwas anderes. Der gute Programmierer schweißt seinen Diebstahl zu einem einzigartigen Ganzen zusammen, das sich völlig von dem unterscheidet, aus dem es gerissen wurde.
Video-Vorlesungen zu Kernel-Rezepten
linux-0.11
boot
bootsect.s head.s setup.s
fs
bitmap.c block_dev.c buffer.c char_dev.c exec.c
fcntl.c file_dev.c file_table.c inode.c ioctl.c
namei.c open.c pipe.c read_write.c
stat.c super.c truncate.c
include
a.out.h const.h ctype.h errno.h fcntl.h
signal.h stdarg.h stddef.h string.h termios.h
time.h unistd.h utime.h
asm
io.h memory.h segment.h system.h
linux
config.h fdreg.h fs.h hdreg.h head.h
kernel.h mm.h sched.h sys.h tty.h
sys
stat.h times.h types.h utsname.h wait.h
init
main.c
kernel
asm.s exit.c fork.c mktime.c panic.c
printk.c sched.c signal.c sys.c system_calls.s
traps.c vsprintf.c
blk_drv
blk.h floppy.c hd.c ll_rw_blk.c ramdisk.c
chr_drv
console.c keyboard.S rs_io.s
serial.c tty_io.c tty_ioctl.c
math
math_emulate.c
lib
close.c ctype.c dup.c errno.c execve.c _exit.c
malloc.c open.c setsid.c string.c wait.c write.c
Makefile
mm
memory.c page.s
tools
build.c
Linux_source_dir/Documentation/*
Versuchen Sie, das Buch von Robert Love über Linux-Kernel-Programmierung zu bekommen. Es ist sehr prägnant und leicht zu verstehen.
Danach oder begleitend dazu können Sie einen Blick auf "Understanding the Linux kernel" werfen, aber ich würde es in der Anfangsphase nicht empfehlen.
Sehen Sie sich auch die Linux-Kernel-Programmieranleitung . Da man viel über die Programmierung von Kernelmodulen lernen kann, wird Ihnen diese Anleitung helfen. Und ja, viele Informationen finden Sie im Unterverzeichnis "documentation" des Tarballs der Kernel-Quellen.
Überprüfen Sie Das Linux Kernel Janitor Projekt
Wir gehen den Quellcode des Linux-Kernels durch, führen Code-Reviews durch, bereinigen nicht gewarteten Code und führen andere Bereinigungen und API-Konvertierungen durch. Es ist ein guter Einstieg in das Kernel-Hacking.''
Ich würde sagen: "C lernen". :)
Probieren Sie dieses kostenlose Online-Buch aus.
Linux-Kernel-Modul-Programmieranleitung http://www.linuxhq.com/guides/LKMPG/mpg.html
Die folgenden Bücher habe ich gelesen und für sehr nützlich befunden:
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.