Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Projekt: OS-Development  ::  Memory Managment     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
tty
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.02.2010
Beiträge: 2
Beitrag tty Mitglied 22:35:15 20.02.2010   Titel:   Memory Managment            Zitieren

Beschreibung des MM von Badestrand:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-261588-and-postdays-is-0-and-postorder-is-asc-and-start-is-4.html



---------------------------------------


Hi Sub-Forum,

ich hab mir nen paar gedanken über ein Memory Managment Konzept gemacht das die Seiten für die einzelnen Bereiche (Kernel, Applikation, Treiber) sauber trennt und "erweiterbar" ist.

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Big-System

Das OS braucht einen Speicher-Verwaltungs Algorithmus der einzelne Seiten (4kb) Allokiert (eine oder mehrere)(die seiten können im Kernel-Land oder im User-Land oder für die Treiber benutzt werden und wir nennen sie hier "batch"), die Access-flags (read-only oder read/write| supervisor level oder user level) werden entsprechend der Anfrage für die Seiten gesetzt.
Dabei speichern wir "in band" (die Kontroll Datenstrukturen werden in der Datenstruktur drinnen gespeichert) die Verwaltungs-Daten (s_manage) in einer Seite (4k) vor dem Bereich.

Die Struktur der Verwaltungsdaten:

enum batch_level {
    USERLAND,
    KERNELLAND,
    DRIVERLAND
};

struct s_manage {
    uint count; // how many pages follow after this until the next s_mange 4kb page?
   
    // maybe we can combine this two flags in one byte
    bool last;  // is this the last allocated "batch" of pages
    bool free;  // is this "batch" that follows free
   
    // if it is not free we save here the data about the batch
    batch_level level; // this is the level for who it was allocated
    // TODO< maybe we save here for who exactly we had allocated it ? (except for kernel) >
};

Wenn der Kernel zum Beispiel 10 4-kb Seiten braucht sieht die Struktur nach dem reservieren wie folgt aus (die einzelnen Mappings für die Seiten):

Page 0                Page 1 - 10       Page 11
s_manage            |                 | s_manage
count = 10          | Data for Kernel | last = true
last = false        | (batch)         |
free = false        |                 |
level = KERNELLAND  |                 |

(Die Flags für die Seiten des Batches werden entsprechend der Anfrage gesetzt)

Small-System

Das Small System Teilt den Speicherbereich der vom Big-System gekommen ist nochmal ein weil der Kernel/Die Userland Programme meistens keine 4kb-Brocken brauchen.

Die Kontroll-Strukturen werden "out of Band" (außerhalb des Speicherbereichs wo die daten für das Programm/den Treiber später gespeicher werden) gespeichert.
Das hat den Vorteil das man es nicht so einfach überschreiben kann (wenn die Seite(n) wo die Kontroll-Daten liegen als Supervisor gekennzeichnet sind kann man als Treiber(Ring1/2?) und als User(ring3) nicht drauf zugreifen).

Wir nennen die Nutz-Strukturen hier "Junks".

Nutz-Strukturen
---------------

Das Prinzip ist das wir eine 4kb Seite n mal zerstückeln und so die Junks erhalten (wobei n = 1, 2, 3 ... 4096/8)(4096/8 weil ein 8 Byte-"Alignment" sehr gut ist).

n = 1
|                    4 kB Seite                                                 |

n = 2
|              2kb Junk                 |                 2 kb Junk             |

n = 3
4096/3 = 1365,3...(periode)

man sieht schon das der erste Junk 8 Byte aligned ist aber der zweite Junk ist es nicht, also was tun wir?

Wir wissen das der Junk kleiner sein soll als 1265 und durch 8 ohne rest teilbar (wegen dem Aligment), das heißt...

1365 % 8 = 5
so ziehen wir 5 bytes von der größe ab und wir liegen richtig
1365-5 = 1360

Das bedeutet das jeder Junk 1360 Bytes groß ist und die restlichen (4096 - 1360*3 = 16) Bytes werden am ende "verschmissen".
|       1360            |    1360               | 1368                   | ... |

usw.


Das Prinzip kann man natürlich auch nicht nur mit Seiten sondern auch mit größeren (8kb, 12kb, ...) Speicherbereichen machen.

Kontrollstrukturen
------------------

In den Kontrollstrukturen müssen wir nur speichern wie groß ein Junk ist und welche belegt/frei sind.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Big-System

Das OS braucht einen Speicher-Verwaltungs Algorithmus der einzelne Seiten (4kb) Allokiert (eine oder mehrere)(die seiten können im Kernel-Land oder im User-Land oder für die Treiber benutzt werden und wir nennen sie hier "batch"), die Access-flags (read-only oder read/write| supervisor level oder user level) werden entsprechend der Anfrage für die Seiten gesetzt.
Dabei speichern wir "in band" (die Kontroll Datenstrukturen werden in der Datenstruktur drinnen gespeichert) die Verwaltungs-Daten (s_manage) in einer Seite (4k) vor dem Bereich.

