操作系统真相还原_第3章:8086汇编硬件交互

寄存器

段寄存器

CS:代码段寄存器
DS:数据段寄存器
ES:附加段寄存器
FS:附加段寄存器
GS:附加段寄存器
SS:栈段寄存器

通用寄存器

AX:累加器
BX:基址寄存器
CX:计数器
DX:数据寄存器
si:源变址寄存器
di:目的变址寄存器
sp:栈指针寄存器
bp:基址指针

标志寄存器

FLAGS

8086-1MB内存分布

寻址方式

寄存器寻址
立即数寻址
内存寻址
其中内存寻址可分为:
直接寻址
基址寻址
变址寻址
基址+变址寻址

bochs调试命令

Debugger control类

退出调试状态:q | quit | exit
设置寄存器的值:set reg=val
设置每次停止执行时是否反汇编指令:set u on | off
每次切换模式时进行提示:show mode
每次中断时进行提示:show int
每次函数调用时进行提示:show call
每次执行一条指令将反汇编代码打印:trace on | off
代码反汇编:u | disasm /num start end

Execution control类

持续执行,遇到断点则停止:c | cont | continue
执行n条指令,默认1条,不跳过函数:s | step n
执行1条指令,跳过函数:p | n | next

Breakpoint control类

以地址设置断点

物理地址:pb | pbreak | b | break [addr]
线性地址:lb | lbreak [addr]
虚拟地址:vb | vbreak [seg : off]

以指令数设置断点

从当前位置算起执行n条指令后中断:sb n
从CPU开始运行算起执行n条指令后中断:sba n

以读写IO设置断点

若对 [phy_addr]进行读操作时则中断:watch r | read [phy_addr]
若对 [phy_addr]进行写操作时则中断:watch w | write [phy_addr]

补充

显示所有读写断点:watch
清除[phy_addr]上的读写断点:unwatch [phy_addr]
清除所有读写断点:unwatch
显示所有断点信息:blist
禁用/启用断点n,n使用blist进行查询:bpd | bpe n
删除断点n,n使用blist进行查询:d | del | delete n

CPU and memory contents类

内存查看

查看物理地址内存:xp /nuf [phy_addr]
查看线性地址内存:x /nuf [addr]
堆栈查看:print-stack [num]
n:显示的单元数量
u:显示单元的大小,b为1B,h为2B,w为4B,g为8B
f:显示格式,x为十六进制,d为十进制,u为无符号十进制,o为八进制,t为二进制,c为字符显示,s为ASCIIz显示,i为instr显示

内存操作

设置[phy_addr]开始的连续size个字节的内容为val:setpmem [phy_addr] [size] [val]

寄存器查看

通用寄存器查看:r | regs | registers
状态寄存器查看:info flags | eflags
段寄存器查看:sreg
调试寄存器查看:dreg
控制寄存器查看:creg
查看所有寄存器:info CPU

特殊数据查看

断点信息查看,等同于blist:info pb | pbreak | b | break
FPU状态查看:info fpu
查看全局描述符表中第n个表项:info gdt n
查看中断向量表中第n个表项:info ivt n
查看中断向量表:info idt
查看局部描述符表:info ldt
查看任务状态段:info tss
查看线性地址到物理地址的映射:page line_addr
查看页表中线性地址到物理地址的映射:info tab

显存交互

显存的基础知识

显存分布:

显示模式:
从起始地址0xB8000到0xBFFFF的32KB的内存区域用于文本显示
显示模式有多种,用列数行数来表示,例如8025,4025…
模式的乘积就是整个屏幕可以容纳的字符数量,默认在80
25模式下工作
1个字符的数据结构如下,前1字节为ASCII码,后1字节为字符属性
在8025的工作模式下,1页屏幕占用280*25字节,一共可以分为32KB/4KB页

操作显存示例

编写主引导扇区代码,在屏幕上显示 Hello, World!!!

程序编写mbr.s

