Moving into the best parts of the kernel

Das erste, was wir können müssen, ist: Es zu benutzen: Netinstaller: Und das ist auch der Witz bei der Geschichte! Weil, wir machen hier kein Kernel Seminar. Wir tun hier allerhand Kernel hin und wollen die mal so benutzen und mal so, könnte man fast sagen: Wir nehmen sie wie ein Ding und gucken, wie wir sie wohin tun können.
Nun nebenbei, nur ganz nebenbei, staunen wir ab und zu darüber, was vielleicht da für ein PCB oder eine Freispeicherlist ist.
Oder warum es mm heißt. Auch, wenn neben den Kerneln, diese Ausführungen länger sind als der Rest.
Blos: Erst dann, wenn wir schon ein EPROM-Programmiergerät haben, vielleicht wird es dann sehr genau.

Der erste Teil von Minix, der ins Auge fällt

Ja, zunächst mal finden wir hier do_exec. Das fällt uns natürlich schon auf. Es steht auch noch in mm/exec., wo sonst. Blos, das wollen wir jetzt nicht - trotz allem.

Das Beste! Das Beste, was man je gesehen hat, ist die mm/alloc. - alloc - das sagt ja wohl alles. malloc() - das ist ja auch die Funktion, die beim Programmieren mit Turbo C erst richtig Spaß bereitet.

Uns hier steht: alloc_mem

Wie sieht das aus?

PUBLIC phys_clicks alloc_mem(clicks)
phys_clicks clicks;
{
  register struct hole *hp, *prev_ptr;
  phys_clicks old_base;

  hp = hole_head;
  while (hp != NIL_HOLE) {
    if(hp->h_len >= clicks) {
      old_base = hp->h_base;
      hp->h_base += clicks;
      hp->h_len -= clicks;

      if (hp->h_len != 0) return (old_base);

      del_slot(prev_ptr, hp);
      return(old_base);
    }

    prev_ptr = hp;
    hp = hp->h_next;
  }
  return(NO_MEM);
}



Kurze Frage, wie sieht dieser Algorithmus aus? Ganz einfach: Zunächst, was wir niemals tun werden, außer wir sind gerade bei unseren EPROM's mit Programmiergerät, ja dann - dann werden wir sehr konkret - vorher aber nie - wir stellen uns niemals vor, wir führen das aus. Wir sehen nur den Code. Mehr nicht.


Der Algorithmus könnte lauten: hp = hole_head;

while (hp != NIL_HOLE) {
  prev_ptr = hp;
  hp = hp->h_next;
}


Wir können uns die Sache aber auch ohne prev_ptr vorstellen. Dann sieht sie so aus: hp = hole_head;

while (hp != NIL_HOLE) {
  hp = hp->h_next;
}


Dazu schreiben wir ein Programm, das nicht alleine Kernel typisch ist.



Jetzt können wir diesen eigenen Quelltext, mit den in Anführungsstrichen, eigenen Teilen auch noch anpassen, dass er gemäß dem ersten ist.






Jetzt entwickeln wir eine lineare Liste, die so etwas tut, wie sie bei Andrew S. Tanenbaums Minix tut. Wir machen den ersten Schritt. Zunächst wird jedes h_len mit 10 initialisert. Danach ziehen wir bei jedem Aufruf der Funktion einen entsprechenden Wert ab. Wie gesagt, zu Beginn steht jedes Listenelement auf 10.






Im nächsten Schritt, kriegt jedes Element, eine base. Das was später der Startindex ist. Wenn wir nun alloc_mem() mit dem Wert 4 aufrufen und an der Stelle des entsprechenden Listenelements für length den Wert 10 stehen, dann addieren wir 4 zu base und ziehen 4 von length ab.

Die Elemente wiederum stehen untereinander alle im Abstand von 10 - was base betrifft.






Jetzt haben wir nur ein Problem: Ein malloc gibt es bei unserem Betriebssystem nicht. Und das ist logisch. Denn malloc() wird durch das Betriebssystem zur Verfügung gestellt, dieses wollen wir aber gerade programmieren - also gibt es das nicht.

Um jetzt eine lineare Liste zu realisieren, müssen wir sie wiederum in einem Feld unterbringen.








