当前位置:   article > 正文

《真象还原》读书笔记——第五章 保护模式进阶,向内核迈进(获取物理内存容量)_保护模式下,可以获取内存大小吗?

保护模式下,可以获取内存大小吗?

5.1 获取物理内存容量

5.1.1 学习linux获取内存的方法

BIOS中断0x15的3个子功能:BIOS中断是实模式下的用法,不能在保护模式下使用。若全部失败了就只好让机器挂起了。运行成功再启动保护模式。

  • EAX=0xE820:遍历主机上全部内存
  • AX=0xE801:分别检测出64MB和16MB~4GB的内存,最大支持4GB
  • AH=0x88:最多检测出64MB内存,实际内存超过该容量也按64MB返回

5.1.2 利用BIOS中断0x15子功能0xe820获取内存

返回地址消息,通过地址范围描述符
地址范围描述符结构ARDS
Type字段的含义:
地址范围描述符结构的Type字段
BIOS中断0x15中的0xe820子功能需要的参数。
因为是在32位下工作,所以只用到BaseAddrLow+lengthLow是一片内存区域上限。
BIOS中断0x15子功能0xe820说明
BIOS中断0x15子功能0xe820说明
操作步骤

  1. 填写“调用前输入”中列出的寄存器。
  2. 执行中断,调用 int 0x15
  3. 在CF位为0的情况下,“返回后输出",中对应寄存器会有对应的结果。

5.1.3 利用BIOS中断0x15子功能0xe801获取内存

最大只能识别4GB,对于32位也算可以了。

  • 低于15MB的内存以1KB为单位,数量在AX,CX中记录。
    因此实际内存=AX*1024。AX,CX最大值为0x3c00
  • 16MB~4GB以64KB为单位,数量在BX,DX中记录。
    因此实际内存=AX*64 *1024。
    至于15~16MB的部分是留给ISA设备的。没有入统计。
    BIOS中断0x15子功能0xE801说明
    操作步骤
  1. 将AX寄存器写入0xE801
  2. 执行中断int 0x15
  3. 在CF=0的情况下,”返回后输出“中对应的寄存器会有对应结果。

5.1.4 利用BIOS中断0x15子功能0x88获取内存

即使内存容量大于64MB,也只会显示63MB。因为此中断只会显示1MB之上的内存,所以记得手动加上1MB
BIOS中断0x15子功能0x88说明

  1. 将AX寄存器写入0x88
  2. 执行中断调用int 0x15
  3. 在CF位为0的情况下,”返回后输出“中对应的寄存器便会有对应的结果。

5.1.5 实战内存容量检测

更改的内容:将第44行jmp到load的代码改为:
jmp LOADER_BASE_ADDR+0x300


%include "boot.inc"
section mbr vstart=0x7c00
   mov ax,cs
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov sp,0x7c00
   mov ax,0xb800
   mov gs,ax

   ;清屏
   mov ax,0600h
   mov bx,0700h
   mov cx,0
   mov dx,184fh
   int 10h

   ;输出字符串:MBR
   mov byte[gs:0x00],'1'
   mov byte[gs:0x01],0xA4

   mov byte[gs:0x02],' '
   mov byte[gs:0x03],0xA4

   mov byte[gs:0x04],'M'
   mov byte[gs:0x05],0xA4

   mov byte[gs:0x06],'B'
   mov byte[gs:0x07],0xA4

   mov byte[gs:0x08],'R'
   mov byte[gs:0x09],0xa4


   mov eax,LOADER_START_SECTOR                 ;其实栓去lba地址
   mov bx ,LOADER_BASE_ADDR                    ;写入的地址
   mov cx ,4                                   ;这里的cx就是读取扇区数
   call rd_disk_m_16
mov byte[gs:160],'r'
mov byte[gs:162],'d'
   
   jmp LOADER_BASE_ADDR+0x300
   
   ;===读取硬盘n个扇区===
rd_disk_m_16:
   mov esi, eax
   mov di,cx

   ;第一步,读取扇区
   mov dx,0x1f2
   mov al,cl 
   out dx,al 

   mov eax,esi
   ;第二步,将LBA地址存入0x1f3~0x1f6

   ;lba地址7~0写入端口0x1f3
   mov dx,0x1f3 
   out dx,al

   ;lba地址15-8写入端口0x1f4
   mov cl,8
   shr eax,cl
   mov dx,0x1f4
   out dx,al
   
   ;lba地址32~16写入端口0x1f5
   shr eax,cl
   mov dx,0x1f5
   out dx,al
   
   ;lba14~27
   shr eax,cl
   and al,0x0f 
   or al,0xe0      ;设置7-4位1110,表示lba模式。
   mov dx,0x1f6
   out dx,al
   
   ;第3步:向0x1f7端口写入命令,0x20
   mov dx,0x1f7
   mov al,0x20
   out dx,al
   
   ;第4步:检测硬盘状态