Die Struktur der Verwaltungsdaten:

enum batch_level {
USERLAND,
KERNELLAND,
DRIVERLAND
};

struct s_manage {
uint count; // how many pages follow after this until the next s_mange 4kb page?

// maybe we can combine this two flags in one byte
bool last; // is this the last allocated "batch" of pages
bool free; // is this "batch" that follows free

// if it is not free we save here the data about the batch
batch_level level; // this is the level for who it was allocated
// TODO< maybe we save here for who exactly we had allocated it ? (except for kernel) >
};

Wenn der Kernel zum Beispiel 10 4-kb Seiten braucht sieht die Struktur nach dem reservieren wie folgt aus (die einzelnen Mappings für die Seiten):

Page 0 Page 1 - 10 Page 11
s_manage | | s_manage
count = 10 | Data for Kernel | last = true
last = false | (batch) |
free = false | |
level = KERNELLAND | |

(Die Flags für die Seiten des Batches werden entsprechend der Anfrage gesetzt)

Small-System

Das Small System Teilt den Speicherbereich der vom Big-System gekommen ist nochmal ein weil der Kernel/Die Userland Programme meistens keine 4kb-Brocken brauchen.

Die Kontroll-Strukturen werden "out of Band" (außerhalb des Speicherbereichs wo die daten für das Programm/den Treiber später gespeicher werden) gespeichert.
Das hat den Vorteil das man es nicht so einfach überschreiben kann (wenn die Seite(n) wo die Kontroll-Daten liegen als Supervisor gekennzeichnet sind kann man als Treiber(Ring1/2?) und als User(ring3) nicht drauf zugreifen).

Wir nennen die Nutz-Strukturen hier "Junks".

Nutz-Strukturen
---------------

Das Prinzip ist das wir eine 4kb Seite n mal zerstückeln und so die Junks erhalten (wobei n = 1, 2, 3 ... 4096/8)(4096/8 weil ein 8 Byte-"Alignment" sehr gut ist).

n = 1
| 4 kB Seite |

n = 2
| 2kb Junk | 2 kb Junk |

n = 3
4096/3 = 1365,3...(periode)

man sieht schon das der erste Junk 8 Byte aligned ist aber der zweite Junk ist es nicht, also was tun wir?

Wir wissen das der Junk kleiner sein soll als 1265 und durch 8 ohne rest teilbar (wegen dem Aligment), das heißt...

1365 % 8 = 5
so ziehen wir 5 bytes von der größe ab und wir liegen richtig
1365-5 = 1360

Das bedeutet das jeder Junk 1360 Bytes groß ist und die restlichen (4096 - 1360*3 = 16) Bytes werden am ende "verschmissen".
| 1360 | 1360 | 1368 | ... |

usw.


Das Prinzip kann man natürlich auch nicht nur mit Seiten sondern auch mit größeren (8kb, 12kb, ...) Speicherbereichen machen.

Kontrollstrukturen
------------------

In den Kontrollstrukturen müssen wir nur speichern wie groß ein Junk ist und welche belegt/frei sind.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Big-System

Das OS braucht einen Speicher-Verwaltungs Algorithmus der einzelne Seiten (4kb) Allokiert (eine oder mehrere)(die seiten können im Kernel-Land oder im User-Land oder für die Treiber benutzt werden und wir nennen sie hier "batch"), die Access-flags (read-only oder read/write| supervisor level oder user level) werden entsprechend der Anfrage für die Seiten gesetzt.
Dabei speichern wir "in band" (die Kontroll Datenstrukturen werden in der Datenstruktur drinnen gespeichert) die Verwaltungs-Daten (s_manage) in einer Seite (4k) vor dem Bereich.

Die Struktur der Verwaltungsdaten:

enum batch_level {
    USERLAND,
    KERNELLAND,
    DRIVERLAND
};

struct s_manage {
    uint count; // how many pages follow after this until the next s_mange 4kb page?
   
    // maybe we can combine this two flags in one byte
    bool last;  // is this the last allocated "batch" of pages
    bool free;  // is this "batch" that follows free
   
    // if it is not free we save here the data about the batch
    batch_level level; // this is the level for who it was allocated
    // TODO< maybe we save here for who exactly we had allocated it ? (except for kernel) >
};

Wenn der Kernel zum Beispiel 10 4-kb Seiten braucht sieht die Struktur nach dem reservieren wie folgt aus (die einzelnen Mappings für die Seiten):

Page 0                Page 1 - 10       Page 11
s_manage            |                 | s_manage
count = 10          | Data for Kernel | last = true
last = false        | (batch)         |
free = false        |                 |
level = KERNELLAND  |                 |

(Die Flags für die Seiten des Batches werden entsprechend der Anfrage gesetzt)

