Get Memory Map - Freien Speicher bestimmen


  • Mod

    INT 0x15, EAX = 0xE820 ... available on all PCs built since 2002

    http://wiki.osdev.org/Detecting_Memory_(x86)#Getting_an_E820_Memory_Map

    Ich würde in PrettyOS gerne den physikalischen Speicher zuverlässig messen, da ich diesen an einer Stelle für die Zahl der Frames benötige.
    Mein Bootloader arbeitet momentan nur mit [Bits 16] (oder weg lassen) richtig, aber nicht mit [Bits 32] (wird zwar übersetzt, funktioniert aber nicht, nur Reset).
    Für obigen Code bräuchte ich aber eine 32-Bit-Umgebung, wenn ich das richtig sehe. Diese habe ich erst nach dem Sprung nach PM, dort ist dann aber int 0x15 weg.



  • Der sollte im Real Mode funktionieren. Die BIOS-Funktion wäre sonst ziemlich sinnfrei 😉 Die 32 Bit Register stehen dir (auf einem 386er und aufwärts) im Real Mode zur freien Verfügung.


  • Mod

    Die 32 Bit Register stehen dir (auf einem 386er und aufwärts) im Real Mode zur freien Verfügung.

    OK, daher geht auch so etwas wie hier:

    switch_to_PM:	
        mov eax, cr0      ; switch-over to Protected Mode
        or  eax, 1        ; set bit 0 of CR0 register
        mov cr0, eax      ;
    

    Was bewirkt dann die Angabe [Bits 16], [Bits 32], < nichts angeben >, die sich ja auf die Operationen bezieht, genau in diesem Zusammenhang bei NASM? Kann ich diese BIOS-Funktion mit [Bits 16] sinnvoll ausführen?

    Ich habe die Funktion eingebaut und rufe sie im Bootloader auf. Zumindest wird alles übersetzt, und das OS bootet noch. Wird langsam eng in den 512 Byte. Nun muss ich mal schauen, wie ich meine Werte zusammen suche und an den C-Kernel übergebe. 🙂



  • Von http://developer.apple.com/documentation/DeveloperTools/nasm/nasmdoc5.html (Google scheint die Nasm Dokumentation von Apple irgendwie zu bevorzugen):

    You do not need to specify BITS 32 merely in order to use 32-bit instructions in a 16-bit DOS program; if you do, the assembler will generate incorrect code because it will be writing code targeted at a 32-bit platform, to be run on a 16-bit one.

    When NASM is in BITS 16 state, instructions which use 32-bit data are prefixed with an 0x66 byte, and those referring to 32-bit addresses have an 0x67 prefix. In BITS 32 state, the reverse is true: 32-bit instructions require no prefixes, whereas instructions using 16-bit data need an 0x66 and those working on 16-bit addresses need an 0x67.

    Die BITS Direktive scheint also nur etwas mit der Auswahl der passenden "echten" Maschinenbefehle zu tun.


  • Mod

    Danke für die interessante Information.

    Ich überlege gerade, wo ich den Puffer für die Listen hinlege:
    Stack ist bei 0x7000, bootloader liegt bei 0x7C00 und lädt den Kernel beginnend ab 0x10000. Also wäre doch Platz für solche Dinge ab 0x8000, also ES:DI = 0x0000:8000 ?

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Determine physical memory                  ;
    ;                                            ;
    ;   input:                                   ;
    ;   es:di -> destination buffer              ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    xor ax, ax
    mov es, ax
    mov ax, 0x8000
    mov di, ax
    call get_memory_by_int15_e820
    

    Hinterher landet der "entry count" hier:

    mov [mmap_ent], bp	            ; store the entry count
    

    Ich habe da mal Platz für mmap_ent gehalten:

    mmap_ent dw 0
    

    Ist define word o.k., bp ist doch 16 bit?

    Hab's mal eingebaut, sowas in der Art finde ich aber noch nicht in bochs output:

    Typical Output by a call to INT 15h, EAX=E820 in Bochs:

    Base Address | Length | Type
    0x0000000000000000 | 0x000000000009FC00 | Free Memory (1)
    0x000000000009FC00 | 0x0000000000000400 | Reserved Memory (2)
    0x00000000000E8000 | 0x0000000000018000 | Reserved Memory (2)
    0x0000000000100000 | 0x0000000001F00000 | Free Memory (1)
    0x00000000FFFC0000 | 0x0000000000040000 | Reserved Memory (2)

    Kann ich mir jetzt vom C-Kernel nach dem Sprung nach PM die Zahlen ab 0x8000 einlesen? Wie finde ich von C aus dieses mmap_ent? Assembler ist leider nicht meine Homebase, wird aber sicher noch, wenn ich so weiter mache und mich GRUB trotzig widersetze. 😃

    Hier ein Ausdruck aus dem C-Kernel (als ULONG, da muss man wegen little endian sicher noch etwas ändern) beginnend ab 0x8000:

    // physical memory
        ULONG i;
        for(i=0; i<80; i+=4)
            printformat("%x: %x\n",0x8000+i,( *( (ULONG*)(0x8000+i) ) ) );
    

    00008000h: 00000000h
    00008004h: 00000000h
    00008008h: 0009F000h
    0000800Ch: 00000000h
    00008010h: 00000001h
    00008014h: 00000001h
    00008018h: 0009F000h
    0000801Ch: 00000000h
    00008020h: 00001000h
    00008024h: 00000000h
    00008028h: 00000002h
    0000802Ch: 00000001h
    00008030h: 000E8000h
    00008034h: 00000000h
    00008038h: 00018000h
    0000803Ch: 00000000h
    00008040h: 00000002h
    00008044h: 00000001h
    00008048h: 00100000h
    0000804Ch: 00000000h

    qword sind dann doch zwei ULONG, dword ist ein ULONG.

    * First qword = Base address
    * Second qword = Length of "region" (if this value is 0, ignore the entry)
    * Next dword = Region "type"
    o Type 1: Usable (normal) RAM
    o Type 2: Reserved - unusable
    o Type 3: ACPI reclaimable memory
    o Type 4: ACPI NVS memory
    o Type 5: Area containing bad memory
    * Next dword = ACPI 3.0 Extended Attributes bitfield (if 24 bytes are returned, instead of 20)
    o Bit 0 of the Extended Attributes indicates if the entire entry should be ignored (if the bit is clear). This is going to be a huge compatibility problem because most current OSs won't read this bit and won't ignore the entry.
    o Bit 1 of the Extended Attributes indicates if the entry is non-volatile (if the bit is set) or not. The standard states that "Memory reported as non-volatile may require characterization to determine its suitability for use as conventional RAM."
    o The remaining 30 bits of the Extended Attributes are currently undefined.

    D.h. pro Eintrag müssten es qword, qword, dword, dword also 6 ULONG oder 24 BYTE sein.



  • Erhard Henkes schrieb:

    Wie finde ich von C aus dieses mmap_ent? Assembler ist leider nicht meine Homebase, wird aber sicher noch, wenn ich so weiter mache und mich GRUB trotzig widersetze. 😃

    Da es auch nicht gerade mein Spezielgebiet ist (vor allem keine praktische Erfahrung) kann ich grad auch nur (mit Begründung) drauflos raten und weiß weder ob es elegant oder richtig ist.

    Nach meinem Verständniss ist bei dem Bootloader, der ja im Bin Format vorliegt und nicht gelinkt wird, Code und Daten zusammengewürftelt und so hinternander wie man es in den Assemblercode schreibt. Wir wissen, dass der Bootloader an der Stelle 0x7C00 liegt, und mmap_ent liegt dann an irgendeinem Offset von dort aus, den wir geeignet wählen sollten. Offset 0 geht nicht, da dort ein Befehl liegen sollte, da das Bios dorthin springt um den Bootloader auszuführen. Daher würde ich es ans Ende (natürlich vor den Magic-Werten) schreiben. Also nur noch bis 509 bytes mit Nullen füllen und dann dort mmap_ent hinlegen. Die Adresse ist dann fest 0x7DFD (0x7C00 + 509).

    Erhard Henkes schrieb:

    Kann ich mir jetzt vom C-Kernel nach dem Sprung nach PM die Zahlen ab 0x8000 einlesen?

    Davon gehe ich aus, sonst würde meine Idee auch nicht funktionieren 😃


  • Mod

    Also nur noch bis 509 bytes mit Nullen füllen und dann dort mmap_ent hinlegen. Die Adresse ist dann fest 0x7DFD (0x7C00 + 509).

    Danke, gute Idee! Da ich wegen bp ein "word" frei gehalten habe, werde ich aber 2 Byte vorsehen:

    bootdrive db 0    
        loadmsg db "loading kernel ...",13,10,0
        errormsg db "sector read error ...",13,10,0
        progressmsg db "*",0
    
        times 508-($-$$) hlt
        mmap_ent dw 0 
        db 0x55
        db 0xAA
    

    Habe mir das in MyOS.bin mit dem Hex-Editor angeschaut:
    f4 f4 f4 00 00 55 aa (exakt am richtgien Platz zum Booten)

    0x7C00 + 508 = 0x7DFC

    printformat("%x: %x\n\n",0x7DFC,( *( (USHORT*)(0x7DFC) ) ) );
    

    00007DFCh: 00000006h

    6 Einträge

    Ich habe mal den Test durchgeführt und die Funktion nicht aufgerufen, sieht gut aus:

    00007DFCh: 00000000h

    00008000h: 00000000h
    00008004h: 00000000h
    00008008h: 00000000h
    0000800Ch: 00000000h
    00008010h: 00000000h
    00008014h: 00000000h
    00008018h: 00000000h
    0000801Ch: 00000000h
    00008020h: 00000000h
    00008024h: 00000000h
    00008028h: 00000000h
    0000802Ch: 00000000h
    00008030h: 00000000h
    00008034h: 00000000h
    00008038h: 00000000h
    0000803Ch: 00000000h
    00008040h: 00000000h
    00008044h: 00000000h
    00008048h: 00000000h
    0000804Ch: 00000000h

    🙂

    Jetzt muss ich mir nur noch die Infos passend zusammen suchen. Ein kleines Puzzle. 😉

    Habe mir das jetzt mal auf einem richtigen PC (512 MB RAM = 0x1FFFFFFF) angeschaut:
    Zahl der Einträge: 5 (wie erwartet) 🙂

    Erster Eintrag: (im Ausdruck alles ULONG also dword, beim qword daher zuerst low dword, dann high dword)

    qword,         qword,               dword,          dword
    0x0 0x0        0xA0000 0x0          0x1             0x1
    Base address   Length of "region"   Region "type"   Extended Attributes bitfield
                   if this value is 0,  Type 1: 
                   ignore the entry     Usable RAM      Bit0: 1 ignore if clear
                                                        Bit1: 0 volatile (?)
    

    sieht gut aus:
    Erste Region geht also bis 0xA0000 und ist normales RAM, klingt vernünftig:
    http://www.henkessoft.de/OS_Dev/Bilder/Speicherbelegung.JPG

    Zweiter Eintrag: (im Ausdruck alles ULONG also dword)

    qword,         qword,               dword,          dword
    0xF0000 0x0    0x10000 0x0          0x2             0x1
    Base address   Length of "region"   Region "type"   Extended Attributes bitfield
                   if this value is 0,  Type 2: 
                   ignore the entry     Reserved        Bit0: 1 ignore if clear
                                        = unusable      Bit1: 0 volatile (?)
    

    Dritter Eintrag: (im Ausdruck alles ULONG also dword)

    qword,         qword,               dword,          dword
    0x100000 0x0   0x1FEF0000 0x0       0x1             0x1
    Base address   Length of "region"   Region "type"   Extended Attributes bitfield
                   if this value is 0,  Type 1: 
                   ignore the entry     Usable RAM      Bit0: 1 ignore if clear
                                                        Bit1: 0 volatile (?)
    

    Beim vierten Eintrag sehe ich momentan nur die Basisadesse:
    0x1FFF0000

    Da muss ich meine Printroutine erweitern und umbauen, am besten gleich mit Auswertung nach diesem Schema. 🙂

    Zusammengefasst (hex):
    0 - A0000 RAM
    F0000 - 100000 Reserved
    100000 - 1FFF0000 RAM
    1FFF0000 - ? ...

    Super! Hat perfekt geklappt, wenn ich es richtig sehe, außer diesem non-volatil/volatil (Bit1 von letztem DWORD: 1=non-volatil 0=volatil, die 0x1 für das DWORD bedeutet für Bit1 = 0, also volatil) haut alles bestens hin.

    Danke für die moralische Unterstützung und die Tipps! 👍
    Jetzt muss das nur noch auf möglichst vielen PCs klappen.


  • Mod

    Hier ist das Foto der vollständigen Memory-Analyse des untersuchten PC:
    http://www.henkessoft.de/OS_Dev/Bilder/detect_memory.JPG

    Zurück zur Frage der Bestimmung des "Physical Memory" des untersuchten Rechners. Wenn ich das richtig sehe, muss man nun die "length" der Speicherbereiche addieren, die "type" gleich 1 (usable RAM) haben.

    Region "type"

    * Type 1: Usable (normal) RAM
    * Type 2: Reserved - unusable
    * Type 3: ACPI reclaimable memory
    * Type 4: ACPI NVS memory
    * Type 5: Area containing bad memory

    Das wären in diesem konkreten Fall (RAM 512 MB wird beim Booten angezeigt):
    0xA0000 + 0x1FEF0000 = 0x1FF90000 = 536412160 Byte = 523840 KB = 511,5625 MB

    0xA0000 = 640 KB ("low memory")

    Passt also sehr gut. 😉

    Ich habe diese Experimente hier dokumentiert:
    http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId584885

    So kann man das sehr schön als Gesamt Usable RAM erfassen und anzeigen:

    typedef struct Mem_Chunk_struct
     {
       ULONG base_lo;
       ULONG base_hi;
       ULONG length_lo;
       ULONG length_hi;
       ULONG type;
       ULONG extended;
     }Mem_Chunk_t;
    //...
    Mem_Chunk_t Mem_Chunk[10]; // contiguous parts of memory detected by int 15h eax = 820h
        //...
    
        // physical memory
        USHORT num_of_entries = *( (USHORT*)(0x7DFC) );
    
        //printformat("# entries: %d\n\n",(num_of_entries) );
        //printformat("base                length              type      extended\n");
    
        pODA->Memory_Size = 0;
        ULONG i,j;
        for(i=0; i<num_of_entries; ++i)
        {
            //printformat("\n");
            for(j=0; j<24; j+=4)
            {
                if(j== 0) Mem_Chunk[i].base_lo   = *( (ULONG*)(0x8000+i*24+j) );
                if(j== 4) Mem_Chunk[i].base_hi   = *( (ULONG*)(0x8000+i*24+j) );
                if(j== 8) Mem_Chunk[i].length_lo = *( (ULONG*)(0x8000+i*24+j) );
                if(j==12) Mem_Chunk[i].length_hi = *( (ULONG*)(0x8000+i*24+j) );
                if(j==16) Mem_Chunk[i].type      = *( (ULONG*)(0x8000+i*24+j) );
                if(j==20) Mem_Chunk[i].extended  = *( (ULONG*)(0x8000+i*24+j) );
    
                // printformat("%x ", *( (ULONG*)(0x8000+i*24+j) ) );
            }
            if((Mem_Chunk[i].type)==1) pODA->Memory_Size += Mem_Chunk[i].length_lo;
            // printformat("\n");
        }
        printformat("\nUsable RAM: %d KB", (pODA->Memory_Size)/1024);
        printformat("\n\n");
    

    PrettyOS [Version 0.1.0087] (C) 2009 henkessoft.de

    Usable RAM: 523840 KB

    Command Line:
    $>


  • Mod

    Könnte ein Mod diesen Thread bitte nach OS-Development verschieben?



  • Dieser Thread wurde von Moderator/in Nobuo T aus dem Forum Assembler in das Forum Projekt: OS-Development verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


Anmelden zum Antworten