.not_ready:
   nop
   in al,dx 
   and al,0x88 
   cmp al,0x08 
   jnz .not_ready

   ;第5步:从0x1f0端口读数据
   mov ax,di
   mov dx,256
   mul dx
   mov cx,ax
   ;di为要读取的扇区数,一个扇区512字节,每读取一个字;共需要di*512/2次,所以是256
   mov dx,0x1f0 
   
.go_on_read:
   in ax,dx
   mov [bx],ax
   add bx,2
   loop .go_on_read
   ret

times 510-($-$$) db 0
db 0x55,0xaa

  • 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
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111

让调整数据结构为了让total_mem_bytes在0xb00位置上。

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR

;------------------------------
;构建gdt及其内部的描述符
GDT_BASE:           dd 0x00000000
                    dd 0x00000000

CODE_DESC:          dd 0x0000FFFF
                    dd DESC_CODE_HIGH4

DATA_STACK_DESK:    dd 0x0000FFFF
                    dd DESC_DATA_HIGH4

VIDEO_DESC:         dd 0x80000007               ;limit=(0xbffff-0xb8000)/4k=0x7
                    dd DESC_VIDEO_HIGH4         ;此时dp1为0

GDT_SIZE            equ $-GDT_BASE
GDT_LIMIT           equ GDT_SIZE-1
times 60 dq 0

SELECTOR_CODE       equ (0x0001<<3)+TI_GDT+RPL0
SELECTOR_DATA       equ (0x0002<<3)+TI_GDT+RPL0
SELECTOR_VIDEO      equ (0x0003<<3)+TI_GDT+RPL0 

total_mem_bytes     dd  0;存放内存大小

gdt_ptr             dw GDT_LIMIT
                    dd GDT_BASE

;------- 记录 ARDS结构体数 ----------
ards_buf            times   244 db 0
ards_nr             dw      0

;------------------------------

mov byte[gs:480],'G'
mov byte[gs:482],'D'
mov byte[gs:484],'T'

loader_start: ;打印字符串
mov byte[gs:640],'L'
mov byte[gs:642],'O'
mov byte[gs:644],'A'
mov byte[gs:646],'D'
mov byte[gs:648],'E'
mov byte[gs:650],'R'
mov byte[gs:652],'_'
mov byte[gs:654],'S'
mov byte[gs:656],'T'
mov byte[gs:658],'A'
mov byte[gs:660],'R'
mov byte[gs:662],'T'

;    mov sp,LOADER_BASE_ADDR
;    mov bp,loadermsg
;    mov cx,17
;    mov ax,0x1301
;    mov bx,0x001f
;    mov dx,0x1800
;    int 0x10

    ;--- 获取内存布局 ---
    xor ebx, ebx
    mov edx, 0x534d4150
    mov di, ards_buf

.e820_mem_get_loop:
    mov eax, 0x0000e820
    mov ecx,20
    int 0x15
    jc .e820_failed_so_try_e801

    add di,cx
    inc word [ards_nr]
    cmp ebx, 0
jnz .e820_mem_get_loop
    mov cx, [ards_nr]
    mov ebx, ards_buf
    xor edx,edx

.find_max_mem_area:
    mov eax,[ebx]
    add eax,[ebx+8]
    add ebx, 20
    cmp edx,eax

    jge .next_ards
    mov edx,eax
.next_ards:
    loop .find_max_mem_area
    jmp .mem_get_ok

;------ int 15h ax=E801和------

.e820_failed_so_try_e801:
    mov ax,0xe801
    int 0x15
    jc .e801_failed_so_try88

    mov cx,0x400
    mul cx
    shl edx,16
    and eax,0x0000FFFF
    or edx,eax
    add edx, 0x100000
    mov esi,edx

    xor eax,eax
    mov ax,bx
    mov ecx,0x10000
    mul ecx

    add esi,eax
    mov edx,esi
    jmp .mem_get_ok