Small-System

Das Small System Teilt den Speicherbereich der vom Big-System gekommen ist nochmal ein weil der Kernel/Die Userland Programme meistens keine 4kb-Brocken brauchen.

Die Kontroll-Strukturen werden "out of Band" (außerhalb des Speicherbereichs wo die daten für das Programm/den Treiber später gespeicher werden) gespeichert.
Das hat den Vorteil das man es nicht so einfach überschreiben kann (wenn die Seite(n) wo die Kontroll-Daten liegen als Supervisor gekennzeichnet sind kann man als Treiber(Ring1/2?) und als User(ring3) nicht drauf zugreifen).

Wir nennen die Nutz-Strukturen hier "Junks".

Nutz-Strukturen
---------------

Das Prinzip ist das wir eine 4kb Seite n mal zerstückeln und so die Junks erhalten (wobei n = 1, 2, 3 ... 4096/8)(4096/8 weil ein 8 Byte-"Alignment" sehr gut ist).

n = 1
|                    4 kB Seite                                                 |

n = 2
|              2kb Junk                 |                 2 kb Junk             |

n = 3
4096/3 = 1365,3...(periode)

man sieht schon das der erste Junk 8 Byte aligned ist aber der zweite Junk ist es nicht, also was tun wir?

Wir wissen das der Junk kleiner sein soll als 1265 und durch 8 ohne rest teilbar (wegen dem Aligment), das heißt...

1365 % 8 = 5
so ziehen wir 5 bytes von der größe ab und wir liegen richtig
1365-5 = 1360

Das bedeutet das jeder Junk 1360 Bytes groß ist und die restlichen (4096 - 1360*3 = 16) Bytes werden am ende "verschmissen".
|       1360            |    1360               | 1368                   | ... |

usw.


Das Prinzip kann man natürlich auch nicht nur mit Seiten sondern auch mit größeren (8kb, 12kb, ...) Speicherbereichen machen.

Kontrollstrukturen
------------------

In den Kontrollstrukturen müssen wir nur speichern wie groß ein Junk ist und welche belegt/frei sind.


Irgendwelche Kritik oder Vorschläge, andere Techniken, pro/contra währ produktiv...


Zuletzt bearbeitet von Erhard Henkes am 19:47:30 21.03.2010, insgesamt 7-mal bearbeitet
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 13:32:30 21.02.2010   Titel:              Zitieren

Hi tty,

so ganz habe ich dein Konzept noch nicht verstanden. Wo genau willst du die Daten des Big Systems speichern? Und das Small-System, ist das dann quasi sowas wie ein Heap?
tty
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.02.2010
Beiträge: 2
Beitrag tty Mitglied 18:29:25 22.02.2010   Titel:              Zitieren

Hallo Badestrand,

Der Speicher der das Small-System bereitstellt kann man natürlich auch als "Heap" benutzen, aber es kann auch das konzept des pro-Programm-Heap ganz ersetzen (was auch Vorteile hat).
Die Speicherbereiche die das small-System abgibt haben eine n*4bk-Seiten Größe und sie können theoretisch belibig im Arbeitsspeicher gemappt werden (und weil es Seiten sind kann man auch die Zugriffsrechte setzen).

Die Daten des Big-System werden in den einzelnen Seiten (4kb) vor den "Nutzdaten"(fürn Kernel oder für die Anwendungen) Gespeichert.
Wobei man unter Daten folgendes versteht:
- was folgt nach der Seite in der die Daten über die folgenden Seiten Gespeichert sind?
- wie viele seiten folgen?

und das Beispiel was ich versucht habe zu illustrieren war das:
Code:
Page 0                Page 1 - 10       Page 11
s_manage            |                 | s_manage
count = 10          | Data for Kernel | last = true
last = false        | (batch)         |
free = false        |                 |
level = KERNELLAND  |                 |
Code:
Page 0 Page 1 - 10 Page 11
s_manage | | s_manage
count = 10 | Data for Kernel | last = true
last = false | (batch) |
free = false | |
level = KERNELLAND | |
Code:
Page 0                Page 1 - 10       Page 11
s_manage            |                 | s_manage
count = 10          | Data for Kernel | last = true
last = false        | (batch)         |
free = false        |                 |
level = KERNELLAND  |                 |

