Autor Thema: Monolitischer Kernel mit Modulen  (Gelesen 13203 mal)

woigl

  • Beiträge: 93
    • Profil anzeigen
    • http://www.nogos.org
Gespeichert
« am: 02. August 2005, 20:42 »
Ich bin neu hier und hoffe das mir jemand von euch weiterhelfen kann, da dieses Forum kompetent aussieht.

Kann mir jemand weiterhelfen bei meiner folgenden Frage:

Ich will gerne ein OS programmieren und dann dynamisch die Treiber laden - wie ist hier das vorgehen? hat jemand Beispiele? wie wird dies bei Linux geloest?

Ich will einfach vermeiden das Grafiktreiber, Soundtreiber usw. im Kernel implementiert sind.

maumo

  • Beiträge: 182
    • Profil anzeigen
    • http://maumo.50webs.com/
Gespeichert
« Antwort #1 am: 02. August 2005, 21:06 »
kommt drauf an wie DUs halt machen willst. du könntest die treiber per grub laden lassen und in den kernelspace mappen. oder  du machst es so wie ich, indem du jeden treiber als eigenen prozess laufen lässt und dann alles auf IPC setzt. es kommt halt ganz auf DEINE ansprüche an. außerdem musst du die erstmal ein treiberformat überlegen

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 02. August 2005, 21:57 »
Sorry - was ist IPC?... Wahrscheinlich kenn ich's, aber die Abkürzung ist mir gerade nicht geläufig.

maumo

  • Beiträge: 182
    • Profil anzeigen
    • http://maumo.50webs.com/
Gespeichert
« Antwort #3 am: 02. August 2005, 22:54 »
inter-processing-communication

hannibal

  • Host
  • Beiträge: 400
    • Profil anzeigen
    • brainsware - the rock.
Gespeichert
« Antwort #4 am: 02. August 2005, 22:58 »
Zitat von: WhiteDragon
Sorry - was ist IPC?... Wahrscheinlich kenn ich's, aber die Abkürzung ist mir gerade nicht geläufig.


ich glaub eher er meinte den PIC, programmable interrupt controller ;)
\\o
o//
\o/

maumo

  • Beiträge: 182
    • Profil anzeigen
    • http://maumo.50webs.com/
Gespeichert
« Antwort #5 am: 02. August 2005, 23:08 »
nun noch mal alle:

pic = programmable interrupt controller
pci = peripheral controll interface
ipc = inter-processing-communication
pit = programmabel interval timer

noch was  :wink:

n3Ro

  • Beiträge: 288
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 02. August 2005, 23:33 »
Fast richtig ;-) IPC = Inter-Process-Communication, dann macht der Begriff nämlich sogar Sinn :)

So jetzt zum Thema:
Ich weiß nicht wie weit du bist, aber zuerst solltest du dir genaue Gedanken machen, wie dein OS aufgebaut sein soll, was der Kernel so alles wie macht und wie dann Anwendungen und Treiber miteinander kooperieren sollen. Dazu kann ich nur, wenn du Zugang zu einer Bibliothek hast, Andrew S. Tanenbaum Werk "Moderne Betriebssystem" in der 2. Auflage Kapitel 12 "Entwurf von Betriebssystemen" und wenn du des Englischen mächtig bist das "design considerations" Kapitel im OS-FAQ Wiki empfehlen.
Agieren statt Konsumieren!

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 03. August 2005, 11:17 »
schon besser ;) aber wenn IPC ein englischer begriff sein soll, wirds kleingeschrieben und es kommen nicht ganz so viele bindestriche rein (inter-process communication) :)
Dieser Text wird unter jedem Beitrag angezeigt.

woigl

  • Beiträge: 93
    • Profil anzeigen
    • http://www.nogos.org
Gespeichert
« Antwort #8 am: 03. August 2005, 20:19 »
Also um mal zu erklaeren wie mein Aufbau aussehen soll:

Ich moechte einen Kernel haben der die Schaltzentrale zwischen Programmen und Treiber ist.

Also wenn ein Programm grafische Ausgaben macht, dann soll es an den Kernel gehen und der leitet es an den jeweiligen Grafiktreiber weiter welcher dann an die Hardware uebergibt.

Ich habe das ganze Buch von Tannenbaum gelesen und habe schon so meine Vorstellungen.