Jetzt haben wir bei unserem alloc_mem noch einen Fehler gemacht. Wir geben ptr->h_base zurück, also die neue base. Wir wollen aber die alte zurückgeben.






Jetzt wollen wir die Sache um del_slot() erweitern. Wir wollen alle Listenelemente aus der Liste entfernen, die als h_len den Wert 0 tragen.

So sieht das bei Andrew S. Tanenbaum aus:

PUBLIC phys_clicks alloc_mem(clicks)
phys_clicks clicks;
{
  register struct hole *hp, *prev_ptr;
  phys_clicks old_base;

  hp = hole_head;
  while (hp != NIL_HOLE) {
    if(hp->h_len >= clicks) {
      old_base = hp->h_base;
      hp->h_base += clicks;
      hp->h_len -= clicks;

      if (hp->h_len != 0) return (old_base);

      del_slot(prev_ptr, hp);
      return(old_base);
    }

    prev_ptr = hp;
    hp = hp->h_next;
  }
  return(NO_MEM);
}

...

PRIVATE del_slot(prev_ptr, hp)
register struct hole *prev_ptr;
register struct hole *hp;
{

  if (hp == hole_head)
    hole_head = hp->h_next;
  else
    prev_ptr->>h_next = hp->h_next;
  hp->h_next = free_slots;
  free_slots = hp;
}



Wir führen zunächst ein del_slot ein, was die alten Elemente, die ausgesondert werden, nicht speichert. Das heißt, wir entfernen einfach alle Elemente, mit der Länge 0, ohne um uns, um sie zu kümmern.

Und da stellen wir auch schon fest, wir haben in den vorherigen Codes vergessen, in print_list() ptr auf head zu setzen. Das holen wir nach und korrigieren wir.








Jetzt erweiteren wir das ganze um eine Liste, die unseren leeren Elemente enthält, die aus der ersten Liste entnommen wurden.







An dieser Stelle, haben wir eine ganz wichtige Routinen, oder bzw. die zwei Routinen erstellen, mit denen wir Speicher anfordern können. Wir können jetzt Speicher anfordern. Was wir noch nicht können ist ihn wieder frei zu geben - aber - das ist uns zunächst egal - weil das Entscheidende ist, zunächst Mal einfach Speicher an zu fordern.

Den Quelltext, den wir jetzt gerade geschrieben haben, der erinnert ziemlich stark an das, was Andrews S. Tanenbaum geschrieben hat. Vergegenwärtigen wir uns, so hieß es gerade eben:

PUBLIC phys_clicks alloc_mem(clicks)
phys_clicks clicks;
{
  register struct hole *hp, *prev_ptr;
  phys_clicks old_base;

  hp = hole_head;
  while (hp != NIL_HOLE) {
    if(hp->h_len >= clicks) {
      old_base = hp->h_base;
      hp->h_base += clicks;
      hp->h_len -= clicks;

      if (hp->h_len != 0) return (old_base);

      del_slot(prev_ptr, hp);
      return(old_base);
    }

    prev_ptr = hp;
    hp = hp->h_next;
  }
  return(NO_MEM);
}

...

PRIVATE del_slot(prev_ptr, hp)
register struct hole *prev_ptr;
register struct hole *hp;
{

  if (hp == hole_head)
    hole_head = hp->h_next;
  else
    prev_ptr->>h_next = hp->h_next;
  hp->h_next = free_slots;
  free_slots = hp;
}



Das ist schon beinahe identisch. Es stellt sich aber eine Frage. Wie heißt denn die Struktur, die Andrew S. Tanenbaum für struct lin_list verwendet - einfach nur der Name - weil, er wird wohl kaum den Namen struct lin_list verwenden.

Da finden wir bei Andrew S. Tanenbaum. >uch in der Datei mm/alloc.c diese Struktur definiert. Und zwar in 33:025

#define NR_HOLES 128
#define NIL_HOLE (struct hole *)0

PRIVATE struct hole {
  phys_clicks h_base;
  phys_clicks h_len;
  struct hole *h_next;
} hole [NR_HOLES];

Und nebenbei noch:

