请选择 进入手机版 | 继续访问电脑版

4Ameta

 找回密码
 立即注册
搜索
查看: 64|回复: 0

Learn x86 protected mode assembly language-c17_mbr.asm

[复制链接]

26

主题

26

帖子

119

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119
发表于 2022-9-12 21:17:55 | 显示全部楼层 |阅读模式
  1.          ;代码清单17-1
  2.          ;文件名:c17_mbr.asm
  3.          ;文件说明:硬盘主引导扇区代码
  4.          ;创建日期:2012-07-13 11:20        ;设置堆栈段和栈指针
  5.          
  6.          core_base_address equ 0x00040000   ;常数,内核加载的起始内存地址
  7.          core_start_sector equ 0x00000001   ;常数,内核的起始逻辑扇区号

  8. ;===============================================================================
  9. SECTION  mbr  vstart=0x00007c00         

  10.          mov ax,cs      
  11.          mov ss,ax
  12.          mov sp,0x7c00
  13.       
  14.          ;计算GDT所在的逻辑段地址
  15.          mov eax,[cs:pgdt+0x02]             ;GDT的32位物理地址
  16.          xor edx,edx
  17.          mov ebx,16
  18.          div ebx                            ;分解成16位逻辑地址

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

  21.          ;跳过0#号描述符的槽位
  22.          ;创建1#描述符,保护模式下的代码段描述符
  23.          mov dword [ebx+0x08],0x0000ffff    ;基地址为0,界限0xFFFFF,DPL=00
  24.          mov dword [ebx+0x0c],0x00cf9800    ;4KB粒度,代码段描述符,向上扩展

  25.          ;创建2#描述符,保护模式下的数据段和堆栈段描述符
  26.          mov dword [ebx+0x10],0x0000ffff    ;基地址为0,界限0xFFFFF,DPL=00
  27.          mov dword [ebx+0x14],0x00cf9200    ;4KB粒度,数据段描述符,向上扩展

  28.          ;初始化描述符表寄存器GDTR
  29.          mov word [cs: pgdt],23             ;描述符表的界限   

  30.          lgdt [cs: pgdt]
  31.       
  32.          in al,0x92                         ;南桥芯片内的端口
  33.          or al,0000_0010B
  34.          out 0x92,al                        ;打开A20

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

  36.          mov eax,cr0                  
  37.          or eax,1
  38.          mov cr0,eax                        ;设置PE位
  39.       
  40.          ;以下进入保护模式... ...
  41.          jmp dword 0x0008:flush             ;16位的描述符选择子:32位偏移
  42.                                             ;清流水线并串行化处理器
  43.          [bits 32]               
  44.   flush:                                 
  45.          mov eax,0x00010                    ;加载数据段(4GB)选择子
  46.          mov ds,eax
  47.          mov es,eax
  48.          mov fs,eax
  49.          mov gs,eax
  50.          mov ss,eax                         ;加载堆栈段(4GB)选择子
  51.          mov esp,0x7000                     ;堆栈指针
  52.          
  53.          ;以下加载系统核心程序
  54.          mov edi,core_base_address

  55.          mov eax,core_start_sector
  56.          mov ebx,edi                        ;起始地址
  57.          call read_hard_disk_0              ;以下读取程序的起始部分(一个扇区)

  58.          ;以下判断整个程序有多大
  59.          mov eax,[edi]                      ;核心程序尺寸
  60.          xor edx,edx
  61.          mov ecx,512                        ;512字节每扇区
  62.          div ecx

  63.          or edx,edx
  64.          jnz @1                             ;未除尽,因此结果比实际扇区数少1
  65.          dec eax                            ;已经读了一个扇区,扇区总数减1
  66.    @1:
  67.          or eax,eax                         ;考虑实际长度≤512个字节的情况
  68.          jz pge                             ;EAX=0 ?

  69.          ;读取剩余的扇区
  70.          mov ecx,eax                        ;32位模式下的LOOP使用ECX
  71.          mov eax,core_start_sector
  72.          inc eax                            ;从下一个逻辑扇区接着读
  73.    @2:
  74.          call read_hard_disk_0
  75.          inc eax
  76.          loop @2                            ;循环读,直到读完整个内核

  77.    pge:
  78.          ;准备打开分页机制。从此,再也不用在段之间转来转去,实在晕乎~
  79.          
  80.          ;创建系统内核的页目录表PDT
  81.          mov ebx,0x00020000                 ;页目录表PDT的物理地址
  82.          
  83.          ;在页目录内创建指向页目录表自己的目录项
  84.          mov dword [ebx+4092],0x00020003

  85.          mov edx,0x00021003                 ;MBR空间有限,后面尽量不使用立即数
  86.          ;在页目录内创建与线性地址0x00000000对应的目录项
  87.          mov [ebx+0x000],edx                ;写入目录项(页表的物理地址和属性)      
  88.                                             ;此目录项仅用于过渡。
  89.          ;在页目录内创建与线性地址0x80000000对应的目录项
  90.          mov [ebx+0x800],edx                ;写入目录项(页表的物理地址和属性)

  91.          ;创建与上面那个目录项相对应的页表,初始化页表项
  92.          mov ebx,0x00021000                 ;页表的物理地址
  93.          xor eax,eax                        ;起始页的物理地址
  94.          xor esi,esi
  95.   .b1:      
  96.          mov edx,eax
  97.          or edx,0x00000003                                                      
  98.          mov [ebx+esi*4],edx                ;登记页的物理地址
  99.          add eax,0x1000                     ;下一个相邻页的物理地址
  100.          inc esi
  101.          cmp esi,256                        ;仅低端1MB内存对应的页才是有效的
  102.          jl .b1
  103.          
  104.          ;令CR3寄存器指向页目录,并正式开启页功能
  105.          mov eax,0x00020000                 ;PCD=PWT=0
  106.          mov cr3,eax

  107.          ;将GDT的线性地址映射到从0x80000000开始的相同位置
  108.          sgdt [pgdt]
  109.          mov ebx,[pgdt+2]
  110.          add dword [pgdt+2],0x80000000      ;GDTR也用的是线性地址
  111.          lgdt [pgdt]

  112.          mov eax,cr0
  113.          or eax,0x80000000
  114.          mov cr0,eax                        ;开启分页机制
  115.    
  116.          ;将堆栈映射到高端,这是非常容易被忽略的一件事。应当把内核的所有东西
  117.          ;都移到高端,否则,一定会和正在加载的用户任务局部空间里的内容冲突,
  118.          ;而且很难想到问题会出在这里。
  119.          add esp,0x80000000                 
  120.                                              
  121.          jmp [0x80040004]  
  122.       
  123. ;-------------------------------------------------------------------------------
  124. read_hard_disk_0:                           ;从硬盘读取一个逻辑扇区
  125.                                             ;EAX=逻辑扇区号
  126.                                             ;DS:EBX=目标缓冲区地址
  127.                                             ;返回:EBX=EBX+512
  128.          push eax
  129.          push ecx
  130.          push edx
  131.       
  132.          push eax
  133.          
  134.          mov dx,0x1f2
  135.          mov al,1
  136.          out dx,al                          ;读取的扇区数

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

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

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

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

  151.          inc dx                             ;0x1f7
  152.          mov al,0x20                        ;读命令
  153.          out dx,al

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

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

  166.          pop edx
  167.          pop ecx
  168.          pop eax
  169.       
  170.          ret

  171. ;-------------------------------------------------------------------------------
  172.          pgdt             dw 0
  173.                           dd 0x00008000     ;GDT的物理/线性地址
  174. ;-------------------------------------------------------------------------------                             
  175.          times 510-($-$$) db 0
  176.                           db 0x55,0xaa
复制代码


回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|4ameta

GMT+8, 2022-10-3 00:40 , Processed in 0.041876 second(s), 17 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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