Ebenfalls sollte ich noch erwaehnen das ich den Kernel in C schreiben moechte.

Bitte um weitere Infos...

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 03. August 2005, 21:25 »
Du musst das Modul erstmal laden. Du kannst Module mit GRUB laden lassen oder sie mit einem eigenen Treiber von einer Festplatte oder was auch immer lesen. Falls du nicht schon beim kompilieren der Module weißt, an welche Addresse sie später geladen werden, musst du die Module dynamisch linken/relocaten. Das ist zum Beispiel bei ELF sehr einfach zu realisieren. Je nach Design des OS kannst du die Treiber mit eigenem Addressspace versehen oder sie in alle Prozesse mappen. Der Kernel kann dann direkt über Jumps oder Taskswitches in den Treiber springen.

woigl

  • Beiträge: 93
    • Profil anzeigen
    • http://www.nogos.org
Gespeichert
« Antwort #10 am: 04. August 2005, 11:20 »
Zitat von: SSJ7Gohan
Du musst das Modul erstmal laden. Du kannst Module mit GRUB laden lassen oder sie mit einem eigenen Treiber von einer Festplatte oder was auch immer lesen. Falls du nicht schon beim kompilieren der Module weißt, an welche Addresse sie später geladen werden, musst du die Module dynamisch linken/relocaten. Das ist zum Beispiel bei ELF sehr einfach zu realisieren. Je nach Design des OS kannst du die Treiber mit eigenem Addressspace versehen oder sie in alle Prozesse mappen. Der Kernel kann dann direkt über Jumps oder Taskswitches in den Treiber springen.


Ja klingt plausibel, aber hat da jemand ein Beispiel... mir fehlt da einiges an Wissen diesbezueglich.

maumo

  • Beiträge: 182
    • Profil anzeigen
    • http://maumo.50webs.com/
Gespeichert
« Antwort #11 am: 04. August 2005, 12:58 »
grub oder relocations?

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 04. August 2005, 13:11 »
Ein Beispiel für ELF Relocation kann ich dir geben:
Es ist noch zu beachten, das man damit den Kernel sehr leicht mit korrupten ELF Files manipulieren kann, da mein Code weitgehend nicht überprüft ob die Werte der ELF File gültig sind. Falls du den Code in deinem OS benutzt solltest du also überprüfen ob die Pointer auf gültige Stellen in der ELF File zeigen.

Es sind ausserdem grundlegende libc Funktionen nötig um den Code auszuführen. ( strcmp(), memcpy() usw. )

Ausserdem sind vieleicht meine Structs nicht so sehr leicht zu verstehen, da die Namen nicht alle selbstdokumentierend sind ^^;; und der Code ist nicht sehr gut dokumentiert. :(

typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef long s32;
typedef short s16;

#define ELF386_SEC_SYMTABLE 2

#define ELF386_R_32 1
#define ELF386_R_PC32 2

#define ELF386_R_SYMBOL(z) ( (z) >> 8 )
#define ELF386_R_TYPE(z) ( (unsigned char)(z) )

#define ELF386_ST_BINDING(z) ( (z) >> 4 )
#define ELF386_ST_TYPE(z) ( (z) & 0xF )

#define ELF386_MAGINDEX_0 0
#define ELF386_MAGINDEX_1 1
#define ELF386_MAGINDEX_2 2
#define ELF386_MAGINDEX_3 3

#define ELF386_MAG_0 0x7F
#define ELF386_MAG_1 'E'
#define ELF386_MAG_2 'L'
#define ELF386_MAG_3 'F'

typedef struct {
u8  elfMagic[16];
u16  elfType;
u16  elfMachine;
u32  elfVersion;
u32  elfEntry;
u32  elfProgramOffset;
u32  elfSectionOffset;
u32  elfFlags;
u16  elfHeaderSize;
u16  elfProgramSize;
u16  elfProgramCount;
u16  elfSectionSize;
u16  elfSectionCount;
u16  elfStringSection;
} __attribute__ ((packed)) elf386Header;

typedef struct {
u32  sectionName;
u32  sectionType;
u32  sectionFlags;
u32  sectionAddress;
u32  sectionOffset;
u32  sectionSize;
u32  sectionLink;
u32  sectionInfo;
u32  sectionAlign;
u32  sectionEntrySize;
} __attribute__ ((packed)) elf386Section;

typedef struct {
u32  symbolName;
u32  symbolValue;
u32  symbolSize;
u8  symbolInfo;
u8  symbolOther;
u16  symbolSection;
} __attribute__ ((packed)) elf386Symbol;

typedef struct {
u32  relocOffset;
u32  relocInfo;
s32  relocAdded;
} __attribute__ ((packed)) elf386Relocation;

typedef struct {
u32  programType;
u32  programOffset;
u32  programVirtualAddress;
u32  programPhysicalAddress;
u32  programFileSize;
u32  programSize;
u32  programFlags;
u32  programAlign;
} __attribute__ ((packed)) elf386ProgramHeader;

void *elf386LoadModule( char *image, unsigned long size );
int elf386Relocate( char *image );
int elf386DoRelocation( char *image, elf386Section *section, elf386Relocation *relocation );
unsigned long elf386GetSymbol( char *image, unsigned long symbolTable, unsigned long symbolID );
void *elf386GetSymbolOffset( char *image, char *name );

// in memory.h steht die Funktion allocateSystemMemory(), die benutzt wird um die Module zu laden.
#include "../memory.h"
#include "string.h"

void *elf386LoadModule( char* image, unsigned long size ) {
elf386Header *header = (elf386Header *)image;
elf386Section *section;

if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {

return -1;
}

unsigned long bssSize;

// loop trough the sections and look for the bss section
unsigned long i;
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );

if( section->sectionType != 8 )
continue;

bssSize = section->sectionSize;

break;
}