Wobei das aus der Sicht des Virtuellen Speichers ist (der physikalische Speicher kann über das Mapping oberhalb von 16 MB oder sonstwo gemappt werden, ist eigentlich egal wo das genau hinkommt.

Hoffentlich habe ich das verständlich erklärt.
Ich kann auch später bissel Code "nachschieben" (natürlich gut dokumentiert).


Zuletzt bearbeitet von tty am 18:05:08 23.02.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:41:58 27.02.2010   Titel:              Zitieren

Beschreibung des MM von Badestrand:
http://www.c-plusplus.de/forum/viewtopic-var-t-is- ....... days-is-0-and-postorder-is-asc-and-start-is-4.html


Zitat:
Hi Erhard, magst du das mal in's Forum schreiben, in den Memory-Management Thread von tty? Ich kann mich z.Zt. nicht einloggen, ab Sonntag aber wohl wieder...


von "Badestrand" per mail:

Hab da mal ein Dokument zum Memory Management verfasst*. Ich hoffe es genügt so, ansonsten bitte konkrete Kritik abgeben (und keine Scheu, ich kann damit umgehen). Falls im Source Code noch irgendwo was unklar ist, sponsore ich auch da gerne noch einige Kommentare. Den Bereich von MMIO hatte ich auf 0xF....... beschränkt, weil Erhard ID-Mapping brauchte und ich nicht zulassen wollte, dass plötzlich irgendwo mittendrin in den Heap oder gar in unseren Code irgendwelche Hardware-Sachen reingeschrieben werden. However, Erhard und ich hatten zum Glück am Anfang aneinander vorbeigeredet; da hatte ich was gecodet, was den angeforderten physischen Speicher einfach an eine freie virtuelle Adresse mappt und alles konfliktfrei abläuft. Ich baue es die Tage mal wieder ein, vielleicht funktioniert's ja. IRC und wieder ordentliches Internet geht bei mir hoffentlich wieder ab Sonntag (ich will das lieber nicht erklären, damit könnte ich mittlerweile ein ganzes Buch füllen..).

Auch generell zu Kritik am Memory System bin ich offen. Aber bitte auch hier konkrete Anmerkungen.

* http://www.file-upload.net/download-2297022/PrettyOS-Memory-Layout.pdf.html

@tty: Ich werde mir dein Konzept am Wochenende mal zu Gemüte führen. Mal sehen, wenn sich das als einfacher (zum Verständnis und in der Implementierung) erweist, könnten wir das Memory System auch neu schreiben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:43:57 21.03.2010, insgesamt 3-mal bearbeitet
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 01:10:57 13.03.2010   Titel:              Zitieren

PrettyOS Memory Layout

General Memory Layout
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
0 MB - 16 MB         For DMA only. Kernel code resides somewhere inbetween, I think
16 MB - 20 MB        For placement allocation while the heap is not set up. Here resides
                       - "Physical" bit table                        (128 KB)
                       - Kernel page directory                       (circa 8 KB)
                       - Kernel's page tables for 0 MB - 20 MB       (20 KB)
                       - Kernel's page tables for 3 GB - 4 GB        (1024 KB)
                       - Heap's "region" list (nongrowable)          (Remaining)
20 MB - 3 GB         Intended for user programs' code, stack, heap
3 GB - 0xFFF00000    For the kernel heap only; malloc'd memory resides here
0xFFF00000 - 4 GB    Memory mapped stuff. E.g. for the PCI area.
Code:
1
2
3
4
5
6
7
8
9
10
0 MB - 16 MB For DMA only. Kernel code resides somewhere inbetween, I think
16 MB - 20 MB For placement allocation while the heap is not set up. Here resides
- "Physical" bit table (128 KB)
- Kernel page directory (circa 8 KB)
- Kernel's page tables for 0 MB - 20 MB (20 KB)
- Kernel's page tables for 3 GB - 4 GB (1024 KB)
- Heap's "region" list (nongrowable) (Remaining)
20 MB - 3 GB Intended for user programs' code, stack, heap
3 GB - 0xFFF00000 For the kernel heap only; malloc'd memory resides here
0xFFF00000 - 4 GB Memory mapped stuff. E.g. for the PCI area.
Code:
1
2
3
4
5
6
7
8
9
10
0 MB - 16 MB         For DMA only. Kernel code resides somewhere inbetween, I think
16 MB - 20 MB        For placement allocation while the heap is not set up. Here resides
                       - "Physical" bit table                        (128 KB)
                       - Kernel page directory                       (circa 8 KB)
                       - Kernel's page tables for 0 MB - 20 MB       (20 KB)
                       - Kernel's page tables for 3 GB - 4 GB        (1024 KB)
                       - Heap's "region" list (nongrowable)          (Remaining)
20 MB - 3 GB         Intended for user programs' code, stack, heap
3 GB - 0xFFF00000    For the kernel heap only; malloc'd memory resides here
0xFFF00000 - 4 GB    Memory mapped stuff. E.g. for the PCI area.



About the code - Preface

The whole memory management code is contained in four files: paging.h, paging.c, kheap.h, kheap.c.
The interface (stuff in the header files) is designed to be as small as possible. The code itself is aimed to be most easy to understand, so the concepts and implementations are held rather simple than performant (also some optimizations were applied).
The implementation supports memory of up to 4 GB, requiring a page size of 4 KB.


About the physical memory management

As in most hobby OS, the physical memory is managed via a bit table, each bit reflects the state of a physical 4 KB memory frame. The state can be "free" or "reserved", resulting in a 0-bit for "free" and a 1-bit for "reserved".
To avoid calculations the bit table is 128 KB of size, thus covering 4 GB of memory.

No functions or data are exported, all functionality is used directly by the paging module. The code resides in the paging.c file, all functions and variables marked as "static".

Internal data structures:
The BIOS provides a "memory map", each entry specifying a memory block's address, size and whether it is usable for us.
C/C++ Code:
typedef struct
{
    uint64_t base;   // The region's address
    uint64_t size;   // The region's size
    uint32_t type;   // Is "1" for "free"
    uint32_t ext;    // Unimportant for us
} __attribute__((packed)) mem_map_entry_t;
C/C++ Code:
typedef struct
{
uint64_t base; // The region's address
uint64_t size; // The region's size
uint32_t type; // Is "1" for "free"
uint32_t ext; // Unimportant for us
} __attribute__((packed)) mem_map_entry_t;
C/C++ Code:
typedef struct
{
    uint64_t base;   // The region's address
    uint64_t size;   // The region's size
    uint32_t type;   // Is "1" for "free"
    uint32_t ext;    // Unimportant for us
} __attribute__((packed)) mem_map_entry_t;


The internal variables:
Pointer to the bit table. We access 32 bits at a time since we cannot directly access each bit on it's own.
C/C++ Code:
uint32_t* bittable;
C/C++ Code:
uint32_t* bittable;
C/C++ Code:
uint32_t* bittable;


When we (linearly) search for a free frame, it is a waste to always start searching at bit 0. So an optimization is applied in that we remember the first possible integer which might contain a free bit.
C/C++ Code:
uint32_t first_free_dword;
C/C++ Code:
uint32_t first_free_dword;
C/C++ Code:
uint32_t first_free_dword;


The internal functions:
Scans through the memory map to find out whether the specified physical range (from beg inclusively to end exclusively) is free for use. Independent from the bit table, does not use the internal variables. Returns true if the area is free for use.
C/C++ Code:
bool memorymap_availability( const mem_map_entry_t* entries, uint64_t beg, uint64_t end )
C/C++ Code:
bool memorymap_availability( const mem_map_entry_t* entries, uint64_t beg, uint64_t end )
C/C++ Code:
bool memorymap_availability( const mem_map_entry_t* entries, uint64_t beg, uint64_t end )


Sets the appropiate bits in the bittable for the physical address range given by addr_begin and addr_end.
C/C++ Code:
void phys_set_bits( uint32_t addr_begin, uint32_t addr_end, bool reserved )
C/C++ Code:
void phys_set_bits( uint32_t addr_begin, uint32_t addr_end, bool reserved )
C/C++ Code:
void phys_set_bits( uint32_t addr_begin, uint32_t addr_end, bool reserved )


Does the initialization. At first, the memory map's entries get constrained to 4 GB in case they exceed that mark. Subsequently we check whether the region 16 MB - 20 MB is marked as free in the memory map as we want to store our private data here.
Afterwards we allocate the bit table, set it's bits according to the memory map, reserve 0 MB - 20 MB, initialize first_free_dword and determine and return the amount of available memory.
C/C++ Code:
uint32_t phys_init()
C/C++ Code:
uint32_t phys_init()
C/C++ Code:
uint32_t phys_init()


Allocates (flips the appropiate bit from "free" to "reserved") a random 4 KB physical frame and returns the physical address. Adjusts the first_free_dword variable if necessary.
C/C++ Code:
uint32_t phys_alloc()
C/C++ Code:
uint32_t phys_alloc()
C/C++ Code:
uint32_t phys_alloc()


De-allocates the given 4 KB physical frame by setting it's bit to "reserved" and besides eventually adjusts first_free_dword.
C/C++ Code:
void phys_free( uint32_t addr )
C/C++ Code:
void phys_free( uint32_t addr )
C/C++ Code:
void phys_free( uint32_t addr )



About the paging facility

Uses conventional data structures and concepts. There are page directories and page tables. However, there may be one unconventional detail: All page tables for memory that belongs to the kernel are pre-allocated so there won't be a need to adjust all user page directories in case of (e.g. heap-) changes.

Several functions are exported but neither the datastructures nor the kernel's page directory address are. The code resides in the paging.c file.

Internal data structures:
Holds the page tables' physical and virtual pointers as well as it's own physical address.
C/C++ Code:
struct page_directory_
{
    uint32_t      codes[1024];
    page_table_t* tables[1024];
    uint32_t      pd_phys_addr;
} __attribute__((packed));
C/C++ Code:
struct page_directory_
{
uint32_t codes[1024];
page_table_t* tables[1024];
uint32_t pd_phys_addr;
} __attribute__((packed));
C/C++ Code:
struct page_directory_
{
    uint32_t      codes[1024];
    page_table_t* tables[1024];
    uint32_t      pd_phys_addr;
} __attribute__((packed));


Holds the page mappings: Their physical addresses and flags.
C/C++ Code:
typedef struct
{
    uint32_t pages[1024];
} page_table_t;
C/C++ Code:
typedef struct
{
uint32_t pages[1024];
} page_table_t;
C/C++ Code:
typedef struct
{
    uint32_t pages[1024];
} page_table_t;


The internal variables:
A pointer to the kernel's page directory.
C/C++ Code:
page_directory_t* kernel_pd;
C/C++ Code:
page_directory_t* kernel_pd;
C/C++ Code:
page_directory_t* kernel_pd;


The internal functions:
Returns the mapped physical address for the given page directory and virtual address.
C/C++ Code:
uint32_t paging_get_phys_addr( page_directory_t* pd, void* virt_addr )
C/C++ Code:
uint32_t paging_get_phys_addr( page_directory_t* pd, void* virt_addr )
C/C++ Code:
uint32_t paging_get_phys_addr( page_directory_t* pd, void* virt_addr )


The exported functions:
Setups the physical and paging management. Invokes phys_init, allocates and fills the kernel's page directory. Does identity mapping for 0 MB - 20 MB, sets the video area user-accessible (although I think we don't need that any more), initializes the page table for the kernel heap. The heap's page table entries remain unmapped here, i.e. they don't specify a physical address. Finally the actual paging is enabled in the CPU.
C/C++ Code:
uint32_t paging_install()
C/C++ Code:
uint32_t paging_install()
C/C++ Code:
uint32_t paging_install()

