鱼C论坛

 找回密码
 立即注册
查看: 2347|回复: 0

[学习笔记] X86汇编语言-从实模式到保护模式—笔记(24)-第13章 程序的动态加载和执行(2)

[复制链接]
发表于 2017-12-1 19:09:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 兰陵月 于 2017-12-5 21:52 编辑
  1.          ;代码清单13-1
  2.          ;文件名:c13_mbr.asm
  3.          ;文件说明:硬盘主引导扇区代码
  4.          ;创建日期:2011-10-28 22:35        ;设置堆栈段和栈指针
  5.          
  6.          core_base_address equ 0x00040000   ;常数,内核加载的起始内存地址
  7.          core_start_sector equ 0x00000001   ;常数,内核的起始逻辑扇区号
  8.          
  9.          mov ax,cs      
  10.          mov ss,ax
  11.          mov sp,0x7c00
  12.       
  13.          ;计算GDT所在的逻辑段地址
  14.          mov eax,[cs:pgdt+0x7c00+0x02]      ;GDT的32位物理地址
  15.          xor edx,edx
  16.          mov ebx,16
  17.          div ebx                            ;分解成16位逻辑地址

  18.          mov ds,eax                         ;令DS指向该段以进行操作
  19.          mov ebx,edx                        ;段内起始偏移地址

  20.          ;跳过0#号描述符的槽位
  21.          ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
  22.          mov dword [ebx+0x08],0x0000ffff    ;基地址为0,段界限为0xFFFFF
  23.          mov dword [ebx+0x0c],0x00cf9200    ;粒度为4KB,存储器段描述符

  24.          ;创建保护模式下初始代码段描述符
  25.          mov dword [ebx+0x10],0x7c0001ff    ;基地址为0x00007c00,界限0x1FF
  26.          mov dword [ebx+0x14],0x00409800    ;粒度为1个字节,代码段描述符

  27.          ;建立保护模式下的堆栈段描述符      ;基地址为0x00007C00,界限0xFFFFE
  28.          mov dword [ebx+0x18],0x7c00fffe    ;粒度为4KB
  29.          mov dword [ebx+0x1c],0x00cf9600
  30.          
  31.          ;建立保护模式下的显示缓冲区描述符   
  32.          mov dword [ebx+0x20],0x80007fff    ;基地址为0x000B8000,界限0x07FFF
  33.          mov dword [ebx+0x24],0x0040920b    ;粒度为字节
  34.          
  35.          ;初始化描述符表寄存器GDTR
  36.          mov word [cs: pgdt+0x7c00],39      ;描述符表的界限   

  37.          lgdt [cs: pgdt+0x7c00]
  38.       
  39.          in al,0x92                         ;南桥芯片内的端口
  40.          or al,0000_0010B
  41.          out 0x92,al                        ;打开A20

  42.          cli                                ;中断机制尚未工作

  43.          mov eax,cr0
  44.          or eax,1
  45.          mov cr0,eax                        ;设置PE位
  46.       
  47.          ;以下进入保护模式... ...
  48.          jmp dword 0x0010:flush             ;16位的描述符选择子:32位偏移
  49.                                             ;清流水线并串行化处理器
  50.          [bits 32]               
  51.   flush:                                 
  52.          mov eax,0x0008                     ;加载数据段(0..4GB)选择子
  53.          mov ds,eax
  54.       
  55.          mov eax,0x0018                     ;加载堆栈段选择子
  56.          mov ss,eax
  57.          xor esp,esp                        ;堆栈指针 <- 0
  58.          
  59.          ;以下加载系统核心程序
  60.          mov edi,core_base_address
  61.       
  62.          mov eax,core_start_sector
  63.          mov ebx,edi                        ;起始地址
  64.          call read_hard_disk_0              ;以下读取程序的起始部分(一个扇区)
  65.       
  66.          ;以下判断整个程序有多大
  67.          mov eax,[edi]                      ;核心程序尺寸
  68.          xor edx,edx
  69.          mov ecx,512                        ;512字节每扇区
  70.          div ecx

  71.          or edx,edx
  72.          jnz @1                             ;未除尽,因此结果比实际扇区数少1
  73.          dec eax                            ;已经读了一个扇区,扇区总数减1
  74.    @1:
  75.          or eax,eax                         ;考虑实际长度≤512个字节的情况
  76.          jz setup                           ;EAX=0 ?

  77.          ;读取剩余的扇区
  78.          mov ecx,eax                        ;32位模式下的LOOP使用ECX
  79.          mov eax,core_start_sector
  80.          inc eax                            ;从下一个逻辑扇区接着读
  81.    @2:
  82.          call read_hard_disk_0
  83.          inc eax
  84.          loop @2                            ;循环读,直到读完整个内核

  85. setup:
  86.          mov esi,[0x7c00+pgdt+0x02]         ;不可以在代码段内寻址pgdt,但可以
  87.                                             ;通过4GB的段来访问
  88.          ;建立公用例程段描述符
  89.          mov eax,[edi+0x04]                 ;公用例程代码段起始汇编地址
  90.          mov ebx,[edi+0x08]                 ;核心数据段汇编地址
  91.          sub ebx,eax
  92.          dec ebx                            ;公用例程段界限
  93.          add eax,edi                        ;公用例程段基地址
  94.          mov ecx,0x00409800                 ;字节粒度的代码段描述符
  95.          call make_gdt_descriptor
  96.          mov [esi+0x28],eax
  97.          mov [esi+0x2c],edx
  98.       
  99.          ;建立核心数据段描述符
  100.          mov eax,[edi+0x08]                 ;核心数据段起始汇编地址
  101.          mov ebx,[edi+0x0c]                 ;核心代码段汇编地址
  102.          sub ebx,eax
  103.          dec ebx                            ;核心数据段界限
  104.          add eax,edi                        ;核心数据段基地址
  105.          mov ecx,0x00409200                 ;字节粒度的数据段描述符
  106.          call make_gdt_descriptor
  107.          mov [esi+0x30],eax
  108.          mov [esi+0x34],edx
  109.       
  110.          ;建立核心代码段描述符
  111.          mov eax,[edi+0x0c]                 ;核心代码段起始汇编地址
  112.          mov ebx,[edi+0x00]                 ;程序总长度
  113.          sub ebx,eax
  114.          dec ebx                            ;核心代码段界限
  115.          add eax,edi                        ;核心代码段基地址
  116.          mov ecx,0x00409800                 ;字节粒度的代码段描述符
  117.          call make_gdt_descriptor
  118.          mov [esi+0x38],eax
  119.          mov [esi+0x3c],edx

  120.          mov word [0x7c00+pgdt],63          ;描述符表的界限
  121.                                        
  122.          lgdt [0x7c00+pgdt]                  

  123.          jmp far [edi+0x10]  
  124.       
  125. ;-------------------------------------------------------------------------------
  126. read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
  127.                                          ;EAX=逻辑扇区号
  128.                                          ;DS:EBX=目标缓冲区地址
  129.                                          ;返回:EBX=EBX+512
  130.          push eax
  131.          push ecx
  132.          push edx
  133.       
  134.          push eax
  135.          
  136.          mov dx,0x1f2
  137.          mov al,1
  138.          out dx,al                       ;读取的扇区数

  139.          inc dx                          ;0x1f3
  140.          pop eax
  141.          out dx,al                       ;LBA地址7~0

  142.          inc dx                          ;0x1f4
  143.          mov cl,8
  144.          shr eax,cl
  145.          out dx,al                       ;LBA地址15~8

  146.          inc dx                          ;0x1f5
  147.          shr eax,cl
  148.          out dx,al                       ;LBA地址23~16

  149.          inc dx                          ;0x1f6
  150.          shr eax,cl
  151.          or al,0xe0                      ;第一硬盘  LBA地址27~24
  152.          out dx,al

  153.          inc dx                          ;0x1f7
  154.          mov al,0x20                     ;读命令
  155.          out dx,al

  156.   .waits:
  157.          in al,dx
  158.          and al,0x88
  159.          cmp al,0x08
  160.          jnz .waits                      ;不忙,且硬盘已准备好数据传输

  161.          mov ecx,256                     ;总共要读取的字数
  162.          mov dx,0x1f0
  163.   .readw:
  164.          in ax,dx
  165.          mov [ebx],ax
  166.          add ebx,2
  167.          loop .readw

  168.          pop edx
  169.          pop ecx
  170.          pop eax
  171.       
  172.          ret

  173. ;-------------------------------------------------------------------------------
  174. make_gdt_descriptor:                     ;构造描述符
  175.                                          ;输入:EAX=线性基地址
  176.                                          ;      EBX=段界限
  177.                                          ;      ECX=属性(各属性位都在原始
  178.                                          ;      位置,其它没用到的位置0)
  179.                                          ;返回:EDX:EAX=完整的描述符
  180.          mov edx,eax
  181.          shl eax,16                     
  182.          or ax,bx                        ;描述符前32位(EAX)构造完毕
  183.       
  184.          and edx,0xffff0000              ;清除基地址中无关的位
  185.          rol edx,8
  186.          bswap edx                       ;装配基址的31~24和23~16  (80486+)
  187.       
  188.          xor bx,bx
  189.          or edx,ebx                      ;装配段界限的高4位
  190.       
  191.          or edx,ecx                      ;装配属性
  192.       
  193.          ret
  194.       
  195. ;-------------------------------------------------------------------------------
  196.          pgdt             dw 0
  197.                           dd 0x00007e00      ;GDT的物理地址
  198. ;-------------------------------------------------------------------------------                             
  199.          times 510-($-$) db 0
  200.                           db 0x55,0xaa
复制代码

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-20 10:00

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表