Autor Thema: Speicherverwaltung  (Gelesen 57856 mal)

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« am: 30. May 2008, 21:45 »
Hi Community,
da ich gerade mal wieder am neuschreiben meines Memory Managers bin, habe ich ein paar Fragen an euch. :roll:
 
Nun ist es ja so, dass, wenn ich DMA verwenden will, der Speicher im Bereich unter 16 MB liegen muss, ansonsten sollte das oberhalb sein (>16MB).
Daraus resultierend habe ich mir für meine physikalische Speicherverwaltung folgende Funktionen ausgedacht (Prototypen):
 
extern void physical_page_free(unsigned int page);
extern void physical_page_range_free(unsigned int page, int num);

extern unsigned int physical_alloc_dma_page(void);
extern unsigned int physical_alloc_dma_page_range(unsigned int num);

extern unsigned int physical_alloc_page(void);
extern unsigned int physical_alloc_page_range(unsigned int num);

Was haltet Ihr davon?
Ist das so vollständig, oder fehlt da eventuell noch etwas, das ich übersehen habe?
 
Gruß Christian
« Letzte Änderung: 02. June 2008, 09:42 von ChristianF »

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #1 am: 30. May 2008, 22:00 »
Du solltest wohl die Funktion nicht auf >16Mb beschränken, denn sonst hast du ein Problem, wenn ein Rechner nur 8 Mb hat. Es macht aber sicherlich Sinn, erst den Speicher über 16Mb zu vergeben.

Vielleicht wären Funktionen um zu Prüfen ob eine bestimmte Page besetzt ist, respektive um eine bestimmte Page zu reservieren nicht verkehrt, falls mal ein Treiber eine bestimmte Adresse will. Später, wenn du mal ein free oder sowas in deiner Shell haben willst, um zu wissen, wieviel Speicher noch frei ist, wäre vielleicht eine Funktion nützlich die dir die Anzahl der freien/besetzen Pages zurückgibt.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #2 am: 30. May 2008, 23:35 »
Hi
Vielleicht wären Funktionen um zu Prüfen ob eine bestimmte Page besetzt ist, respektive um eine bestimmte Page zu reservieren nicht verkehrt, falls mal ein Treiber eine bestimmte Adresse will. Später, wenn du mal ein free oder sowas in deiner Shell haben willst, um zu wissen, wieviel Speicher noch frei ist, wäre vielleicht eine Funktion nützlich die dir die Anzahl der freien/besetzen Pages zurückgibt.
Nun das was du meinst, kommt nach der physikalischen Speicherverwaltung, da das Paging ja zur Virtuellen Speicherverwaltung zählt.
Da habe ich mir bis jetzt auch noch nicht so viele Gedanken gemacht, da das Programm, dass Speicherplatz (z.B. ein Treiber) anfordert nur eine virtuelle Addresse bekommt.
 
Gruß Christian

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 30. May 2008, 23:42 »
Wenn dieses Programm aber ein Treiber ist und die Hardware mit virtuellen Adressen füttert, dürfte viel rauskommen, nur nichts sinnvolles. Es gibt schon Software, die einen Grund dazu hat, bestimmte physische Adressen zu wollen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #4 am: 31. May 2008, 09:24 »
Mmmhhh.....
Das einzigste Problem wäre dann aber, dass die Adressen nicht 1:1 gemappt werden.
Mein Kernel wird an die Adresse 0xC0000000 gemappt (Physikalisch 0-2 MB).
Das würde dann heißen, ich bräuchte bei meinen Paging funktionen noch eine Funktion, die 1:1 Mappt, z.B.:

bool map_page_to_address_1to1(...);

(Wenn ich das richtig verstanden habe.)

Gruß Christian

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #5 am: 31. May 2008, 09:39 »
Die Adressen müssen ja nicht umbedingt 1:1 gemappt werden. Es reicht, wenn der Treiber einen physischen Speicherbereich anfordern kann, und dann die virtuelle Adresse erhält, an die der Bereich gemappt wurde.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #6 am: 01. June 2008, 15:53 »
Und genau so habe ich mir das eigentlich gedacht.

Jetzt mal unabhängig davon, welches Programm/welcher Treiber braucht denn unbedingt eine physikalische Addresse?

Wie sieht es denn aus mit DMA?
Es heißt, dass der Speicher unterhalb der 16 MB grenze liegen muss. Kann ich die Page dann virtuell z.B. an die Stelle 0xABC00000 mappen, oder muss das dann 1:1 sein?
 