Allocates the given amount (size) of memory and maps it consecutively to the given virtual address. E.g. for enhancing the user's heap, call paging_alloc( user_pd, heap_end, _1MB, MEM_USER | MEM_WRITE ).
C/C++ Code:
bool paging_alloc( page_directory_t* pd, void* virt_addr, uint32_t size, uint32_t flags )
C/C++ Code:
bool paging_alloc( page_directory_t* pd, void* virt_addr, uint32_t size, uint32_t flags )
C/C++ Code:
bool paging_alloc( page_directory_t* pd, void* virt_addr, uint32_t size, uint32_t flags )

Frees the memory that was allocated by paging_alloc. As the paging module does not store the size for manually allocated blocks, you have to provide it here.
C/C++ Code:
void paging_free( page_directory_t* pd, void* virt_addr, uint32_t size )
C/C++ Code:
void paging_free( page_directory_t* pd, void* virt_addr, uint32_t size )
C/C++ Code:
void paging_free( page_directory_t* pd, void* virt_addr, uint32_t size )

Creates a page directory, copies the kernel's entries into it and returns it's address.
C/C++ Code:
page_directory_t* paging_create_user_pd()
C/C++ Code:
page_directory_t* paging_create_user_pd()
C/C++ Code:
page_directory_t* paging_create_user_pd()