// allocate memory for the module
void *module = (void *)allocateSystemMemory( size + bssSize );

// copy the image into memory
memcpy( module, image, size );

// zero the bss section
memset( module + size, 0, bssSize );

// setup the bss section
section->sectionOffset = (u32)module + size;

return module;
}

int elf386Relocate( char *image ) {
unsigned long i;
unsigned long j;

elf386Section *section;
elf386Header *header = (elf386Header *)image;
elf386Relocation *relocation;

if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {

return -1;
}

unsigned long relocSize;

// now we loop trough the sections and look for relocation infos
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );

if( section->sectionType == 4 ) {
relocSize = 12;
}else if( section->sectionType == 9 ) {
relocSize = 8;
}else{
continue;
}

// the section contains relocation infos
for( j = 0; j < section->sectionSize / relocSize; j++ ) {
relocation = (elf386Relocation *)( image + section->sectionOffset + relocSize * j );

// do the relocation
elf386DoRelocation( image, section, relocation );
}
}
}

int elf386DoRelocation( char *image, elf386Section *section, elf386Relocation *relocation ) {
elf386Header *header = (elf386Header *)image;
elf386Section *targetSection = (elf386Section *)(image + header->elfSectionOffset + header->elfSectionSize * section->sectionInfo);

unsigned long *relocationOffset = (unsigned long *)( image + targetSection->sectionOffset + relocation->relocOffset );

unsigned long symbol = elf386GetSymbol( image, section->sectionLink, ELF386_R_SYMBOL( relocation->relocInfo ) );

switch( ELF386_R_TYPE( relocation->relocInfo ) ) {
case ELF386_R_32 :
*relocationOffset = *relocationOffset + symbol;

break;
case ELF386_R_PC32 :
*relocationOffset = *relocationOffset + symbol - (unsigned long)relocationOffset;

break;
}
}

unsigned long elf386GetSymbol( char *image, unsigned long symbolTable, unsigned long symbolID ) {
elf386Header *header = (elf386Header *)image;
elf386Section *table = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbolTable );
elf386Symbol *symbol = (elf386Symbol *)( image + table->sectionOffset ) + symbolID;

elf386Section *section;

if( symbol->symbolSection == 0 ) {
// external symbol
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * table->sectionLink );

return lookupExternalSymbols( (char *)( image + section->sectionOffset + symbol->symbolName ) );
}else{
// internal symbol
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbol->symbolSection );

return (unsigned long)( image + section->sectionOffset + symbol->symbolValue );
}

}

void *elf386GetSymbolOffset( char *image, char *name ) {
elf386Header *header = (elf386Header *)image;
elf386Section *section;
elf386Section *strings;
elf386Symbol *symbol;
elf386Section *symbolSection;

if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {

return 0;
}

// loop trough the sections and look for the text section
unsigned long i;
unsigned long j;
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );

if( section->sectionType == ELF386_SEC_SYMTABLE ) {
strings = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * section->sectionLink );

for( j = 0; j < section->sectionSize / sizeof( elf386Symbol ); j++ ) {
symbol = (elf386Symbol *)( image + section->sectionOffset ) + j;

if( strcmp( image + strings->sectionOffset + symbol->symbolName, name ) == 0 ) {
symbolSection = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbol->symbolSection );

return image + symbolSection->sectionOffset + symbol->symbolValue;
}
}
}
}

return 0;
}


Die Funktion allocateSystemMemory() allocated Speicher und mappet ihn in alle Prozesse.
elf386LoadModule() läd ein Modul, das dann noch mit elf386Relocate() relocated werden muss. Die Funktionen elf386DoRelocation() und elf386GetSymbol() sind Hilffunktionen für elf386Relocate. elf386DoRelocation() führt das eigentliche relocaten durch, ersetzt also die Offsets innerhalb der ELF File durch die richtigen Werte. elf386GetSymbol() liefert das Offset eines Symbols, das für den Relocation Vorgang benötigt wird.
elf386GetSymbolOffset() wird benutzt, um z.b. das Offset der main() Funktion zu erhalten.
lookupExternalSymbols( char *name ) kann etwa so aussehen:
void *lookupExternalSymbols( char *name ) {
if( strcmp( name, "printf" ) == 0 ) {
return (void *)printf;
}
}


Ein Beispielcode wie du den Code oben benutzen kannst findest du hier.
Dieser Code führt ein von GRUB geladenes Modul aus.
Die Variable module zeigt auf ein Modul der multibootinfo Struktur.
argc und argv sind Variablen, in denen die Parameter des Modules stehen.
void *kmod = elf386LoadModule( module->mod_start, module->mod_end - module->mod_start );
elf386Relocate( kmod );

void (*entry)( int, char ** ) = elf386GetSymbolOffset( kmod, "main" );
entry( argc, argv );

Das sollte dann die main Funktion mit den Argumenten argc und argv ausführen.
Zu beachten ist noch, das unter Windows standardmässig den Funktionen ein _ vorgestellt wird, du solltest unter Windows also void (*entry)( int, char ** ) = elf386GetSymbolOffset( kmod, "_main" ); benutzen.

maumo

  • Beiträge: 182
    • Profil anzeigen
    • http://maumo.50webs.com/
Gespeichert
« Antwort #13 am: 04. August 2005, 13:33 »
wenn dir dass noch nicht reicht, hätt ich auch noch PE?
@SSJ7Gohan: eigentlich ist der code recht gut zu verstehen  :)

woigl

  • Beiträge: 93
    • Profil anzeigen
    • http://www.nogos.org
Gespeichert
« Antwort #14 am: 05. August 2005, 08:16 »
Hey, vielen Dank, der Code ist toll...

werd mich mal an die Arbeit machen und mich gegebenenfalls nochmals melden!

Vorab brauch ich jetzt mal das Filesystem und dann gehts an die Treiber.

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 06. August 2005, 12:02 »
Achso, du musst die Module mit den Flags -r -fno-common Linken, damit sie zu einer relocateable gelinkt werden. -fno-common bringt, das Variablen in der BSS Sektion erstellt werden. Ohne den Flag werden sie als "Common" deklariert, in der BSS Sektion wird jedoch kein Speicher reserviert. Da mein Relocation Code Common Variablen aber noch nicht richtig behandelt, funktionieren Variablen in der BSS Sektion nur wenn du -fno-common aktiviert hast.

woigl

  • Beiträge: 93
    • Profil anzeigen
    • http://www.nogos.org
Gespeichert
« Antwort #16 am: 06. August 2005, 17:54 »
Zitat von: SSJ7Gohan
Achso, du musst die Module mit dem Flag -r Linken, damit sie zu einer relocateable gelinkt werden.


Danke, das wäre gleich ein Vorschlag zum erwitern des Tutorials Kernel in C - vielleichte Module und sonstige Dinge beschreiben?

Danke fuer den Tip zum Linken.  :idea:

 

Einloggen