;主引导程序 
;------------------------------------------------------------
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov ax, 0xB800
   mov gs, ax
   mov sp,0x7c00

; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
   mov     ax, 0x600
   mov     bx, 0x700
   mov     cx, 0           ; 左上角: (0, 0)
   mov     dx, 0x184f	   ; 右下角: (80,25),
			   ; VGA文本模式中,一行只能容纳80个字符,共25行。
			   ; 下标从0开始,所以0x18=24,0x4f=79
   int     0x10            ; int 0x10


;;;;;;;;;     打印字符串    ;;;;;;;;;;;
   mov cx, sx-msg
   mov si, msg
   mov di, 0
show_str:
   mov byte al, [si]
   mov byte ah, [sx]
   mov word [gs:di], ax
   inc si
   add di, 2
   loop show_str
;;;;;;;;;      打字字符串结束	 ;;;;;;;;;;;;;;;

   jmp $		; 使程序悬停在此

   msg db "Hello, World!!!"
   sx db 0xA4
   times 510-($-$$) db 0
   db 0x55,0xaa

编译并写入硬盘

编译:nasm -o mbr.bin mbr.s
写入硬盘:dd if=OS/boot/mbr.bin of=bochs/hd60M.img bs=512 count=1 conv=notrunc

启动bochs执行

./bochs安装目录/bin/bochs -f bochs配置文件

硬盘交互

通过主引导扇区代码从硬盘中读入loader程序,并跳转至loader入口执行

硬盘控制器主要端口


注:此处的读操作和写操作指的是读写端口,而非硬盘

硬盘寻址

硬盘结构

CHS方式寻址

Cylinder:柱面
Head:磁头
Sector:扇区

LBA方式寻址

分为LBA28、LBA48
LBA28方式寻址:
0~7位:0x1F3 | 0x173
8~15位:0x1F4 | 0x174
16~23位:0x1F5 | 0x175
24~27位:0x1F6低4位 | 0x176低4位

端口

device端口


注:0表示主盘,1表示从盘

command端口

主要使用的命令:
identify:0xEC,硬盘识别
read sector:0x20,读扇区
write sector:0x30,写扇区

status端口

操作端口的指令

in op1, op2
in表示读取端口寄存器
op1为寄存器
op2为端口号

out op1, op2
out表示向端口寄存器写入
op1为端口号
op2为寄存器

注:op1、op2只能是dx, ax或al
dx用于指定端口,ax、al、ah用于传输数据

硬盘读写操作顺序

1、选择主/从通道,向sector count端口写入要操作的扇区的数量
2、写入扇区逻辑地址的低24位,往device中写入逻辑扇区地址的高4位
3、设置device端口第6位选择寻址模式,设置第4位选择硬盘
4、设置command端口的命令(读、写或其他)
5、读取status端口获取硬盘状态,判断硬盘是否已经完成工作
6、若以上步骤是读硬盘则进入下一步,否则完工
7、将硬盘数据读出

补充:
无论是写入或读取硬盘数据,CPU都是与硬盘控制器的缓冲区进行交互
读数据时,硬盘准备好了说明缓冲区已经准备好了需要的数据
写数据时,也是向缓冲区写数据,硬盘准备好了说明缓冲区能够接收数据了

数据读取方式

1、无条件传送方式
2、查询传送方式
3、中断传送方式
4、直接存储器存储方式
5、I/O处理机传送方式

硬盘交互示例

使用mbr.s程序加载硬盘中的loader.s程序,并跳转至loader程序运行
loader程序安排在第2个扇区,LBA地址:0x0000001
%include “配置文件名.inc”,%include为nasm的预处理器,意思是在编译之前将"配置文件名.inc"包含进来

配置文件boot.inc

;--------- mbr & loader ---------
LBA_START_SECTOR equ 0x1
SECTOR_COUNT equ 0x1
LOADER_BASE_ADDR equ 0x100
LOADER_OFF_ADDR equ 0x0
LOADER_ADDR equ 0x1000

mbr程序