Gruß Christian

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 01. June 2008, 16:45 »
Den Speicher für DMA kannst du dahin mappen wo du möchtest.
Alle Memory-Mapped Devices brauchen Zugriff auf bestimmte physische Pages. Dazu gehören viele PCI Devices, APICs und andere Geräte. (HPET z.B.)

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #8 am: 01. June 2008, 18:04 »
Ok
Jetzt hab ich das verstanden (denke ich mal  :roll: ).

Ein Treiber fordert die Pages im Adressraum 0x60000000 - 0x70000000 an.
Der Kernel mappt die dann in die entsprechende Page des Prozesses und dieser kann dann damit arbeiten.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #9 am: 01. June 2008, 21:00 »
Ja, wobei man nur in einem Design mit Microkernel speziellen Prozessen (auch Server genannt) erlaubt physische Speicherbereiche zu allozieren. Bei einem monolithischen Kerneldesign wird nur der Kernel (bzw. die Kernelmodule oder Treiber) diese physischen Speicherbereiche allozieren können und diese werden dann in den Kerneladressraum (also in jeden Prozess, aber mit "supervisor" Rechten als Pageattribut) gemappt.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #10 am: 02. June 2008, 09:44 »
Okay.

Hier ist sind die bis jetzt geplanten Funktionen:
extern void physical_page_free(unsigned int page);
extern void physical_page_range_free(unsigned int page, int num);

extern unsigned int physical_alloc_dma_page(void);
extern unsigned int physical_alloc_dma_page_range(unsigned int num);

extern unsigned int physical_alloc_page(void);
extern unsigned int physical_alloc_page_range(unsigned int num);
extern unsigned int physical_alloc_page_limit(unsigned int lower_limit, unsigned int num);

Ich werde dann demnächst mit der Re-Implementierung der Speicherverwaltung beginnen.
 
Gruß Christian

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #11 am: 04. June 2008, 11:24 »
MMhhh....
Die Physikalische Speicherverwaltung ist nicht sonderlich schwer, da ich das ja nur umbaue.
 
Auf was muss ich denn beim Paging alles achten?
Danach möchte ich mit dem einbauen von Multitasking beginnen, weshalb ich schonmal für alle Paging sachen, wie Page, Pagetable und Page Directory eine Struktur angelegt habe.  :-)
 
Auf was muss ich hinsichtlich des Multitaskings später achten?

Dann ist da nochwas, da ich ja auch einen Heap Manager einbauen muss.
Ist es sinnvoll in einem Microkernel den Heap Manager für den Kernel (Ring 0) und User-Programme/Treiber (Ring 3) in den Kernel einzubauen, oder sollte ich den Part für die User-Programme/Treiber auslagern?
 
Gruß Christian


*EDIT*
Du solltest wohl die Funktion nicht auf >16Mb beschränken, denn sonst hast du ein Problem, wenn ein Rechner nur 8 Mb hat. Es macht aber sicherlich Sinn, erst den Speicher über 16Mb zu vergeben.
Ich habe vor den DMA Speicherbereich dynamisch festzulegen,
z.B.: Wenn 32 MB gesamt da ist, dann nim 16 MB. Wenn nur 16 MB da sind, dann nimm 8 MB.

*EDIT 2*
Laut diesem Tutorial: Multitasking Tutorial muss für das Kopieren der Daten eines Frames/einer Page (physikalisch) das Paging deaktiviert werden, was mir doch recht langsam erscheint.
Geht das nur so, oder ist da noch ein anderer Weg?
« Letzte Änderung: 04. June 2008, 13:49 von ChristianF »

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #12 am: 04. June 2008, 14:03 »
Auf was muss ich hinsichtlich des Multitaskings später achten?
Alles sinnvoll im Virtuellen Adressraum anordnen, so dass später genug Platz für den userspace ist und nicht ein totales Kuddelmuddel entsteht.

Zitat
Ist es sinnvoll in einem Microkernel den Heap Manager für den Kernel (Ring 0) und User-Programme/Treiber (Ring 3) in den Kernel einzubauen, oder sollte ich den Part für die User-Programme/Treiber auslagern?
Also alles was mit dem Kernelheap zu tun hat, würde ich auf jeden Fall im Kernel haben. Was den Userspaceheap angeht würde ich das nur auf Pageebene im Kernel verwalten, ein malloc kann dann die userspace libc selbst bereitsstellen.