#define NR_HOLES 128
#define NIL_HOLE (struct hole *)0

PRIVATE struct_hole {
  phys_clicks h_base;
  phys_clicks h_len;
  struct hole *h_next;
} hole [NR_HOLES];

PRIVATE struct hole *hole_head;
PRIVATE struct hole *free_slots;


Jetzt stellt sich die Frage, was wir eigentlich getan haben? Nun wir können das in folgende Teile gliedern:
  1. Wir haben eine lineare Liste erstellt
  2. Wir haben eine lineare Liste erstellt, die
    1. Als Elemente eine Länge enthält und jedes Mal, wenn man die Liste bemüht, wird von dem am Kopf der Liste nächsten Element, die Länge abzgezogen, um die man die Liste bemüht hat.
  3. Wir haben eine lineare Liste erstellt, die
    1. Als Elemente eine Länge enthält und jedes Mal, wenn man die Liste bemüht, wird von dem am Kopf der Liste nächsten Element, die Länge abzgezogen, um die man die Liste bemüht hat.
    2. Wir haben eine Basis eingeführt. Anstatt jetzt einfach den Wert von der Länge ab zu ziehen, wird er zusätzlich zur Basis addiert. Bei diesem Szenario ist auf Folgendes zu achten:
      • Die Basen können nicht identisch sein, sondern sie sind quasi aufsteigend sortiert
      • Die maximale Länge, die entnommen kann entspricht der Länge, die maximalst unter den Elementen der Liste gefunden werden kann
      • Die Basis + die Länge kann niemals über den Bereich so hinausgehen, dass er hinter der Basis eines anderen Elements der Liste liegt
    3. Als Elemente eine Länge enthält und jedes Mal, wenn man die Liste bemüht, wird von dem am Kopf der Liste nächsten Element, die Länge abzgezogen, um die man die Liste bemüht hat.
  4. Wir haben eine lineare Liste erstellt, die
    1. Als Elemente eine Länge enthält und jedes Mal, wenn man die Liste bemüht, wird von dem am Kopf der Liste nächsten Element, die Länge abzgezogen, um die man die Liste bemüht hat.
    2. Wir haben eine Basis eingeführt. Anstatt jetzt einfach den Wert von der Länge ab zu ziehen, wird er zusätzlich zur Basis addiert.
    3. Jetzt nehmen wir alle Elemente, deren Länge Null ist einfach aus der Liste
  5. Wir haben eine lineare Liste erstellt, die
    1. Als Elemente eine Länge enthält und jedes Mal, wenn man die Liste bemüht, wird von dem am Kopf der Liste nächsten Element, die Länge abzgezogen, um die man die Liste bemüht hat.
    2. Wir haben eine Basis eingeführt. Anstatt jetzt einfach den Wert von der Länge ab zu ziehen, wird er zusätzlich zur Basis addiert.
    3. Jetzt nehmen wir alle Elemente, deren Länge Null ist einfach aus der Liste ...
    4. ... und führen sie in eine neue Liste mit leeren Elementen ein

Was uns noch fehlt - mal abgesehen vom Speicher-Freigeben

Was wir noch nicht berücksichtigt haben - wir haben eine Funktion geschrieben, die unsere lineare Liste initialisiert. Und dazu eine Funktion my_alloc geschrieben, die selber an dieser Stelle natürlich interessant ist, weil, wir eine Funktion alloc_mem() realisiert haben und unsere Funktion my_alloc() haben wir nur dazu verwendet, jeweils Listenelemente der Freispeicherliste zu erhalten.

Abgeleitet hat sich unser my_alloc daraus, dass wir bei Listen meistens malloc() verwenden, was wir am Anfang in den ersten Codes auch taten.

Jetzt wäre interessant zu erfahren, wie Andrew S. Tanenbaum, die Liste am Anfang initialisiert hat?

Das geschieht in der Funktion mem_init() in mm/alloc.c in Zeile 35:202 bis 35:224

PUBLIC mem_init(clicks)
phys_clicks clicks;
{

  register struct hole *hp;

  for (hp = &hole[0]; hp++) hp->h_next = hp + 1;
  hole[0].h_next = NIL_HOLE;
  hole_head = &hole[0];
  free_slots = &hole[1];
  hole[0].h_base = 0;
  hole[0].h_len = clicks;
}

