§ Определение количества физической памяти
Начнём с процедуры определения количества физической памяти, установленной в компьютере. К сожалению, мне не удалось найти документации по BIOS-у, в которой было бы описан доступ к переменным, хранящим размер памяти установленной в компьютере. Вообще говоря, вы можете получить dw-размер расширенной памяти по адресу 0040:0013h или прочитать его из CMOS, но это подразумевается память, размером не более 16Мб. Для i386 это, скорее всего, подходит, но для всех остальных компьютеров - нет.Вашему вниманию предлагается процедура "get_phys_mem_size", которая сканирует всю физическую память и вычисляет её размер. Этот алгоритм имеет только одно ограничение - размер памяти не должен превышать 4Гб, т.к. мы пока рассматриваем 32-разрядную страничную организацию памяти.
Принцип работы данной процедуры простой - она записывает в память число, а затем считывает его. Если было прочитано записанное число - значит данная ячейка памяти присутствует в компьютере, если было прочитано другое число, то возможны 3 варианта:
- Было обращение к ПЗУ (ROM).
- Физическая память по данному адресу не присутствует.
- Физическая память повреждена.
Первый вариант, с обращением к ПЗУ также можно обойти, если начинать исследование памяти со второго мегабайта, т.к. ПЗУ размещено в конце первого мегабайта. При этом будет подразумеваться, что в компьютере установлен минимум - мегабайт памяти; это вполне разумное допущение, т.к. 32-разрядные процессоры обычно снабжают не меньшим количеством памяти. Если же вы пишете ОС, которая должна управлять контроллером или компьютером на базе 32-разрядного процессора с памятью, менее 1Мб, то приводимая в примере процедура вам не понадобится - используйте CMOS.
Итак, наша процедура определения размера физической памяти предназначена только для компьютеров и исправной памятью, размер которой - не менее 1Мб.
Для того, чтобы сканировать память не обязательно проверять каждый байт адресного пространства. Микросхемы памяти по объёму кратны, как правило, целому числу мегабайт, но даже если будут использоваться микросхемы меньшего размера, можно гарантировать, что они будут иметь объём, кратный 4Кб. Это значение взято не спроста - такой же размер имеет, как вы помните, физическая страница памяти и минимальная логическая страница (а мы пока только такие и рассматриваем), поэтому достаточно записать и затем прочитать одну ячейку памяти в каждой физической странице и проверить это значение.
При проверке считанного значения применяется "неразрушающий" контроль, который обеспечивается двумя командами XCHG:
1 xchg [es:edi], eax ; Поменяли значениями регистр 2 ; и ячейку памяти. 3 4 xchg [es:edi], eax ; Вернули прежнее значение обратно 5 ; в память. Теперь в регистре число, 6 ; которое "побывало" в ячейке памяти. 7 ; Если оно не изменилось - значит, 8 ; запись была в ОЗУ.Как правило, при считывании числа из неприсутствующей физической памяти, мы всегда получаем значение, одинаковое для каждого байта, например, FFh:
1 mov edx, 12345678h 2 mov eax, edx 3 xchg [es:edi], eax ; EAX = FFFF FFFFh 4 xchg [es:edi], eax ; EAX = FFFF FFFFh 5 6 ; EAX <> EDX, значит, что ES:EDI указывают на не-ОЗУ 7 ; При обращении к ОЗУ мы получим то, что туда записали: 8 9 mov edx, 12345678h 10 mov eax, edx 11 xchg [es:edi], eax ; EAX = FFFF FFFFh 12 xchg [es:edi], eax ; EAX = 1234 5678h 13 14 ; EAX = EDXДалее приводится процедура "get_phys_mem_size" (tasm):
1get_phys_mem_size: 2 3; Вычисляет размер физической памяти, установленной в компьютере 4; Возврат: EAX = размер памяти в байтах 5 6 push bx 7 push ecx 8 push edx 9 push ebp 10 push es 11 push edi 12 13 mov ax, All_mem_sel ; Для проверки памяти мы будем 14 mov es, ax ; использовать сегмент, описывающий 15 ; всю память. 16 17 mov bx, Page_Directory_adr ; DS:BX указывает на начало каталога страниц. 18 add bx, 1000h + 256 * 4 ; А теперь - на первую страницу 19 ; второго мегабайта памяти в первой 20 ; таблице страниц. 21 22 mov edx,12345678h ; Это тестовое значение, которое 23 ; мы будем записывать и затем 24 ; считывать из памяти. 25 26 mov ebp,1024 * 1024 * 2 ; В EBP будет находится адрес, 27 ; с которого мы будем проверять 28 ; память. 29gpms_1: 30 31; Подготавливаем в первой определённой таблице страниц 256 элементов PTE, 32; начиная с 256. Они будут описывать второй мегабайт адресного пространства. 33; Эти PTE мы отобразим не один мегабайт физической памяти, начиная с адреса 34; в EBP. 35 36 mov edi,1024 * 1024 37 mov eax,ebp 38 39 mov cx,256 40 mov al,3 ; Записывая в AL 3, мы тем самым устанавливаем 41 ; биты 0 и 1 этого регистра. Когда мы запишем EAX 42 ; на место какого-либо элемента PTE в таблице 43 ; страниц, то эти биты определят этот элемент как 44 ; присутствующий (бит P=1) с разрешённым доступом 45 ; по чтению записи (бит R/W=1). 46 47; Записываем 256 элементов PTE: 48gpms_2: 49 mov [ bx ],eax 50 add eax,1000h 51 add bx,4 52 loop gpms_2 53 54 mov eax, cr3 ; Перегружаем значение CR3. Это вызовет 55 mov cr3, eax ; сброс буферов TLB и заставит процессор 56 ; использовать обновлённые значения из 57 ; изменённой нами таблицы страниц. 58 59 jmp $+2 ; Выполняя команду перехода, мы сбрасываем 60 ; конвейер команд процессора, заставляя его заново 61 ; считывать текущую часть кода и очистить результаты 62 ; всех спекулятивно выполненных команд. Для нас это 63 ; гарантия того, что процессор будет работать с 64 ; обновлённой таблицей страниц. 65 66 sub bx, 256 * 4 ; Возвращаем указатель на 256-й элемент 67 ; PTE в таблице страниц. 68 69 mov cx, 256 70 71; Тестируем память: 72gpms_3: 73 74 mov eax, edx ; EAX = 12345678h. 75 xchg eax, [ es:edi ] ; Пара команд XCHG выполнит "не 76 xchg eax, [ es:edi ] ; разрушающий" контроль памяти. 77 add edi, 1000h 78 79 cmp eax,edx ; Если было прочитано то же значение, что 80 ; и записано, значит текущая страница памяти 81 ; отображена на ОЗУ. 82 83 jne gpms_4 ; Иначе - мы дошли до конца ОЗУ. 84 85 loop gpms_3 86 87 add ebp, 1000h * 256 ; Здесь меняется адрес физической 88 ; памяти, на который будет отображён 89 ; следующий мегабайт. 90 jmp gpms_1 91 92gpms_4: 93 94 mov eax,ebp 95 add eax,edi 96 sub eax,1000h * 257 ; EAX содержит адрес последней 97 ; реально присутствующей физической 98 ; страницы памяти, это и есть размер 99 ; физической памяти. 100 101; Очистка элементов PTE, отображённых на второй мегабайт (т.е. возврат 102; таблицы страниц в первоначальное состояние. 103 104 mov edx,eax 105 106 mov ax,ds 107 mov es,ax 108 mov di,Page_Directory_adr 109 add di,256 * 4 110 mov cx,256 111 xor eax,eax 112 cld 113 rep stosd 114 115 mov eax,edx ; EAX = размер физической памяти в байтах. 116 117 pop edi 118 pop es 119 pop ebp 120 pop edx 121 pop ecx 122 pop bx 123 124 ret