Kernel Panic - Board on Fire   /     [Podcast] Kernel Panic - Board on Fire ~~> #003: Ein Rennen um Nanosekunden - NebenlĂ€ufigkeit mit Hardwareeinheiten

Description

In dieser Folge erzĂ€hlt Michael Grzeschik die Geschichte eines USB-Controllers, der dann und wann einfach aufhört zu funktionieren und davon wie er dem Fehler mit Tracing, einem Disassembler und viel CodelektĂŒre auf die Schliche gekommen ist. Wir stellen einmal mehr fest, dass Probleme mit NebenlĂ€ufigkeit schwierig zu debuggen sind und nicht nur Software-Software Interaktion betreffen, sondern manchmal auch Software-Hardware.

Subtitle
Duration
Publishing date
2023-01-24 10:10
Link
https://www.pengutronix.de/de/blog/2023-01-24-kernel-panic-board-on-fire-003-ein-rennen-um-nanosekunden.html
Contributors
Enclosures
https://www.pengutronix.de/data/kernel_panic/003_rennen_um_nanosekunden.mp3
audio/mpeg

Shownotes

In dieser Folge erzĂ€hlt Michael Grzeschik die Geschichte eines USB-Controllers, der dann und wann einfach aufhört zu funktionieren und davon wie er dem Fehler mit Tracing, einem Disassembler und viel CodelektĂŒre auf die Schliche gekommen ist. Wir stellen einmal mehr fest, dass Probleme mit NebenlĂ€ufigkeit schwierig zu debuggen sind und nicht nur Software-Software Interaktion betreffen, sondern manchmal auch Software-Hardware.

Über den Kernel Panic - Board on Fire Podcast

In wahrscheinlich jedem Berufsfeld gibt es Schauergeschichten, die man sich abends am Lagerfeuer mit einer Taschenlampe am Kinn erzĂ€hlen kann. So auch in der Welt der Software. In diesem Podcast geben wir in unregelmĂ€ĂŸigen AbstĂ€nden Entwicklerinnen und Entwicklern die Möglichkeit ihre Schauergeschichten zu erzĂ€hlen. Es geht um monatelange Fehlersuchen, deren Ergebnis nur eine Hand voll Zeilen falscher Code sind, um subtil fehlerhafte Hardware, die zu sporadisch auftretenden Geistern im System fĂŒhrt, um bröckelnde Software, deren Quellcode schon vor Jahren verloren gegangen ist, und manchmal auch um ganz was anderes.

Shownotes

Wer nicht die ganze Folge hören möchte kann sich an den folgenden Zeitmarken orientieren:

00:00 Vorstellung und einleitende warme Worte. Michael beschĂ€ftigt sich viel mit der Device-Seite von USB unter Linux. In letzter Zeit insbesondere mit dem Fall, dass ein Linux GerĂ€t sich verhĂ€lt wie eine USB-Webcam und Video an einen anderen Rechner ĂŒbertrĂ€gt. Das gibt ihm sowohl BerĂŒhrungspunkte mit Kernelthemen, als auch mit Grafikthemen. 07:00

Einleitung der Lagerfeuergeschichte. Beim Bug-Quartett wÀre sie mit drei Zeilen angepasstem Code bei mehreren Wochen Suchzeit eine gute Karte.

Ausgangspunkt ist ein Linux-Computer, der sich einem anderen Computer gegenĂŒber als USB-GerĂ€t ausgeben sollte. An diesem sollte er dann ein serielles Kommunikationsinterface bereitstellen, ĂŒber das man z.B. eine Linux Commandline benutzen kann. Nach einigen Stunden Laufzeit blieb allerdings die gesamte Kommunikation stecken und die USB-Einheit im GerĂ€t ließ sich nicht mehr ansprechen.

11:00 Weil das Problem so schlecht reproduzierbar ist war Trial and Error kein guter Ansatz. Die Alternative ist erstmal scharfes Hinsehen im Treibercode, um das Verhalten mit dem Datenblatt zu vergleichen. Besonderes Augenmerk hat er dabei auf die Datenstrukturen gelegt, die zwischen dem Treiber und der Hardware ausgetauscht werden. 13:00

Zusammenfassung des bisher gehörten:

  • Das GerĂ€t um das es geht spielt die Rolle eines USB-Device, ein anderes GerĂ€t (z.B. ein Desktoprechner) den USB Host.
  • Die Übertragungskette ist also Userspace-Software -> Kernel-Treiber -> USB-Einheit -> Kabel -> USB-Einheit -> Kernel-Treiber -> Userspace-Software.
  • Der Fehler liegt zwischen Kernel-Treiber und USB-Einheit auf GerĂ€teseite. In den Treiber kann man hinein schauen, in die USB-Einheit nicht.
16:00 Weiter mit der Bestandsaufnahme. Es handelt sich nicht um einen der typischen USB-Fehler, wie einen leer gelaufenen Datenpuffer, die werden nÀmlich schon behandelt. Es bleibt wirklich die ganze USB-Einheit hÀngen. 21:00 Peripherieeinheiten wie USB oder Netzwerkcontroller werden von Chipherstellern oft eingekauft und in ihr eigenes Design integriert. So finden sich die selben Einheiten oft in ganz unterschiedlichen Chips. Bei USB waren in der Zeit besonders der dwc2 und der Chipidea Controller relevant. 30:00 Ansatz um die fehlerhafte Stelle einzugrenzen: Einbau von Tracing in den Treiber, um Daten aufnehmen zu können im Moment in dem der Fehler tatsÀchlich passiert. Das Tracing ergibt, dass die Hardware nach EinhÀngen neuer Daten stehen bleibt. 39:00

Der selbe Treiber und die Peripherieeinheit werden auch auf anderen Systemen genutzt, warum ist es da nicht aufgefallen? Die CPU in der problematischen Hardware kann Daten nicht unaligned schreiben/ lesen. D.h. wenn z.B. ein 32 Bit Wert aus dem Speicher in ein Register gelesen werden soll geht das nur dann in einer einzigen Prozessor-Instruktion, wenn die Speicheradresse (in Bytes) durch vier teilbar ist (also durch 32 Bit). Ansonsten muss es durch vier einzelne byteweise Reads passieren. Auf anderen Platformen gibt es mitunter Befehle um auch unaligned in einer Instruktion lesen/schreiben zu können.

Im disassemblierten Code konnte man sehen, dass die Adresse der nÀchsten Datenstruktur als vier einzelne Bytes geschrieben wurde und nicht als ein 32 Bit Wert.

43:00 In der Zeit in dem der neue Pointer Byte fĂŒr Byte geschrieben wird kann die Hardware vorbei kommen und einen Wert auslesen, der nur teilweise die richtigen Daten enthĂ€lt. Weil das Zeitfenster nur ein paar Nanosekunden lang ist, tritt der Fehler so selten auf. 50:00 Warum hat der Compiler ĂŒberhaupt angenommen, dass das Datenfeld nicht auf 32 Bit aligned war? Weil die Datenstruktur extra als packed markiert war. Mit der zusĂ€tzlichen Markierung aligned(4) wird das Feld wieder in einer Instruktion geschrieben. 58:00 Mit dem Markieren als aligned(4) ist der Patch auch quasi schon fertig. Der VollstĂ€ndigkeit halber fĂŒgt er auch noch ein wmb() (Write-Memory-Barrier) ein, um sicherzustellen, dass der Compiler das Schreiben der Daten in die Datenstruktur nicht hinter das EinhĂ€ngen der Datenstruktur verschiebt. 60:00 Zusammenfassung und Abschluss