Bevor wir weiter machen

An dieser Stelle noch drei Mal ein Betriebssystem:
  1. debian-9.12.0-amd64-DVD-1.iso
  2. debian-10.3.0-amd64-DVD-1.iso
  3. dopenSUSE-Leap-15.1-DVD-x86_64.iso
Bei dem Debian habe ich gespart. Das sind drei Iso's jeweils. Die können Sie sich natürlich aus dem Netz herunterladen.
Jetzt, was ist Sache?
  1. Das erste ist: Wir sind bei Debian Version 10 angekommen. Auf diesem Server, auf dem Sie das hier lesen, läft Debian 10. Auf meine anderen Rechnern läuft Debian9

    Diese Nummerierung innerhab einer Distribution hat nichts mit der Zählung bei der Kernel-Version zu tun. Beim Kernel, waren wir bei 1, dann 2, dann lange 3, und wie ich sehe, sind wir glaube ich inzwischen bei 5 oder 6.

    Die Distributionen, wie Debian benutzen diese Kernel.

    Neben Debian habe ich hier OpenSuSE geposted
  2. Dann der zweite Teil ist das mit dem Netzwerkinstaller. Und es ist so: Generell kann man alles auf einer oder 3 oder auch früher 6 CD's oder DVD's haben. Aber: DAs hat so oder so einen Nachteil: Die Quellen sind generell im Netz. Das heißt die Repositories. Hier wird mit einer URL ein Ort angegeben, wo der Computer Pakete beziehen kann. Ein schnelles Netz ist so oder so notwendig. Warum nicht den Network-Installer nehmen? Ich meine: Die Netzwerkhardware wird meistens schon bei der Installation erkannt.

Jetzt etwas zu dem von oben

Jetzt erst ein Mal, hier ganz viele alte Kernel. Diese haben die klassische Nummerierung: linux-1.0, linux-1.2, ... - und bis 2 sollte man es wissen. Hier ganz sporadisch einige Kernel. Wir werden das MM aus allen Kerneln besprechen. Das heißt, wir gehen in jedem Kernel auf das mm.

Hier die Kernel: Und jetzt das Schöne, nämlich: Wir hatten es oben von dem mm von minix und natürlich gibt es auch bei Linux spezifisches, was mm betrifft, hier:

Im nächsten Moment besprechen wir mal den PCB

Ich stelle nicht den gesamten PCB vor, nur das, was mich jetzt interessiert, und das sieht so aus: Es ist definiert in kernel/proc.h in 11:009

EXTERN struct proc {
  int p_reg[NR_REGS];
...

} proc[NR_TASKS+NR_PROCS];
Interessant ist das p_reg mit einer Zahl NR_REGS. Dazu gehören die Register AX, BX, CX, DX,BP,SP,SI,DI, aber auch die Segmentregister CS,DS,SS,ES.

Und hier findet man auch ihre Definition, kurz vorher - in kernel/const.h:

#define ES_REG    7
#define DS_REG    8
#define CS_REG    8
#define SS_REG   10


Jetzt haben wir darin aber noch etwas Interessantes:

EXTERN struct proc {
  int p_reg[NR_REGS];
...

  struct mem_map p_map[NR_SEGS];
...

} proc[NR_TASKS+NR_PROCS];

Das ist sehr interessant, denn das sind die Segmente. Wir wissen bei unserem Intel-8086 gibt es nicht nur ein Segment, je Prozess, oder überhaupt, sondern vier: Das Codesegment, das Datensegment, das Extrasegment und das Stacksegment.
Wobei wir unsere Aufteilung von den Segmenten nicht zwingend mit einem Prozess in Verbindung bringen müssen.

Wenn man jetzt mal schaut, findet man, in der main()-Funktion des Kernels einen Code, wie:

rp->p_map[T].mem_len = VERY_BIG;
rp->p_map[T].mem_phys = base_click;
rp->p_map[D].mem_len = VERY_BIG;
rp->p_map[D].mem_phys = base_click;
rp->p_map[S].mem_len = VERY_BIG;
rp->p_map[S].mem_phys = base_click;