Delete a page directory that you created by a call to paging_create_user_pd. All valid mappings of memory registered in that page directory that do not belong to the kernel get freed. Finally the page directory itself is freed.
C/C++ Code:
void paging_destroy_user_pd( page_directory_t* pd )
C/C++ Code:
void paging_destroy_user_pd( page_directory_t* pd )
C/C++ Code:
void paging_destroy_user_pd( page_directory_t* pd )

Switches to the given page directory.
C/C++ Code:
void paging_switch( page_directory_t* pd )
C/C++ Code:
void paging_switch( page_directory_t* pd )
C/C++ Code:
void paging_switch( page_directory_t* pd )



About the heap

The heap provides the malloc/free-functionality, i.e. dynamic allocation of memory. It manages a certain amount of continuous virtual memory, starting at "heap_start". Whenever more memory is requested than there is available, the heap expands.
For expansion, the heap asks the paging module to map physical memory to the following virtual addresses and increases it's "heap_size" variable afterwards.

To manage the free and reserved (allocated) areas of the heap, an array of "region" elements is held. Each region specifies it's size and whether it is reserved/allocated. Free regions always get merged. Regions don't store their addresses, the third region's address is calculated by adding the first and second region's size to "heap_start":
region_3_addr = heap_start + regions[0].size + regions[1].size.

Before the heap is set up memory is allocated on a "placement address". This is an identity mapped area of continuous memory, the allocation just moves a pointer forward by the requested size and returns it's previous value.

The heap's management data is placed at this placement address, too. Since this area cannot grow, the heap has a maximum amount of region-objects ("region_max_count").

Internal data structures:
Holds the info about a single region.
C/C++ Code:
typedef struct
{
    uint32_t size;
    bool     reserved;
} region_t;
C/C++ Code:
typedef struct
{
uint32_t size;
bool reserved;
} region_t;
C/C++ Code:
typedef struct
{
    uint32_t size;
    bool     reserved;
} region_t;


