Продолжаю эксперименты с разработкой ОС. См. также: Совмещение 16-ти битного и 32-битного кода в ядре.
Для работы Операционной системе необходимо определить сколько и какой памяти доступно для работы. Современный способ определения доступной памяти основан на использовании функции BIOS 0x15, EAX = 0xE820. Этой функции достаточно на современном железе, на старом, могут потребоваться другие функции.
Подробно о различных механизмах определения доступной памяти рассказано в 2-х источниках:
- http://wiki.osdev.org/Detecting_Memory_(x86)
- http://ru.osdev.wikia.com/wiki/Определение_объёма_памяти
Вкратце, память определяется циклическим обращением к функции 0x15, EAX = 0xE820. В регистр EBX при первом обращении указывается 0, при последующих обращениях в EBX просто оставляется то, что возвратило предыдущее обращение к функции. Результат возвращается в виде 24 байтных записей. Адрес для возвращаемых записей передается в ES:DI.
Формат записей такой
- First qword = Base address
- Second qword = Length of «region» (if this value is 0, ignore the entry)
- Next dword = 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
- Next dword = ACPI 3.0 Extended Attributes bitfield (if 24 bytes are returned, instead of 20)
- 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.
- 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.»
- The remaining 30 bits of the Extended Attributes are currently undefined.
Я воспользовался функцией приведенной в первой ссылке для определения объема памяти. Функция в качестве параметра получает [ds:si]. Туда будут записаны все записи о доступной памяти. Результат функции — регистр bp с количеством полученных записей. При возникновении ошибки, функция выставляет флаг CF. Функция портит все регистры, кроме esi.
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map ; inputs: es:di -> destination buffer for 24 byte entries ; outputs: bp = entry count, trashes all registers except esi global i16MemDetect section .text [bits 16] i16MemDetect: xor ebx, ebx ; ebx must be 0 to start mov di, bx xor bp, bp ; keep an entry count in bp mov edx, 0x0534D4150 ; Place "SMAP" into edx mov eax, 0xe820 mov dword [es:di + 20], 1 ; force a valid ACPI 3.X entry mov ecx, 24 ; ask for 24 bytes int 0x15 jc short .failed ; carry set on first call means "unsupported function" mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register? cmp eax, edx ; on success, eax must have been reset to "SMAP" jne short .failed test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless) je short .failed jmp short .jmpin .e820lp: mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call mov dword [es:di + 20], 1 ; force a valid ACPI 3.X entry mov ecx, 24 ; ask for 24 bytes again int 0x15 jc short .e820f ; carry set means "end of list already reached" mov edx, 0x0534D4150 ; repair potentially trashed register .jmpin: jcxz .skipent ; skip any 0 length entries cmp cl, 20 ; got a 24 byte ACPI 3.X response? jbe short .notext test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear? je short .skipent .notext: mov ecx, [es:di + 8] ; get lower dword of memory region length or ecx, [es:di + 12] ; "or" it with upper dword to test for zero jz .skipent ; if length qword is 0, skip entry inc bp ; got a good entry: ++count, move to next storage spot add di, 24 .skipent: test ebx, ebx ; if ebx resets to 0, list is complete jne short .e820lp .e820f: clc ; there is "jc" on end of list to this point, so the carry must be cleared ret .failed: stc ; "function unsupported" error exit ret
В результате применения получаю такую таблицу памяти.
В этой таблице пока наиболее интересными являются записи, у которых в третьем поле единичка. Это блоки RAM доступные для использования.
Тест проходил на виртуальной машине. Доступны 3 участка памяти:
0x0-0x9f800 653 килобайта примерно внутри первого мегабайта
0x100000-0xFEF0000 252 мегабайта
0xFF00000 — 0x10000000 1 мегабайт
Исходники к этому эксперименту:
https://github.com/chesnokov/dev64-os/tree/master/experiments/exp.000001