Dabei handelt es sich um einen Prozess, bei dem alle Teile (Code, Daten, Stack) im selben Bereich untergebracht sind. Wie für Speicherverwaltung und Kernel so üblich. Außerdem: T steht für Text, eine übliche Bezeichnung für Code und D für Daten und S für Stack.

Jetzt wäre es natürlich noch interessant die Struktur mem_map wirklich zu finden. Und sie ist definiert in h/type.h in 08:111 bis 08:115

struct mem_map {
  vir_clicks mem_vir;
  phys_clicks mem_phys;
  vir_clicks mem_len;
};

Damit haben wir wohl drei wesentliche Strukturen zusammen:
  1. struct hole - für die Freispeicherliste
  2. struct mem_map - um jedem Prozess auch wiederum den Anfang und die Länge eines Segments zuweisen zu können
  3. struct proc - eine Struktur, die für jeden Prozess einen Eintrag bereit hält, der alles beschreibt, was einen Prozess ausmacht
Interessant sind desweiteren, die Definitionen von Variablen, von diesen Typen:
  1. struct hole
    1. Die Liste mit den freien Bereichen im Arbeitsspeicher
    2. Eine Liste mit leeren Elementen dieser Liste
  2. struct mem_map, in jedem Prozess, aber für
    1. Text (Code)
    2. Daten
    3. Stacksegment
  3. struct proc

So, jetzt habe ich eine Überraschung für Sie

Bitteschön - ein Linux-Kernel

Er hat die Versionsnummer 5.5.0-2 ist also einer von den neueren Kerneln - fast ganz neu.

Er ist 5,5 MiB (5.762.800) Byte groß. Ist also nicht über die Maßen groß. Wenn man bedenkt, dass, wenn man eine eigene Partition für /home/ anlegt und /var/ und /tmp usw. nicht in eine eigene Partition packt, dass dann 30 GByte = 30 * 1024 =~ 30.000 gut ausreichen. Umgekehrt, woran erkennt man so einen Kernel?

Na ja, zunächst Mal daran: So ein Kernel heißt eigentlich von Natur aus immer vmlinuz

Wichtig ist, dass wir zwischen dem gebauten Kernel und dem Quelltext (Code) unterscheiden. Für jeden Kernel, gibt es eigentlich pro Linux-Betriebssystem (Distribution + Version), drei Pakete:
  1. Den gebauten Kernel
  2. kernel-src (Source)
  3. kernel-syms
Wie kommt man eigentlich an den Kernel ran?
Das ist eine generelle Frage. Weil man sich fragen muss, wie man bei Paketen an die eigentlichen Inhalten heran kommt. Wir müssen bedenken: Pakete selber werden benötigt, um sie mit der Paketverwaltung in das System ein zu bauen, natürlich nicht die Pakete, sondern die Programme oder Daten, die sie enthalten.
Die Paketverwaltung ist dazu da, dass man sich nicht jedes Programm einzeln holen muss. Natürlich sind die von Natur aus angebotenen Programme bei allen Distributionen zunächst mal zum größten Teil gleich. Es empfiehlt sie zentral zu lagern und an zu bieten.
Dazu ist die Paketverwaltung da. Da bei Paketen eine gewisse Anzahl weiterer Informationen notwendig ist, um zum Beispiel Informationen, die für die Instalation notwendig sind zu liefern, werden neben dem Programm, oder den Daten noch weitere Daten in das Paket verpackt. Aber halt! So magisch das klingen mag - das sind meist viel weniger Daten, als man so meinen möchte. Meist sehen die Dinge sehr mystisch aus, so, dass man meinen könnte da sind eine Menge kryptischer Daten eingepackt. Das ist es nicht. Ziel von Paketen ist die Installation von Programmen. Und, neben den eigentlichen Daten oder Programmen, die in einem Paket sein können sind dort meist auch noch die Verzeichnisse gleich erstellt. Wenn ein Programm in /boot/ entpackt wird, dann ist in dem Paket meist auch ein Verzeichnis /boot.

