gdt硬盘装android+x86,[024][x86汇编语言]第十三章 学习加载程序C13_mbr.asm

学习笔记

第十三章的 代码

用户程序 c13.asm

内核程序 c13_core.asm

加载程序 c13_mbr.asm

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

第十三章的代码文件.png

主引导程序 C13_mbr.asm

主引导程序 C13_mbr.asm 程序结构

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

主引导程序 C13_mbr.asm 程序结构.png

加载程序 加载完 内核程序 后的 GDT 布局

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

加载程序 加载完内核后的GDT布局.png

内存布局示意图

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

内存布局示意图.png

完整源码 code_13_mbr.asm (增加注释)

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

;代码清单13-1

;文件名:code_13_mbr.asm

;文件说明:硬盘主引导扇区代码

;创建日期:8:43 2018/6/1

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

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

;常数

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

core_base_address equ 0x00040000 ;内核程序将要被加载到的物理地址

core_start_sector equ 0x00000001 ;内核程序位于硬盘的起始逻辑扇区号

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

;加载程序开始

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

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

; 所有数据都是十六进制

; 表内偏移量 GDT 描述符索引

; +38 核心代码段(位于核心数据段之后) 0x38

; +30 核心数据段(位于系统公用例程段之后) 0x30

; +28 公用例程段(起始地址为00040000) 0x28

; +20 文本模式显存(000B8000~00BFFFFF) 0x20

; +18 初始栈段(00006C00~00007C00) 0x18

; +10 初始代码段(00007C00~00007DFF) 0x10

; +08 0~4GB数据段(00000000~FFFFFFFF) 0x08

; +00 空描述符 0x00

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

;加载GDT表 偏移+00~+20 5个项目

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

mov ax,cs

mov ss,ax

mov sp,0x7c00

;计算GDT所在的逻辑段地址

mov eax,[cs:pdgt+0x7c00+0x02] ;GDT的32位物理地址

xor edx,edx

mov ebx,16

div ebx ;分解成16位逻辑地址

mov ds,eax ;令DS指向该段以进行操作

mov ebx,edx ;段内起始偏移地址

;跳过0#号描述符的槽位(空描述符)

;创建1#描述符,这是一个数据段,对应0~4G的线性地址空间

mov dword [ebx+0x08],0x0000ffff ;段基址0x00000000

mov dword [ebx+0x0c],0x00cf9200

;创建保护模式下初始代码段描述符

mov dword [ebx+0x10],0x7c0001ff ;段基址0x00007c00

mov dword [ebx+0x14],0x00409800

;建立保护模式下的堆栈段描述符

mov dword [ebx+0x18],0x7c00fffe ;段基址0x00007c00

mov dword [ebx+0x1c],0x00cf9600

;建立保护模式下的显示缓冲区描述符

mov dword [ebx+0x20],0x80007fff ;段基址0x000B8000

mov dword [ebx+0x24],0x0040920b

;初始化描述符表寄存器GDTR

mov word [cs:pdgt+0x7c00],39 ;5*8-1=39

lgdt [cs:pdgt+0x7c00]

in al,0x92 ;南桥芯片内的端口

or al,0000_0010B

out 0x92,al ;打开A20

cli ;保护模式下中断机制尚未建立,应该禁止中断

mov eax,cr0

or eax,1

mov cr0,eax ;设置PE位

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

;以下进入保护模式

;设置 DS 指向 0~4GB内存空间

; SS 指向堆栈段

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

jmp dword 0x0010:flush ; 16位的描述符选择子:32位偏移

; dword修饰的是偏移地址

; 清空流水线并串行化处理器

[bits 32]

flush:

mov eax,0x0008 ;加载(0...4GB)选择子

mov ds,eax

mov eax,0x0018 ;加载堆栈选择子

mov ss,eax

xor esp,esp ;堆栈指针 = 0

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

;以下加载系统核心程序

;

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

;读取位于硬盘的内核程序 调用子程序 read_hard_disk_0

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

mov edi,core_base_address

mov eax,core_start_sector

mov ebx,edi

call read_hard_disk_0 ;读取内核程序的起始部分(一个扇区)到内存

;以下判断整个内核程序有多大

mov eax,[edi] ;内核程序长度

xor edx,edx

mov ecx,512

div ecx

or edx,edx

jnz @1

dec eax ;已经读了一个扇区,扇区总数减1

@1:

or eax,eax

jz setup ;jz ZF=1 寄存器值为零成立 则跳转

;读取剩余扇区

mov ecx,eax

mov eax,core_start_sector ;32位模式下的LOOP使用ECX

inc eax ;从下一个逻辑扇区接着读

@2:

call read_hard_disk_0

inc eax

loop @2 ;循环读,知道读完整个内核程序

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

; 所有数据都是十六进制

; 表内偏移量 GDT 描述符索引

; +38 核心代码段(位于核心数据段之后) 0x38

; +30 核心数据段(位于系统公用例程段之后) 0x30

; +28 公用例程段(起始地址为00040000) 0x28

; +20 文本模式显存(000B8000~00BFFFFF) 0x20

; +18 初始栈段(00006C00~00007C00) 0x18