The internal variables:
Pointer to the array of region objects. This array is not resizeable as it resides in the placement allocation area.
C/C++ Code:
region_t* regions = NULL;
C/C++ Code:
region_t* regions = NULL;
C/C++ Code:
region_t* regions = NULL;

Number of currently used region objects and the maximum count of region objects that fit into the regions-array.
C/C++ Code:
uint32_t  region_count = 0;
uint32_t  region_max_count = 0;
C/C++ Code:
uint32_t region_count = 0;
uint32_t region_max_count = 0;
C/C++ Code:
uint32_t  region_count = 0;
uint32_t  region_max_count = 0;

Current size that the heap takes up. Grows dynamically when needed.
C/C++ Code:
uint32_t  heap_size = 0;
C/C++ Code:
uint32_t heap_size = 0;
C/C++ Code:
uint32_t  heap_size = 0;


The internal functions:
Receives a pointer to the heap's end and appends size bytes of memory to it. The region-array is adjusted, too.
C/C++ Code:
bool heap_grow( uint32_t size, char* heap_end )
C/C++ Code:
bool heap_grow( uint32_t size, char* heap_end )
C/C++ Code:
bool heap_grow( uint32_t size, char* heap_end )


The exported functions:
Setups the internal variables.
C/C++ Code:
void heap_install()
C/C++ Code:
void heap_install()
C/C++ Code:
void heap_install()

Allocates the requested amount of memory, assuring the given alignment. Eventually lets the heap grow.
C/C++ Code:
void* malloc( uint32_t size, uint32_t alignment )
C/C++ Code:
void* malloc( uint32_t size, uint32_t alignment )
C/C++ Code:
void* malloc( uint32_t size, uint32_t alignment )

Frees the previously allocated memory.
C/C++ Code:
void free( void* addr )
C/C++ Code:
void free( void* addr )
C/C++ Code:
void free( void* addr )



Miscellaneous

Maps some virtual address to the given physical address and returns that virtual address. Use this for memory mapped IO.
C/C++ Code:
void* paging_acquire_pcimem( uint32_t phys_addr )
C/C++ Code:
void* paging_acquire_pcimem( uint32_t phys_addr )
C/C++ Code:
void* paging_acquire_pcimem( uint32_t phys_addr )


Zuletzt bearbeitet von Badestrand am 15:36:25 13.03.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:47:14 13.03.2010   Titel:              Zitieren

wir haben im makefile -O. Das bedeutet ja minimale Optimierung. Wenn man es entfernt oder -O0 (o null) schreibt, kracht es in malloc.

kernel/kheap.c: In function 'malloc':
kernel/kheap.c:104: error: initializer element is not constant :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 15:18:45 13.03.2010   Titel:              Zitieren

Erhard Henkes schrieb:
kernel/kheap.c:104: error: initializer element is not constant :rolleyes:

Witzig, weil ist 'ne Konstante. Dann wird es halt zum define.
Crasht dann aber mit -O0 beim Übergang von init nach main. Ist echt anstrengend zu debuggen.
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 15:22:18 13.03.2010   Titel:              Zitieren

Steckt man die paar Zeilen der init-Funktion direkt an den Anfang der main-Funktion, klappt alles. Verrücktes Verhalten. Ich würde sagen, wir lassen es erstmal bei -O.
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 15:31:40 13.03.2010   Titel:              Zitieren

Der Code ist sehr wahrscheinlich auch mit -O kaputt, nur subtiler. Solche Bugs werden vom Liegenlassen jedenfalls meistens nicht einfacher.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 15:56:28 13.03.2010   Titel:              Zitieren

Da hast du wohl recht.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 18:25:16 13.03.2010   Titel:              Zitieren

Oder es fehlt einfach irgendwo ein "volatile"...
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 18:29:16 13.03.2010   Titel:              Zitieren

Bei Treibern mag das ja regelmäßig vorkommen, aber eine Speicherverwaltung, die volatile braucht, wäre mir suspekt. ;)

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 18:34:41 13.03.2010   Titel:              Zitieren

An der Speicherverwaltung kann es gar nicht liegen, die wird erst später initialisiert, nach dem Crash. Der Code, der bis zum Absturz durchlaufen wird, ist auch relativ überschaubar. Direkt nach dem Eintritt in die main-Funktion wird die "init"-Funktion aufgerufen, die folgende Sachen ausführt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
clear_screen();
settextcolor(14,0);
printformat("PrettyOS [Version 0.0.0.221]\n");
gdt_install();
idt_install();
timer_install();
keyboard_install();
syscall_install();
settextcolor(15,0);
C/C++ Code:
1
2
3
4
5
6
7
8
9
clear_screen();
settextcolor(14,0);
printformat("PrettyOS [Version 0.0.0.221]\n");
gdt_install();
idt_install();
timer_install();
keyboard_install();
syscall_install();
settextcolor(15,0);
C/C++ Code:
1
2
3
4
5
6
7
8
9
clear_screen();
settextcolor(14,0);
printformat("PrettyOS [Version 0.0.0.221]\n");
gdt_install();
idt_install();
timer_install();
keyboard_install();
syscall_install();
settextcolor(15,0);


