Определение доступной памяти

Продолжаю эксперименты с разработкой ОС. См. также: Совмещение 16-ти битного и 32-битного кода в ядре.

Для работы Операционной системе необходимо определить сколько и какой памяти доступно для работы. Современный способ определения доступной памяти основан на использовании функции BIOS 0x15, EAX = 0xE820. Этой функции достаточно на современном железе, на старом, могут потребоваться другие функции.

Подробно о различных механизмах определения доступной памяти рассказано в 2-х источниках:

Вкратце, память определяется циклическим обращением к функции 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

Продолжение следует…

Оставьте комментарий