; +10 初始代码段(00007C00~00007DFF) 0x10

; +08 0~4GB数据段(00000000~FFFFFFFF) 0x08

; +00 空描述符 0x00

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

;再加载GDT表 偏移+28~+38 3个项目

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

;********************** 内核程序 c13_core.asm ****************************

;* ;以下是系统核心的头部,用于加载核心程序

;* core_length dd core_end ;核心程序总长度#00;

;*

;* sys_routine_seg dd section.sys_routine.start

;* ;系统公用例程段位置#04

;*

;* core_data_seg dd section.core_data.start

;* ;核心数据段位置#08

;*

;* core_code_seg dd section.core_code.start

;* ;核心代码段位置#0c

;*

;* core_entry dd start ;核心代码段入口点#10

;* dw core_code_seg_sel

;*

;*********************** 内核程序 c13_core.asm ****************************

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

setup:

mov esi,[0x7c00+pdgt+0x02] ;使用0~4GB的段来访问,寻址pdgt

;建立公用例程段描述符 ;mov edi,core_base_address

mov eax,[edi+0x04] ;公用例程段 在内核程序中的起始汇编地址

mov ebx,[edi+0x08] ;核心数据段 在内核程序中的起始汇编地址

sub ebx,eax

dec ebx ;公用例程段的 段界限

add eax,edi ;公用例程段的 段基地址

mov ecx,0x00409800 ;字节粒度的代码段描述符

call make_gdt_descriptor

mov [esi+0x28],eax

mov [esi+0x2c],edx

;建立核心数据段描述符

mov eax,[edi+0x08] ;核心数据段 起始汇编地址

mov ebx,[edi+0x0c] ;核心代码段 起始汇编地址

sub ebx,eax

dec ebx ;核心数据段 段界限

add eax,edi ;核心数据段 基地址

mov ecx,0x00409200 ;字节粒度的数据段描述符

call make_gdt_descriptor

mov [esi+0x30],eax

mov [esi+0x34],edx

;建立核心代码段描述符

mov eax,[edi+0x0c] ;核心代码段 起始汇编地址

mov ebx,[edi+0x00] ;程序总长度

sub ebx,eax

dec ebx ;核心代码段 段界限

add eax,edi ;核心代码段 段基址

mov ecx,0x00409800 ;字节粒度的代码段描述符

call make_gdt_descriptor

mov [esi+0x38],eax

mov [esi+0x3c],edx

mov word [0x7c00+pdgt],63 ;8*8-1=63

lgdt [0x7c00+pdgt]

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

;转移控制权给内核程序

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

jmp far [edi+0x10]

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

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

;子程序: read_hard_disk_0

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

;功能: 从硬盘读取一个逻辑扇区

;参数: EAX = 逻辑扇区号

; DS:EBX=目标缓冲区地址

;返回: EBX = EBX + 512

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

read_hard_disk_0:

push eax

push ecx

push edx

;设置28位起始LBA扇区号

push eax

mov dx,0x1f2 ;0x1f2

mov al,1 ;读取的扇区数为1

out dx,al

inc dx ;0x1f3

pop eax

out dx,al ;LBA 7~0

inc dx ;0x1f4

mov cl,8

shr eax,cl

out dx,al ;LBA 15~8

inc dx ;0x1f5

shr eax,cl

out dx,al ;LBA 23~16

inc dx ;0x1f6

shr eax,cl

or al,0xe0 ;主硬盘 LBA 27~24

out dx,al

inc dx ;0x1f7

mov al,0x20 ;读命令

out dx,al

.waits:

in al,dx

and al,0x88

cmp al,0x08

jnz .waits ;硬盘已经准备好数据传输

mov ecx,256 ;总共要读取的字数

mov dx,0x1f0 ;0x1f0

.readw:

in ax,dx

mov [ebx],ax

add ebx,2

loop .readw

pop edx

pop ecx

pop eax

ret

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

;子程序: make_gdt_descriptor

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

;功能: 构造描述符

;输入: EAX=线性基地址

; EBX=段界限

; ECX=属性(各属性都在原始位置,其他没用到的位置置为零)

;返回: EDX:EAX=完整的描述符

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

make_gdt_descriptor:

mov edx,eax

shl eax,16

or ax,bx ;描述符低32位构造完毕

and edx,0xffff0000 ;清除基地址中无关的位

rol edx,8

bswap edx ;装配基地址的31~24和23~16(80486+)

and ebx,0x000f0000

or edx,ebx ;装配段界限的高4位

or edx,ecx ;装配属性

;描述符高32位构造完毕

ret

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

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

;表

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

pdgt dw 0

dd 0x00007e00 ;GDT的物理地址

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

;主引导扇区标志

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

times 510-($-$$) db 0

db 0x55,0xaa

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

;加载程序结束

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

代码说明

加载程序mov eax,[edi]与内核程序core_length dd core_end

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

在加载程序中获取内核程序长度

加载程序 jmp far [edi+0x10] 与内核程序 core_entry dd start dw core_code_seg_sel

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

转移控制权 从加载程序到内核程序.png

描述符计算 make_gdt_descriptor 举例

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

描述符计算 1

49cbc4161799?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

描述符计算 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值