;------ int 15h ah=0x88 ------
.e801_failed_so_try88:
    mov ah,0x88
    int 0x15
    jc .error_hlt
    and eax,0x0000FFFF

    mov cx,0x400
    mul cx
    shl edx,16
    or edx,eax
    add edx,0x100000

.mem_get_ok:
    mov [total_mem_bytes],edx



    ;---准备进入保护模式---
    ;---打开A20---
    in al,0x92
    or al,0000_0010B
    out 0x92,al
   
    ;---加载GDT---
    lgdt [gdt_ptr]
    
    ;---cr0第0个位置1
    mov eax,cr0 
    or eax,0x00000001
    mov cr0,eax 

    jmp dword SELECTOR_CODE:p_mode_start ;刷新流水线
.error_hlt
hlt
[bits 32]
p_mode_start:
    mov ax,SELECTOR_DATA
    mov ds,ax
    mov es,ax
    mov ss,ax 
    mov esp,LOADER_STACK_TOP
    mov ax,SELECTOR_VIDEO
    mov gs,ax

    mov byte [gs:800], 'P'
    jmp $

  • 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
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165

按照书中的调试方法进行调试。
得到结果:
32MB
更新:
loader.asm

%include "boot.inc"

section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP    equ LOADER_BASE_ADDR
;jmp loader_start

GDT_BASE:   dd 0x00000000
            dd 0x00000000

CODE_DESC:  dd 0x0000FFFF
            dd DESC_CODE_HIGH4

DATA_STACK_DESC:    dd  0x0000FFFF
                    dd  DESC_DATA_HIGH4

VIDEO_DESC: dd 0x80000007
            dd DESC_VIDEO_HIGH4

GDT_SIZE    equ $-GDT_BASE
GDT_LIMIT   equ GDT_SIZE-1
times 60 dq 0   ;预留60个描述符的位子

;选择子
SELECTOR_CODE equ  (0x0001<<3) + TI_GDT + RPL0
SELECTOR_DATA equ  (0x0002<<3) + TI_GDT + RPL0
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0

total_mem_bytes dd 0 ;4 保存内存容量
;gdt指针
gdt_ptr dw  GDT_LIMIT ;6
        dd  GDT_BASE
ards_buf times 244 db 0 ;244 ards结构体缓存
ards_nr dw 0    ;2 ards结构体数量,一共 4+6+244+2 = 256字节

loader_start:
;==== 读取内存数
    ;int 15h eax,ebx,es:di,ecx,edx
    xor ebx,ebx  ;ARDS后续值,第一次为0
    mov edx,0x534d4150  ;固定为签名标记
    mov di,ards_buf     ;ards结构缓冲区
    .e820_mem_get_loop:
        mov eax,0x0000e820
        mov ecx,20      ;ards 地址范围描述符结构是20字节
        int 0x15

        jc .e820_failed_so_try_e801 ;若cf为1,则发生错误,常识0xe801

        add di,cx   ;cx是读到的结构缓冲区中数据的字节数
        inc word [ards_nr]
        cmp ebx,0   ;如果是0说明这是最后一个ARDS结构
        jnz .e820_mem_get_loop

        ;找出(base_add_low + length_low)的最大值,也就是内存容量
        mov cx,[ards_nr]
        mov ebx,ards_buf
        xor edx,edx
        .find_max_mem_area:
            mov eax,[ebx]
            add eax,[ebx+8]
            add ebx,20  ;ebx存放 ARDS缓存内容地址
            cmp edx,eax ;比较 edx 与 eax大小
            jge .next_ards
            mov edx,eax
            .next_ards:
            loop .find_max_mem_area
        jmp .mem_get_ok


    ;0x15 0xe801
    .e820_failed_so_try_e801:
        mov ax,0xe801
        int 0x15
        jc .e801_failed_so_try88
        ;1 先算出低15MB的内存
        mov cx,0x400;ax KB单位2^10 ,0x400-> 1024 
        mul cx
        shl edx,16
        and eax,0x0000FFFF
        or edx,eax 
        add edx, 0x100000 ;补上1MB
        mov esi,edx ;先放在esi中
        ;2 算>16MB的内存 bx 64KB为单位
        xor eax,eax
        mov ax,bx
        mov ecx,0x10000 ;将64KB单位转为byte
        mul ecx
        add esi,eax ;<=15 + >16

        jmp .mem_get_ok


    .e801_failed_so_try88:
        mov ah,0x88
        int 0x15
        jc .error_hlt
        and eax,0x0000FFFF ;ax*1024+1MB
        mov cx,0x400
        mul cx          ;ax*1024->dx,ax
        shl edx,16
        or edx,eax
        add edx,0x100000 ;+1MB
        
    .mem_get_ok:
        mov [total_mem_bytes],edx 
    .error_hlt:
    mov byte [gs:160],'2'
    mov byte [gs:162],' '
    mov byte [gs:164],'0'
    mov byte [gs:166],'x'
    mov byte [gs:168],'1'
    mov byte [gs:170],'5'