Zitat
Laut diesem Tutorial: Multitasking Tutorial muss für das Kopieren der Daten eines Frames/einer Page (physikalisch) das Paging deaktiviert werden, was mir doch recht langsam erscheint. Geht das nur so, oder ist da noch ein anderer Weg?
Das ist eine Möglichkeit (wenn auch imho eine sehr bescheidene), aber das muss man natürlich nicht so machen. Wenn man das Page-Directory als eine der Page-Tables angibt, dann kann man auf die gesamten page tables zugreifen. Wenn man dann zusätzlich noch das Pagedir mappt, so kann man über den virtuellen Adressraum auf sein Pagedir & seine Pagetables zugreifen und zumindest diese verändern. Wenn man jetzt ein neues PDir erstellen will, dann muss man sich halt in den momentanen Adressraum irgendwo ne physische Page einbinden und diese dann zu nem PageDir bauen und halt wieder unmappen, wenn man damit fertig ist.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #13 am: 04. June 2008, 15:20 »
Nun den Speicher habe ich bis jetzt wie folgt aufgeteilt (Virtuell):
0x00000000 - 0xBFFFFFFF     => User Programme
0xC0000000 - 0xCFFFFFFF     => Kernel
0xD0000000 - 0xDFFFFFFF     => Kernel Heap
0xE0000000 - 0xFFFFFFFF     => "Noch nicht vergeben"

Ist das so sinnvoll, oder wäre es besser, da noch was zu ändern, mal abgesehen von dem letzten Eintrag (0xE0000000-0xFFFFFFFF)?
 
Gruß Christian

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #14 am: 04. June 2008, 15:31 »
Bei uns gibts zwar noch ein paar mehr Sachen im virtuellen Adressraum (siehe hier, das Layout für x64 ist iirc momentan unvollständig und von mips hab ich selbst keine Ahnung *g*), aber ansonsten passt das schon.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #15 am: 05. June 2008, 08:35 »
Mal eine technische Frage:
ich habe eine Funktion
unsigned int find_free_page(unsigned int lower_limit);
Wenn ich nun eine page zu DMA-Zwecken reservieren möchte sieht mein Funktionsaufruf wie folgt aus:
unsigned int page = find_free_page(0);
Wenn ich irgendeine andere Page reservieren möchte, dann muss ich ein Limit angeben, das die Grenze zum DMA-Bereich angibt, z.B.:
(Vorrausgesetzt werden für dieses Beispiel 32MB RAM)
unsigned int page = find_free_page(16*1024*1024);
Nun ist es ja so, dass die Addresse, wenn Sie größer 0 ist, in einen Eintrag umgewandelt werden muss. Nun muss ich aber die Startposition für die bitmap berechnen.
Das habe ich mir wie folgt gedacht:
unsigned int loop;
loop = (loop>0)?(lower_limit / 0x1000 /*PAGE_SIZE*/ / 32):0;

