|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 兰陵月 于 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,[cs:phy_base] ;计算用于加载用户程序的逻辑段地址
- mov dx,[cs:phy_base+0x02]
- 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,[2] ;曾经把dx写成了ds,花了二十分钟排错
- mov ax,[0]
- 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,[0x08]
- mov ax,[0x06]
- call calc_segment_base
- mov [0x06],ax ;回填修正后的入口点代码段基址
- ;开始处理段重定位表
- mov cx,[0x0a] ;需要重定位的项目数量
- mov bx,0x0c ;重定位表首地址
- realloc:
- mov dx,[bx+0x02] ;32位地址的高16位
- mov ax,[bx]
- call calc_segment_base
- mov [bx],ax ;回填段的基址
- add bx,4 ;下一个重定位项(每项占4个字节)
- loop realloc
- jmp far [0x04] ;转移到用户程序
- ;-------------------------------------------------------------------------------
- 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 [bx],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,[cs:phy_base]
- adc dx,[cs:phy_base+0x02]
- 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
复制代码 |
|