Auf den ersten Blick in diese Funktionen sieht das alles recht ungefährlich aus. Die Sachen laufen auch gut durch, beim return geht irgendwas schief, scheint also der Stack kaputt zu sein. Bloß woher :confused: Ich bin schon dabei, zu debuggen und zu disassemblern, ist aber eine eklige Arbeit..
Unregistrierter





Beitrag Unregistrierter 19:03:53 13.03.2010   Titel:              Zitieren

Ist eher alles ein Problem mit den Kompilerflags. Folgendes Beispiel:

C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
// ckernel.c Revision 219

int main()
{
for(;;); // <- Endlosschleife :)

    init();
(...)
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
// ckernel.c Revision 219

int main()
{
for(;;); // <- Endlosschleife :)

init();
(...)
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
// ckernel.c Revision 219

int main()
{
for(;;); // <- Endlosschleife :)

    init();
(...)
}

Ohne Flag "-O" stürzt PrettyOS ab, woraus vorerst nur folgen soll, daß die Endlosschleife nicht ausgeführt wurde (also "verschwunden" ist).

Mit Flag "-O" bleibt PrettyOS in der Endlosschleife hängen, was heißt, daß sie nicht "verschwunden" ist.

Daraus folgt, daß der GCC auch ohne Angabe von Optionen zur Optimierung den Quellcode wie auch immer verändert. Insofern wirst Du wahrscheinlich im Quellcode auch keine Fehler finden. :)
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 19:10:09 13.03.2010   Titel:              Zitieren

Da läuft beim Linken was schief, aber ist der Grund jetzt klar. Der eigentlich als Einstiegscode gedachte "KernelStart" liegt irgendwo in der Mitte des Binaries.

Mit Compiler-Option -O0 wird die "init"-Funktion nicht ge-inline-t und liegt am Anfang des Binaries, d.h. der Code springt direkt in die init-Funktion, ohne vorher in der "main" gewesen zu sein. Logisch, dass dann keine gültige Rücksprungadresse auf dem Stack liegt und es kracht.

Mit -O wird die "init"-Funktion ge-inline-t und die "main"-Funktion liegt direkt am Anfang des Binaries. Damit klappt es zwar, ist aber nicht im Sinne des Erfinders, die "KernelStart"-Funktion gibt es ja nicht umsonst, sie setzt z.B. den Stack auf 0x01900000.

D.h. irgendwie bekommt der Linker es nicht hin, die "KernelMain" an den Anfang des Binaries zu setzen, obwohl die Funktion im Linkerscript als "ENTRY" markiert ist. Hat jemand eine Idee?

edit: Danke, +gjim+!


Zuletzt bearbeitet von Badestrand am 19:11:01 13.03.2010, insgesamt 1-mal bearbeitet
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 19:17:32 13.03.2010   Titel:              Zitieren

Ok, habs. Im Linkerscript muss STARTUP(kernel.o) gesetzt sein, das ENTRY spielt keine Rolle. Ich comitte.

edit: Was für ein Krampf :)


Zuletzt bearbeitet von Badestrand am 19:17:45 13.03.2010, insgesamt 1-mal bearbeitet
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 95
Beitrag XanClic Mitglied 19:49:33 13.03.2010   Titel:              Zitieren

Trotzdem könnte man hier mal anmerken, dass man genau wegen sowas ELF oder ähnliche Formate will (die also einen Entrypoint haben)...

_________________
http://www.lowlevel.eu/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:11:37 21.03.2010   Titel:              Zitieren

Eine Frage aus dem IRC:
Zitat:
ich frag mich, ob es wirklich nötig ist, die page tables für den kernel bereich im voraus zu allokieren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
lk
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.03.2009
Beiträge: 213
Beitrag lk Mitglied 18:08:41 29.07.2011   Titel:              Zitieren

Kann jemand die meory map irgendwie erwitern ? Mehr details wären cool, vielleicht auch graphisch.

Apropo, ich kann auch osdev.org empfehlen.

_________________
Wird wahrscheinlich falsch sein, aber wat solls. :)
Und wenn man am Ende der Kräfte ist: jmp 0xC0FFEE
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1074
Beitrag Mr X Mitglied 18:14:53 29.07.2011   Titel:              Zitieren

Im Repository befindet sich unter /documentation/memory.txt eine detailiertere und aktuellere Übersicht.
C/C++ Forum :: Projekt: OS-Development  ::  Memory Managment   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum nicht antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.