Darauf gekommen bin ich durch die Reservierung der Page. Hier wird ja auch erst mit 32 multipliziert und dann später noch mit der Größe der Page.
return(((i*32)+j) * 0x1000 /*PAGE_SIZE*/

Ist das so richtig, oder habe ich da was übersehen?
Gruß Christian

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 05. June 2008, 10:07 »
Die Bedingung dass die Address größer 0 sein muss ist unnötig.
Außerdem wird die Variable loop in deinem Beispiel nicht initialisiert, die Abfrage if(loop > 0) ist also Schwachsinn. Gemeint war hier wohl eher if(lower_limit > 0).
Ansonsten scheint deine Berechnung in Ordnung zu sein. (Ich gehe davon aus dass du loop als Index in ein Array von 32 Bit Zahlen benutzt; bei einem Bytearray ist die Division durch 32 natürlich falsch)
Ich würde mir aber überlegen, ob die Angabe eines Limits nach oben nicht sinnvoll ist. Schließlich möchtest du nicht, dass ISA DMA Pages in einem Bereich über 16 MiB allokiert werden. Die Behandlung aller Spezialfälle die auftreten könnten fällt warscheinlich mit der Angabe einer oberen Grenze leichter.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #17 am: 05. June 2008, 10:25 »
Nun ja...
Meine Code zum finden einer freien page sieht in der Grund-Version so aus
(wird allerdings nochmals überarbeitet, da lower_limit nicht berücksichtigt wird):
// Wird später initialisiert, mit (max_mem / num_pages)
unsigned int *physical_bitmap = NULL;

unsigned int find_free_page(unsigned int lower_limit)
{
   unsigned int i, j;
   for (i = 0; i < physical_bitmap_size; i++)
   {
       if (physical_bitmap[i] != 0xFFFFFFFF)
       {
           // at least one bit is free here.
           for (j = 0; j < 32; j++)
           {
               if ( !(physical_bitmap[i]&(0x1<<j)) )
                   return(((i*32)+j) * 0x1000);
           }
       }
   }
   return(-1);
}

Ansonsten scheint deine Berechnung in Ordnung zu sein. (Ich gehe davon aus dass du loop als Index in ein Array von 32 Bit Zahlen benutzt; bei einem Bytearray ist die Division durch 32 natürlich falsch)
Ist ja auch verständlich, da das Bytearray ein char Array ist, und so 8 Pages pro Eintrag verwalten kann.
Ich habe mich für die 32-Bit Bitmap entschieden, da Sie mir etwas schneller vorkam, oder täusche ich mich da?  :roll:
 
Die Bedingung dass die Address größer 0 sein muss ist unnötig.
Außerdem wird die Variable loop in deinem Beispiel nicht initialisiert, die Abfrage if(loop > 0) ist also Schwachsinn. Gemeint war hier wohl eher if(lower_limit > 0).
Genau das meinte ich.

Ich würde mir aber überlegen, ob die Angabe eines Limits nach oben nicht sinnvoll ist. Schließlich möchtest du nicht, dass ISA DMA Pages in einem Bereich über 16 MiB allokiert werden. Die Behandlung aller Spezialfälle die auftreten könnten fällt warscheinlich mit der Angabe einer oberen Grenze leichter.
Nun ja dafür hatte ich eine globale Variable vorgesehen, mit dem DMA-Limit. Mit einem Übergabeparameter ist das allerdings etwas sauberer, z.B.:
unsigned int find_free_page(unsigned int lower_limit, unsigned int upper_limit);
Oder sollte ich das doch global speichern?  :wink:

Gruß Christian

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #18 am: 09. June 2008, 20:02 »
Hi
ich habe mit einem richtig komischen Problem zu kämpfen.
 
Folgender Code initialisiert die Physikalische Speicherverwaltung:
void initialise_physical_memory_manager(multiboot_info_t *mbt)
{
unsigned int num_pages = 0, max = 0, i;

if(CHECK_FLAG(mbt->flags, 0))
    {
        max = (mbt->mem_lower + mbt->mem_upper);
max_mem = max * 1024;
        num_pages = max_mem / PAGE_SIZE; /* PAGE_SIZE = 0x1000 */
/* Set DMA-Upper Limit. It should be calculated with max_mem, but max. is 16 MB (16 * 1024 * 1024) */
upper_dma_limit = ((max_mem / 2) > (16 * 1024))?(16*1024*1024):((max_mem / 2) * 1024 * 1024);
    }
    else if(CHECK_FLAG(mbt->flags, 6))
    {
/*
* ToDo: + Look at the Memory Map from GRUB
* + Calculate the whole Memory
* + set the Reserved Areas as used
*
* max = ???
* max_mem = ???
* num_pages = max_mem / PAGE_SIZE;
* upper_dma_limit = ((max_mem / 2) > (16 * 1024))?(16*1024*1024):((max_mem / 2) * 1024 * 1024);
*/
    }
    else
panic("Direct Memory Probing isn't yet implemented!");

/* Calculate the size of the bitmap */
physical_bitmap_size = (num_pages / 32) * 4;
/* Allocate Bitmap and Translate the address to a physical one */
physical_bitmap = (unsigned int *)VIRT2PHYS(kmalloc(physical_bitmap_size));
    /* Set all to 0 from the reserved space */
    memset(physical_bitmap, 0, physical_bitmap_size);
}

Nun hatte ich allerdings das Problem, dass mein Kernel die ganze Zeit hängen geblieben ist (endlosschleife).
Einige Debugausgaben haben folgendes ergeben:
physical_bitmap_size = 131068
physical_bitmap = 0x1069ff

Nun sollte ja eigentlich mit memset der komplette Inhalt auf 0 gesetzt werden, was allerdings nicht passiert, denn alle 131068 Einträge enthalten 0xFFFFFFFF. Auch das manuelle umsetzen ohne Funktionsaufruf hat nichts gebracht.
 
Woran kann das liegen?
 
Gruß Christian

*EDIT*
Genauer gesagt, es kommt ein Out of Memory, da alles mit 0xFFFFFFFF belegt ist.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #19 am: 09. June 2008, 20:12 »
Wo bleibt der Kernel den überhaupt hängen und va. ist es wirklich eine Schleife oder geht er baden (im Sinne von Exception nach Exception nach Exception...)?
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

 

Einloggen