OK, treiben wir es auf die Spitze! Was sind denn nun eigentlich die typischen Pfade in einem Paket. Es gibt sie nämlich schon - diese "kryptischen Daten". Muss es ja! Sonst würde die Paketverwaltung nicht wissen, wohin damit und was alles eingerichtet werden muss. Man muss zum Beispiel wissen, es gibt Dämonen, zum Beispiel. Wenn man das Programm nun installiert, soll es nach der Installation am Besten gleich das notwendig tun.
Aber es gibt in Paketen grundsätzlich zwei Elemente Ordner:
  1. data
  2. control
In control sind alle Daten untergebracht, die für die Installation notwendig oder wissenswert sind. Natürlich ist das alles immer wohl sortiert, so, dass es nicht irgendwelche Daten irgendwo gibt, sondern es gibt:
  1. data
  2. control
Und in data sind die eigentlichen Daten. Halt! Hier muss man aufpassen - wenn wir einen Kernel installieren - oder ein Programm, wie die bash, dann sind diese natürlich Programme. Doch aus Sicht des Pakets, sind sie wiederum Daten - oder "die Daten".

Und in data finden wir unseren Kernel vmlinuz

Aber wir müssen darauf achten. Die Daten in dem Paket in data sind dort so untergebracht, wie nachher auf der Platte. Der Kernel ist in /boot/ auf der Platte untergebracht - also landet er in dem Paket in /boot/, aus der Sicht des Pakets in /data/boot/.

Die Frage ist nun, was sind diese Pakete nun eigentlich? Nun hier könnte man sich wieder etwas kryptisches vorstellen - etwas, dass sich nicht öffnen ließe. Doch zunächst müssen wir aufpassen.
  1. data
  2. control
sind nicht etwa, vollständige Ordner, sondern gepackt als data.tar.xz und control.tar.xz
  1. data.tar.xz
  2. control.tar.xz
Aber unser Paket hat höchst wahrscheinlich die Endung *.rpm oder *.deb
  1. *.deb: Debian, Ubuntu, ...
  2. *.rpm: OpenSuSE zum Beispiel
Diesen Endungen haftet etwas mystisches an. Doch wir können sie mit einem normalen Archivprogramm wie ark öffnen. Während in den Paketen die Archive: data.tar.xz und control.tarz.xz sind, ist *.deb und *.rpm wieder ein Archiv. Und wir wissen Linux unterscheidet Dateien nicht einfach anhand ihrer Dateiendung - das ist manchmal praktisch, gerade bei einer graphischen Benutzeroberfläche wie KDE oder gnome, weil, dann die Dateiformate u.a. schneller erkennbar erkennbar wären, wenn man es so macht - sondern anhand ihrer Inhalte. Und betreff der Inhalte ist *.deb und *.rpm wieder ein Archiv.

Zwischenfrage

Wie kriegen wir jetzt eigentlich das Image des Network-Installers oder des vollen Betriebssystems auf den entsprechenden Speicher? Unter Linux geht das ganz einfach. Hier gibt es den Befehl:

dd

Und wenn sich der USB-Speicherstick als zweites Laufwerk im Computer befindet. Dann gibt man ein - zum Beispiel:

dd if=debian-10.3.0-amd64-netinst.iso of=/dev/sdb

Oder

dd if=debian-10.3.0-amd64-netinst.iso of=/dev/sdb bs=512

/dev/sdb ist zu wählen, wenn es sich um das zweite Laufwerk im Computer handelt, /dev/sdc beim dritten usw. Danach kann man den Computer von dem USB-Stick starten, was alle heutigen Computer unterstützen.

Das geht natürlich unter Linux ganz einfach, unter Windows nicht. Denn bei Windows gibt es den Befehl dd so nicht. Hier gibt es zum Beispiel den Befehl partcopy aber damit kenne ich mich nicht aus. Damit könnte man zur Not das gesamte Image so auf den Stick bekommen, wie es muss. Oder man benutzt eine Windows-typische Anwendung. Es gibt sicher eine jede Menge, mit graphischer Benutzeroberfläche. Oder man brennt das Image auf eine CD oder DVD. Das hat aber nur solange einen Sinn, solange sowohl der Rechner, auf dem man das Image auf eine DVD bringt, einen DVD-Brenner hat und der Computer, auf den man das Betriebssytem anbringt ein DVD-Laufwerk. Ich zum Beispiel habe nur auf meinem Laptop eines und das, weil es schon drin war.