;====

;1 打开 A20
    in al,0x92
    or al,0x02
    out 0x92,al 

;2 加载 GDT
lgdt [gdt_ptr]

;3 cr0 pe置1
mov eax,cr0
or eax,0x01
mov cr0,eax

jmp dword SELECTOR_CODE:p_mode_start

[bits 32]
p_mode_start:
    mov ax,SELECTOR_DATA
    mov ds,ax
    mov es,ax
    mov ss,ax 
    mov esp,LOADER_STACK_TOP
    mov ax,SELECTOR_VIDEO
    mov gs,ax 

    mov byte [gs:320],'3'
    mov byte [gs:322],' '
    mov byte [gs:324],'P'
    mov byte [gs:326],'r'
    mov byte [gs:328],'o'
    mov byte [gs:330],'t'
    mov byte [gs:332],'e'
    mov byte [gs:334],'c'
    mov byte [gs:336],'t'
    mov byte [gs:338],'i'
    mov byte [gs:340],'o'
    mov byte [gs:342],'n'
    mov byte [gs:344],' '
    mov byte [gs:346],'m'
    mov byte [gs:348],'o'
    mov byte [gs:350],'d'
    mov byte [gs:352],'e'
    mov byte [gs:354],'.'


    jmp $
  • 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
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159

mbr.asm

%include "boot.inc"
section MBR vstart=0x7c00
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov fs,ax
	mov sp,0x7c00 
	mov ax,0xb800 
	mov gs,ax 

;使用 int 0x10 功能号 0x06 清屏
	mov ah,0x06
	mov al,0x00		;上卷行数 0->全部
	mov bl,0x00
	mov bh,0x07
	mov cx,0x0000 ;左上( 0, 0)
	mov dx,0x184f ;右下(80,25)
	int 0x10

; ---------- 在显存中输入信息 ---------
; 输出背景为 黄 色,前景 红 色,并且跳动的字符串 "HELLO WORLD"
	mov bx,0
	mov cx,14
	mov si,0
print:
	mov al,[s+si]
	mov [gs:bx],al
	inc bx
	mov byte [gs:bx],0x24
	inc bx
	add si,1
loop print
	
	mov eax, LOADER_START_SECTOR
	mov bx, LOADER_BASE_ADDR
	mov cx, 4

	call rd_disk_m_16
	jmp LOADER_BASE_ADDR+0x300

rd_disk_m_16:
	mov esi,eax
	mov di,cx

	;指定扇区数0x1f2 8bit
	mov dx,0x1f2
	mov al,cl 
	out dx,al

	mov eax,esi 
	;LBA 0-7 8bit
	mov dx,0x1f3
	out dx,al 
	;LBA 8-15 8bit
	mov cl,8
	shr eax,cl
	mov dx,0x1f4
	out dx,al
	;LBA 16-23
	shr eax,cl 
	mov dx,0x1f5
	out dx,al 
	;LBA Device | 24-27
	shr eax,cl 
	and al,0000_1111b
	or  al,1110_0000b ;LBA, DEV主盘
	mov dx,0x1f6
	out dx,al 

	;写入命令
	mov dx,0x1f7
	mov al,0x20
	out dx,al 

	;检测硬盘状态
.not_ready:
	nop ;相当于个停顿
	in al,dx 
	and al,1000_1000b ;忙/准备好
	cmp al,0000_1000b
jnz .not_ready

	;读数据
	mov ax,di
	mov dx,256 ;512/2
	mul dx 
	mov cx,ax ;一共ax个字节

	mov dx,0x1f0
.read_data:
	in ax,dx 
	mov [bx],ax 
	add bx,2
	loop .read_data
ret



s db "1 MBR_start!!!"
times 510 - ($-$$) db 0
db 0x55, 0xaa
  • 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
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

运行结果:
在这里插入图片描述在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/58795
推荐阅读
相关标签
  

闽ICP备14008679号