;主引导程序
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov ax, 0xB800
   mov gs, ax
   mov sp,0x7c00

; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
   mov     ax, 0x600
   mov     bx, 0x700
   mov     cx, 0           ; 左上角: (0, 0)
   mov     dx, 0x184f	   ; 右下角: (80,25),
			   ; VGA文本模式中,一行只能容纳80个字符,共25行。
			   ; 下标从0开始,所以0x18=24,0x4f=79
   int     0x10            ; int 0x10


;;;;;;;;;     打印字符串    ;;;;;;;;;;;

   mov cx, sx - msg
   mov si, msg
   mov di, 0
show_str:
   mov byte al, [si]
   mov byte ah, [sx]
   mov word [gs:di], ax
   inc si
   add di, 2
   loop show_str
   jmp L0

   msg db "enter mbr"
   sx db 0x24

;;;;;;;;;      打字字符串结束	 ;;;;;;;;;;;;;;;
L0:
   push ds
   push di
   mov eax, LBA_START_SECTOR
   push eax
   mov ax, SECTOR_COUNT
   push ax
   mov ax, LOADER_BASE_ADDR
   push ax
   mov ax, LOADER_OFF_ADDR
   push ax
   call read_disk
   add sp, 10
   pop di
   pop ds

   jmp LOADER_ADDR

;;;;;;;;;      read disk      ;;;;;;;;;

; LBA: [bp+10]
; sector count: [bp+8]
; destination: sec=[bp+6], off=[bp+4]
read_disk:
   push bp
   mov bp, sp

;sector_count
   mov dx,0x1f2
   mov ax, [bp+8]
   out dx, al

;sector_addr
   mov dx, 0x1f3
   mov ax, [bp+10]
   out dx, al

   mov dx, 0x1f4
   mov al, ah
   out dx, al

   mov dx, 0x1f5
   mov ax, [bp+12]
   out dx, al

   mov dx, 0x1f6
   mov al, ah
   and al, 0x0f
   or al, 0xe0
   out dx, al

;command_write
   mov dx, 0x1f7
   mov al, 0x20
   out dx, al

disk_test:
   nop          ;give disk a moment
   in al, dx
   and al, 0x88 ;7: BUSY, 3: READY
   cmp al, 0x08 ; (BUSY=0 & READY=1) or not?
   jnz disk_test

;data_read:   
   mov ax, [bp+8]
   mov dx, 256
   mul dx
   mov cx, ax

   mov bx, [bp+4]
   mov ax, [bp+6]
   mov ds, ax

   mov dx, 0x1f0
go_on_read:
   in ax, dx
   mov [bx], ax
   add bx,2
   loop go_on_read

   mov sp, bp
   pop bp
   ret
;;;;;;;;;      read disk      ;;;;;;;;;

   times 510-($-$$) db 0
   db 0x55,0xaa

loader程序

%include "boot.inc"
section loader vstart=LOADER_ADDR
;;;;;;;;;     打印字符串    ;;;;;;;;;;;

   mov cx, sx-msg
   mov si, msg
   mov di, 160
show_str:
   mov byte al, [si]
   mov byte ah, [sx]
   mov word [gs:di], ax
   inc si
   add di, 2
   loop show_str

   msg db "enter loader"
   sx db 0x24

;;;;;;;;;      打字字符串结束    ;;;;;;;;;;;;;;;
   jmp $

编译并写入硬盘

nasm -I 配置文件所在目录 -o mbr.bin mbr.s所在目录/mbr.s
nasm -I 配置文件所在目录 -o loader.s.bin loader.s所在目录/loader.s
dd if=mbr.s所在目录/mbr.bin of=硬盘所在目录/hd60M.img bs=512 count=1 seek=0 conv=notrunc
dd if=loader.s所在目录/loader.bin of=硬盘所在目录/hd60M.img bs=512 count=1 seek=1 conv=notrunc

启动bochs执行

./bochs安装目录/bochs/bin/bochs -f bochs配置文件所在目录/boot.disk

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值