兰陵月 发表于 2017-11-2 21:15:25

X86汇编语言-从实模式到保护模式—笔记(10)

本帖最后由 兰陵月 于 2017-12-5 21:55 编辑

第9章中断和动态时钟显示
例程理解学习

加载程序源代码
         ;代码清单8-1
         ;文件名:c08_mbr.asm
         ;文件说明:硬盘主引导扇区代码(加载程序)
         ;创建日期:2011-5-5 18:17

         app_lba_start equ 100         ;声明常数(用户程序起始逻辑扇区号)
                                       ;常数的声明不会占用汇编地址

SECTION mbr align=16 vstart=0x7c00

         ;设置堆栈段和栈指针
         mov ax,0
         mov ss,ax
         mov sp,ax

         mov ax,            ;计算用于加载用户程序的逻辑段地址
         mov dx,
         mov bx,16
         div bx
         mov ds,ax                     ;令DS和ES指向该段以进行操作
         mov es,ax

         ;以下读取程序的起始部分
         xor di,di                                               ;程序在硬盘上的起始逻辑扇区号---高16位,只有低12位有效,所以高4位必须为0(作为参数传递)
         mov si,app_lba_start            ;程序在硬盘上的起始逻辑扇区号---低16位(作为参数传递)
         xor bx,bx                     ;加载到DS:0x0000处
         call read_hard_disk_0

         ;以下判断整个程序有多大
         mov dx,                      ;曾经把dx写成了ds,花了二十分钟排错
         mov ax,
         mov bx,512                      ;512字节每扇区
         div bx
         cmp dx,0
         jnz @1                        ;未除尽,因此结果比实际扇区数少1
         dec ax                        ;已经读了一个扇区,扇区总数减1
   @1:
         cmp ax,0                        ;考虑实际长度小于等于512个字节的情况
         jz direct

         ;读取剩余的扇区
         push ds                         ;以下要用到并改变DS寄存器

         mov cx,ax                     ;循环次数(剩余扇区数)
   @2:
         mov ax,ds
         add ax,0x20                     ;得到下一个以512字节为边界的段地址
         mov ds,ax

         xor bx,bx                     ;每次读时,偏移地址始终为0x0000
         inc si                        ;下一个逻辑扇区
         call read_hard_disk_0
         loop @2                         ;循环读,直到读完整个功能程序

         pop ds                        ;恢复数据段基址到用户程序头部段

         ;计算入口点代码段基址
   direct:
         mov dx,
         mov ax,
         call calc_segment_base
         mov ,ax                   ;回填修正后的入口点代码段基址

         ;开始处理段重定位表
         mov cx,                   ;需要重定位的项目数量
         mov bx,0x0c                     ;重定位表首地址

realloc:
         mov dx,                ;32位地址的高16位
         mov ax,
         call calc_segment_base
         mov ,ax                     ;回填段的基址
         add bx,4                        ;下一个重定位项(每项占4个字节)
         loop realloc

         jmp far                   ;转移到用户程序

;-------------------------------------------------------------------------------
read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
                                       ;输入:DI:SI=起始逻辑扇区号
                                       ;      DS:BX=目标缓冲区地址
         push ax
         push bx
         push cx
         push dx

         mov dx,0x1f2                                       ;0x1f2,写入的内容为要读取的扇区数
         mov al,1                                               ;读取1个扇区
         out dx,al                     ;读取的扇区数

         inc dx                        ;0x1f3
         mov ax,si                                               ;当前si的值为100D
         out dx,al                     ;LBA地址7~0

         inc dx                        ;0x1f4
         mov al,ah
         out dx,al                     ;LBA地址15~8

         inc dx                        ;0x1f5
         mov ax,di                                               ;当前di的值为0
         out dx,al                     ;LBA地址23~16

         inc dx                        ;0x1f6
         mov al,0xe0                     ;LBA28模式,主盘
         or al,ah                        ;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 cx,256                      ;总共要读取的字数
         mov dx,0x1f0
.readw:
         in ax,dx
         mov ,ax
         add bx,2
         loop .readw

         pop dx
         pop cx
         pop bx
         pop ax

         ret

;-------------------------------------------------------------------------------
calc_segment_base:                     ;计算16位段地址
                                       ;输入:DX:AX=32位物理地址
                                       ;返回:AX=16位段基地址
         push dx

         add ax,
         adc dx,
         shr ax,4
         ror dx,4
         and dx,0xf000
         or ax,dx

         pop dx

         ret

;-------------------------------------------------------------------------------
         phy_base dd 0x10000             ;用户程序被加载的物理起始地址

times 510-($-$) db 0
                  db 0x55,0xaa
页: [1]
查看完整版本: X86汇编语言-从实模式到保护模式—笔记(10)