Ich benutze aber DVD-Laufwerke aus zwei Gründen nicht: (1.) Sie sind teuer (2.) mir gefallen sie nicht. Sie sind nicht einfach nur mechanisch, wie magnetische Festplatten, sie gefallen mir nicht. Ich komme ohne DVD-Laufwerke viel besser davon.

Und: Für zwei von meinen Rechnern habe ich ausgegeben: Ich bin also ca. für 150 Euro davon gekommen. Und: Deswegen sind diese Computer kein wenig schlechter, als etwa, ein wenig ältere Computer. Während man nämlich gerade noch viel Geld für besonders gute Hardware ausgegeben haben, haben meine Computer: SSD, USB 3.1., SATA-III, Intel-HD mit HDMI-Ausgang, DDR4-RAM ...

Und: SATA-III zum Beispiel macht schon einen Unterschied zu SATA-Express zum Beispiel: 600 MByte/s. Und SATA-Express: Na ja - dasselbe. Aber man überlege mal: Wirklich ältere Computer, schneiden hier ganz schlecht ab. Und das kann bedeuten: Obwohl der Rechner sehr teuer gewesen sein mag - er ist nichts mehr wert.

So viel zu EEPROM

Wissen Sie, was das Lustige ist - ich habe ja von EEPROMs geredet und vom Beschreiben und einem Programmer. Und fand ich einfach keinen Programmer für ein EEPROM. Und das Lustige ist: Die EEPROMs heißen auch noch 28C oder so. Also AT28C bzw. AT28C256 (Mit 256 KByte), wenn das EEPROM von Atmel ist. Das heißt, am Ende dachte ich, hier habe ich es mit Atmel-Mikrocontrollern zu tun. Jetzt aber der Witz: Ich fand und fand nichts. Dann habe ich gelesen: Die Betriebsspannung liegt zum Beispiel bei maximal 6V. Das hat mich Staunen gemacht und dann habe ich mal nachgedacht. Und bei mir steht von der Schule im Schrank immer noch das Buch: Fachkenntnisse Elektrotechnik, Kommunikationselektronik und Informationstechnik - und ich habe es mir am Ende fast gedacht. Nachdem conrad.de lauter EEPROM's hat, aber kein Programmiergerät! Für EEPROM's braucht man kein Programmiergerät. Die lassen sich beschreiben, wie sie sich lesen lassen. Sie sind quasi ein RAM nur statisch. Aber sie lassen sich beschreiben. Und das klingt jetzt nach einem Programmierbit - aber sie lassen sich beschreiben, wie lesen.

Das ist gar kein Problem: Das ist Teil der Aufgabe das heraus zu finden. Und ich bestelle mal gleich ganz viele EEPROM’s bei conrad.de

Wir machen weiter

Das erste ist, dass wir das mit den EEPROMs wieder vergessen. Ich habe sie mir mal genau angeschaut - und ehrlich gesagt - das ist das Lustige - sie brauchen kein Programmiergerät. Das können Sie vergessen. Sie brauchen es nicht - weil es EEPROMs gibt, und das heißt im wahrsten Sinne des Wortes, sie werden so gelesen und beschrieben, wie das RAM. Sie haben auch einen Eingang, READ und WRITE, aber sie werden während Laufzeit geschrieben und gelesen, wie RAM - mit einem Unterschied - die herkömmlichen EEPROMs sind ganz langsam - also diese kleinen Teile, wie Sie sie klassischer Weise kriegen, sind langsam - zumindest zum schreiben

Und jetzt zu Minux

Das Letzte, wo wir waren, war der PCB - aber das ging jetzt zu schnell - zurück zur Freispeicherliste - die vollständig machen.

Jetzt listen wir erst ein Mal, alle Dateien auf, die in mm sind Funktionen:


Sämtliche Kernel stehen unter der GPL und dürfen nur als solche weitergereicht werden.

Falls Sie trotzdem Informationen über den Autor der Homepage haben wollen

David Vajda
Schickhardtstraße 5
D-72072 Tübingen