@@ -0,0 +1,7 @@ | |||
*.o | |||
*.bin | |||
*.ini | |||
*.exe | |||
*.vhd | |||
*.rar | |||
*.xml |
@@ -0,0 +1,103 @@ | |||
;代码清单5-1 | |||
;文件名:c05_mbr.asm | |||
;文件说明:硬盘主引导扇区代码 | |||
;创建日期:2011-3-31 21:15 | |||
mov ax,0xb800 ;指向文本模式的显示缓冲区 | |||
mov es,ax | |||
;以下显示字符串"Label offset:" | |||
mov byte [es:0x00],'L' | |||
mov byte [es:0x01],0x07 | |||
mov byte [es:0x02],'a' | |||
mov byte [es:0x03],0x07 | |||
mov byte [es:0x04],'b' | |||
mov byte [es:0x05],0x07 | |||
mov byte [es:0x06],'e' | |||
mov byte [es:0x07],0x07 | |||
mov byte [es:0x08],'l' | |||
mov byte [es:0x09],0x07 | |||
mov byte [es:0x0a],' ' | |||
mov byte [es:0x0b],0x07 | |||
mov byte [es:0x0c],"o" | |||
mov byte [es:0x0d],0x07 | |||
mov byte [es:0x0e],'f' | |||
mov byte [es:0x0f],0x07 | |||
mov byte [es:0x10],'f' | |||
mov byte [es:0x11],0x07 | |||
mov byte [es:0x12],'s' | |||
mov byte [es:0x13],0x07 | |||
mov byte [es:0x14],'e' | |||
mov byte [es:0x15],0x07 | |||
mov byte [es:0x16],'t' | |||
mov byte [es:0x17],0x07 | |||
mov byte [es:0x18],':' | |||
mov byte [es:0x19],0x07 | |||
mov ax,number ;取得标号number的偏移地址 | |||
mov bx,10 | |||
;设置数据段的基地址 | |||
mov cx,cs | |||
mov ds,cx | |||
;求个位上的数字 | |||
mov dx,0 | |||
div bx | |||
mov [0x7c00+number+0x00],dl ;保存个位上的数字 | |||
;求十位上的数字 | |||
xor dx,dx | |||
div bx | |||
mov [0x7c00+number+0x01],dl ;保存十位上的数字 | |||
;求百位上的数字 | |||
xor dx,dx | |||
div bx | |||
mov [0x7c00+number+0x02],dl ;保存百位上的数字 | |||
;求千位上的数字 | |||
xor dx,dx | |||
div bx | |||
mov [0x7c00+number+0x03],dl ;保存千位上的数字 | |||
;求万位上的数字 | |||
xor dx,dx | |||
div bx | |||
mov [0x7c00+number+0x04],dl ;保存万位上的数字 | |||
;以下用十进制显示标号的偏移地址 | |||
mov al,[0x7c00+number+0x04] | |||
add al,0x30 | |||
mov [es:0x1a],al | |||
mov byte [es:0x1b],0x04 | |||
mov al,[0x7c00+number+0x03] | |||
add al,0x30 | |||
mov [es:0x1c],al | |||
mov byte [es:0x1d],0x04 | |||
mov al,[0x7c00+number+0x02] | |||
add al,0x30 | |||
mov [es:0x1e],al | |||
mov byte [es:0x1f],0x04 | |||
mov al,[0x7c00+number+0x01] | |||
add al,0x30 | |||
mov [es:0x20],al | |||
mov byte [es:0x21],0x04 | |||
mov al,[0x7c00+number+0x00] | |||
add al,0x30 | |||
mov [es:0x22],al | |||
mov byte [es:0x23],0x04 | |||
mov byte [es:0x24],'D' | |||
mov byte [es:0x25],0x07 | |||
infi: jmp near infi ;无限循环 | |||
number db 0,0,0,0,0 | |||
times 203 db 0 | |||
db 0x55,0xaa |
@@ -0,0 +1,103 @@ | |||
1 ;代码清单5-1 | |||
2 ;文件名:c05_mbr.asm | |||
3 ;文件说明:硬盘主引导扇区代码 | |||
4 ;创建日期:2011-3-31 21:15 | |||
5 | |||
6 00000000 B800B8 mov ax,0xb800 ;指向文本模式的显示缓冲区 | |||
7 00000003 8EC0 mov es,ax | |||
8 | |||
9 ;以下显示字符串"Label offset:" | |||
10 00000005 26C60600004C mov byte [es:0x00],'L' | |||
11 0000000B 26C606010007 mov byte [es:0x01],0x07 | |||
12 00000011 26C606020061 mov byte [es:0x02],'a' | |||
13 00000017 26C606030007 mov byte [es:0x03],0x07 | |||
14 0000001D 26C606040062 mov byte [es:0x04],'b' | |||
15 00000023 26C606050007 mov byte [es:0x05],0x07 | |||
16 00000029 26C606060065 mov byte [es:0x06],'e' | |||
17 0000002F 26C606070007 mov byte [es:0x07],0x07 | |||
18 00000035 26C60608006C mov byte [es:0x08],'l' | |||
19 0000003B 26C606090007 mov byte [es:0x09],0x07 | |||
20 00000041 26C6060A0020 mov byte [es:0x0a],' ' | |||
21 00000047 26C6060B0007 mov byte [es:0x0b],0x07 | |||
22 0000004D 26C6060C006F mov byte [es:0x0c],"o" | |||
23 00000053 26C6060D0007 mov byte [es:0x0d],0x07 | |||
24 00000059 26C6060E0066 mov byte [es:0x0e],'f' | |||
25 0000005F 26C6060F0007 mov byte [es:0x0f],0x07 | |||
26 00000065 26C606100066 mov byte [es:0x10],'f' | |||
27 0000006B 26C606110007 mov byte [es:0x11],0x07 | |||
28 00000071 26C606120073 mov byte [es:0x12],'s' | |||
29 00000077 26C606130007 mov byte [es:0x13],0x07 | |||
30 0000007D 26C606140065 mov byte [es:0x14],'e' | |||
31 00000083 26C606150007 mov byte [es:0x15],0x07 | |||
32 00000089 26C606160074 mov byte [es:0x16],'t' | |||
33 0000008F 26C606170007 mov byte [es:0x17],0x07 | |||
34 00000095 26C60618003A mov byte [es:0x18],':' | |||
35 0000009B 26C606190007 mov byte [es:0x19],0x07 | |||
36 | |||
37 000000A1 B8[2E01] mov ax,number ;取得标号number的偏移地址 | |||
38 000000A4 BB0A00 mov bx,10 | |||
39 | |||
40 ;设置数据段的基地址 | |||
41 000000A7 8CC9 mov cx,cs | |||
42 000000A9 8ED9 mov ds,cx | |||
43 | |||
44 ;求个位上的数字 | |||
45 000000AB BA0000 mov dx,0 | |||
46 000000AE F7F3 div bx | |||
47 000000B0 8816[2E7D] mov [0x7c00+number+0x00],dl ;保存个位上的数字 | |||
48 | |||
49 ;求十位上的数字 | |||
50 000000B4 31D2 xor dx,dx | |||
51 000000B6 F7F3 div bx | |||
52 000000B8 8816[2F7D] mov [0x7c00+number+0x01],dl ;保存十位上的数字 | |||
53 | |||
54 ;求百位上的数字 | |||
55 000000BC 31D2 xor dx,dx | |||
56 000000BE F7F3 div bx | |||
57 000000C0 8816[307D] mov [0x7c00+number+0x02],dl ;保存百位上的数字 | |||
58 | |||
59 ;求千位上的数字 | |||
60 000000C4 31D2 xor dx,dx | |||
61 000000C6 F7F3 div bx | |||
62 000000C8 8816[317D] mov [0x7c00+number+0x03],dl ;保存千位上的数字 | |||
63 | |||
64 ;求万位上的数字 | |||
65 000000CC 31D2 xor dx,dx | |||
66 000000CE F7F3 div bx | |||
67 000000D0 8816[327D] mov [0x7c00+number+0x04],dl ;保存万位上的数字 | |||
68 | |||
69 ;以下用十进制显示标号的偏移地址 | |||
70 000000D4 A0[327D] mov al,[0x7c00+number+0x04] | |||
71 000000D7 0430 add al,0x30 | |||
72 000000D9 26A21A00 mov [es:0x1a],al | |||
73 000000DD 26C6061B0004 mov byte [es:0x1b],0x04 | |||
74 | |||
75 000000E3 A0[317D] mov al,[0x7c00+number+0x03] | |||
76 000000E6 0430 add al,0x30 | |||
77 000000E8 26A21C00 mov [es:0x1c],al | |||
78 000000EC 26C6061D0004 mov byte [es:0x1d],0x04 | |||
79 | |||
80 000000F2 A0[307D] mov al,[0x7c00+number+0x02] | |||
81 000000F5 0430 add al,0x30 | |||
82 000000F7 26A21E00 mov [es:0x1e],al | |||
83 000000FB 26C6061F0004 mov byte [es:0x1f],0x04 | |||
84 | |||
85 00000101 A0[2F7D] mov al,[0x7c00+number+0x01] | |||
86 00000104 0430 add al,0x30 | |||
87 00000106 26A22000 mov [es:0x20],al | |||
88 0000010A 26C606210004 mov byte [es:0x21],0x04 | |||
89 | |||
90 00000110 A0[2E7D] mov al,[0x7c00+number+0x00] | |||
91 00000113 0430 add al,0x30 | |||
92 00000115 26A22200 mov [es:0x22],al | |||
93 00000119 26C606230004 mov byte [es:0x23],0x04 | |||
94 | |||
95 0000011F 26C606240044 mov byte [es:0x24],'D' | |||
96 00000125 26C606250007 mov byte [es:0x25],0x07 | |||
97 | |||
98 0000012B E9FDFF infi: jmp near infi ;无限循环 | |||
99 | |||
100 0000012E 0000000000 number db 0,0,0,0,0 | |||
101 | |||
102 00000133 00<rept> times 203 db 0 | |||
103 000001FE 55AA db 0x55,0xaa |
@@ -0,0 +1,56 @@ | |||
;代码清单6-1 | |||
;文件名:c06_mbr.asm | |||
;文件说明:硬盘主引导扇区代码 | |||
;创建日期:2011-4-12 22:12 | |||
jmp near start | |||
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\ | |||
'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07 | |||
number db 0,0,0,0,0 | |||
start: | |||
mov ax,0x7c0 ;设置数据段基地址 | |||
mov ds,ax | |||
mov ax,0xb800 ;设置附加段基地址 | |||
mov es,ax | |||
cld | |||
mov si,mytext | |||
mov di,0 | |||
mov cx,(number-mytext)/2 ;实际上等于 13 | |||
rep movsw | |||
;得到标号所代表的偏移地址 | |||
mov ax,number | |||
;计算各个数位 | |||
mov bx,ax | |||
mov cx,5 ;循环次数 | |||
mov si,10 ;除数 | |||
digit: | |||
xor dx,dx | |||
div si | |||
mov [bx],dl ;保存数位 | |||
inc bx | |||
loop digit | |||
;显示各个数位 | |||
mov bx,number | |||
mov si,4 | |||
show: | |||
mov al,[bx+si] | |||
add al,0x30 | |||
mov ah,0x04 | |||
mov [es:di],ax | |||
add di,2 | |||
dec si | |||
jns show | |||
mov word [es:di],0x0744 | |||
jmp near $ | |||
times 510-($-$$) db 0 | |||
db 0x55,0xaa |
@@ -0,0 +1,68 @@ | |||
;代码清单7-1 | |||
;文件名:c07_mbr.asm | |||
;文件说明:硬盘主引导扇区代码 | |||
;创建日期:2011-4-13 18:02 | |||
jmp near start | |||
message db '1+2+3+...+100=' | |||
start: | |||
mov ax,0x7c0 ;设置数据段的段基地址 | |||
mov ds,ax | |||
mov ax,0xb800 ;设置附加段基址到显示缓冲区 | |||
mov es,ax | |||
;以下显示字符串 | |||
mov si,message | |||
mov di,0 | |||
mov cx,start-message | |||
@g: | |||
mov al,[si] | |||
mov [es:di],al | |||
inc di | |||
mov byte [es:di],0x07 | |||
inc di | |||
inc si | |||
loop @g | |||
;以下计算1到100的和 | |||
xor ax,ax | |||
mov cx,1 | |||
@f: | |||
add ax,cx | |||
inc cx | |||
cmp cx,100 | |||
jle @f | |||
;以下计算累加和的每个数位 | |||
xor cx,cx ;设置堆栈段的段基地址 | |||
mov ss,cx | |||
mov sp,cx | |||
mov bx,10 | |||
xor cx,cx | |||
@d: | |||
inc cx | |||
xor dx,dx | |||
div bx | |||
or dl,0x30 | |||
push dx | |||
cmp ax,0 | |||
jne @d | |||
;以下显示各个数位 | |||
@a: | |||
pop dx | |||
mov [es:di],dl | |||
inc di | |||
mov byte [es:di],0x07 | |||
inc di | |||
loop @a | |||
jmp near $ | |||
times 510-($-$$) db 0 | |||
db 0x55,0xaa |
@@ -0,0 +1,209 @@ | |||
;代码清单8-2 | |||
;文件名:c08.asm | |||
;文件说明:用户程序 | |||
;创建日期:2011-5-5 18:17 | |||
;=============================================================================== | |||
SECTION header vstart=0 ;定义用户程序头部段 | |||
program_length dd program_end ;程序总长度[0x00] | |||
;用户程序入口点 | |||
code_entry dw start ;偏移地址[0x04] | |||
dd section.code_1.start ;段地址[0x06] | |||
realloc_tbl_len dw (header_end-code_1_segment)/4 | |||
;段重定位表项个数[0x0a] | |||
;段重定位表 | |||
code_1_segment dd section.code_1.start ;[0x0c] | |||
code_2_segment dd section.code_2.start ;[0x10] | |||
data_1_segment dd section.data_1.start ;[0x14] | |||
data_2_segment dd section.data_2.start ;[0x18] | |||
stack_segment dd section.stack.start ;[0x1c] | |||
header_end: | |||
;=============================================================================== | |||
SECTION code_1 align=16 vstart=0 ;定义代码段1(16字节对齐) | |||
put_string: ;显示串(0结尾)。 | |||
;输入:DS:BX=串地址 | |||
mov cl,[bx] | |||
or cl,cl ;cl=0 ? | |||
jz .exit ;是的,返回主程序 | |||
call put_char | |||
inc bx ;下一个字符 | |||
jmp put_string | |||
.exit: | |||
ret | |||
;------------------------------------------------------------------------------- | |||
put_char: ;显示一个字符 | |||
;输入:cl=字符ascii | |||
push ax | |||
push bx | |||
push cx | |||
push dx | |||
push ds | |||
push es | |||
;以下取当前光标位置 | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
mov dx,0x3d5 | |||
in al,dx ;高8位 | |||
mov ah,al | |||
mov dx,0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
mov dx,0x3d5 | |||
in al,dx ;低8位 | |||
mov bx,ax ;BX=代表光标位置的16位数 | |||
cmp cl,0x0d ;回车符? | |||
jnz .put_0a ;不是。看看是不是换行等字符 | |||
mov ax,bx ;此句略显多余,但去掉后还得改书,麻烦 | |||
mov bl,80 | |||
div bl | |||
mul bl | |||
mov bx,ax | |||
jmp .set_cursor | |||
.put_0a: | |||
cmp cl,0x0a ;换行符? | |||
jnz .put_other ;不是,那就正常显示字符 | |||
add bx,80 | |||
jmp .roll_screen | |||
.put_other: ;正常显示字符 | |||
mov ax,0xb800 | |||
mov es,ax | |||
shl bx,1 | |||
mov [es:bx],cl | |||
;以下将光标位置推进一个字符 | |||
shr bx,1 | |||
add bx,1 | |||
.roll_screen: | |||
cmp bx,2000 ;光标超出屏幕?滚屏 | |||
jl .set_cursor | |||
mov ax,0xb800 | |||
mov ds,ax | |||
mov es,ax | |||
cld | |||
mov si,0xa0 | |||
mov di,0x00 | |||
mov cx,1920 | |||
rep movsw | |||
mov bx,3840 ;清除屏幕最底一行 | |||
mov cx,80 | |||
.cls: | |||
mov word[es:bx],0x0720 | |||
add bx,2 | |||
loop .cls | |||
mov bx,1920 | |||
.set_cursor: | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
mov dx,0x3d5 | |||
mov al,bh | |||
out dx,al | |||
mov dx,0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
mov dx,0x3d5 | |||
mov al,bl | |||
out dx,al | |||
pop es | |||
pop ds | |||
pop dx | |||
pop cx | |||
pop bx | |||
pop ax | |||
ret | |||
;------------------------------------------------------------------------------- | |||
start: | |||
;初始执行时,DS和ES指向用户程序头部段 | |||
mov ax,[stack_segment] ;设置到用户程序自己的堆栈 | |||
mov ss,ax | |||
mov sp,stack_end | |||
mov ax,[data_1_segment] ;设置到用户程序自己的数据段 | |||
mov ds,ax | |||
mov bx,msg0 | |||
call put_string ;显示第一段信息 | |||
push word [es:code_2_segment] | |||
mov ax,begin | |||
push ax ;可以直接push begin,80386+ | |||
retf ;转移到代码段2执行 | |||
continue: | |||
mov ax,[es:data_2_segment] ;段寄存器DS切换到数据段2 | |||
mov ds,ax | |||
mov bx,msg1 | |||
call put_string ;显示第二段信息 | |||
jmp $ | |||
;=============================================================================== | |||
SECTION code_2 align=16 vstart=0 ;定义代码段2(16字节对齐) | |||
begin: | |||
push word [es:code_1_segment] | |||
mov ax,continue | |||
push ax ;可以直接push continue,80386+ | |||
retf ;转移到代码段1接着执行 | |||
;=============================================================================== | |||
SECTION data_1 align=16 vstart=0 | |||
msg0 db ' This is NASM - the famous Netwide Assembler. ' | |||
db 'Back at SourceForge and in intensive development! ' | |||
db 'Get the current versions from http://www.nasm.us/.' | |||
db 0x0d,0x0a,0x0d,0x0a | |||
db ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a | |||
db ' xor dx,dx',0x0d,0x0a | |||
db ' xor ax,ax',0x0d,0x0a | |||
db ' xor cx,cx',0x0d,0x0a | |||
db ' @@:',0x0d,0x0a | |||
db ' inc cx',0x0d,0x0a | |||
db ' add ax,cx',0x0d,0x0a | |||
db ' adc dx,0',0x0d,0x0a | |||
db ' inc cx',0x0d,0x0a | |||
db ' cmp cx,1000',0x0d,0x0a | |||
db ' jle @@',0x0d,0x0a | |||
db ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a | |||
db 0 | |||
;=============================================================================== | |||
SECTION data_2 align=16 vstart=0 | |||
msg1 db ' The above contents is written by LeeChung. ' | |||
db '2011-05-06' | |||
db 0 | |||
;=============================================================================== | |||
SECTION stack align=16 vstart=0 | |||
resb 256 | |||
stack_end: | |||
;=============================================================================== | |||
SECTION trail align=16 | |||
program_end: |
@@ -0,0 +1,247 @@ | |||
1 ;代码清单8-2 | |||
2 ;文件名:c08.asm | |||
3 ;文件说明:用户程序 | |||
4 ;创建日期:2011-5-5 18:17 | |||
5 | |||
6 ;=============================================================================== | |||
7 SECTION header vstart=0 ;定义用户程序头部段 | |||
8 00000000 [00000000] program_length dd program_end ;程序总长度[0x00] | |||
9 | |||
10 ;用户程序入口点 | |||
11 00000004 [A000] code_entry dw start ;偏移地址[0x04] | |||
12 00000006 [00000000] dd section.code_1.start ;段地址[0x06] | |||
13 | |||
14 0000000A 0500 realloc_tbl_len dw (header_end-code_1_segment)/4 | |||
15 ;段重定位表项个数[0x0a] | |||
16 | |||
17 ;段重定位表 | |||
18 0000000C [00000000] code_1_segment dd section.code_1.start ;[0x0c] | |||
19 00000010 [00000000] code_2_segment dd section.code_2.start ;[0x10] | |||
20 00000014 [00000000] data_1_segment dd section.data_1.start ;[0x14] | |||
21 00000018 [00000000] data_2_segment dd section.data_2.start ;[0x18] | |||
22 0000001C [00000000] stack_segment dd section.stack.start ;[0x1c] | |||
23 | |||
24 header_end: | |||
25 | |||
26 ;=============================================================================== | |||
27 SECTION code_1 align=16 vstart=0 ;定义代码段1(16字节对齐) | |||
28 put_string: ;显示串(0结尾)。 | |||
29 ;输入:DS:BX=串地址 | |||
30 00000000 8A0F mov cl,[bx] | |||
31 00000002 08C9 or cl,cl ;cl=0 ? | |||
32 00000004 7406 jz .exit ;是的,返回主程序 | |||
33 00000006 E80400 call put_char | |||
34 00000009 43 inc bx ;下一个字符 | |||
35 0000000A EBF4 jmp put_string | |||
36 | |||
37 .exit: | |||
38 0000000C C3 ret | |||
39 | |||
40 ;------------------------------------------------------------------------------- | |||
41 put_char: ;显示一个字符 | |||
42 ;输入:cl=字符ascii | |||
43 0000000D 50 push ax | |||
44 0000000E 53 push bx | |||
45 0000000F 51 push cx | |||
46 00000010 52 push dx | |||
47 00000011 1E push ds | |||
48 00000012 06 push es | |||
49 | |||
50 ;以下取当前光标位置 | |||
51 00000013 BAD403 mov dx,0x3d4 | |||
52 00000016 B00E mov al,0x0e | |||
53 00000018 EE out dx,al | |||
54 00000019 BAD503 mov dx,0x3d5 | |||
55 0000001C EC in al,dx ;高8位 | |||
56 0000001D 88C4 mov ah,al | |||
57 | |||
58 0000001F BAD403 mov dx,0x3d4 | |||
59 00000022 B00F mov al,0x0f | |||
60 00000024 EE out dx,al | |||
61 00000025 BAD503 mov dx,0x3d5 | |||
62 00000028 EC in al,dx ;低8位 | |||
63 00000029 89C3 mov bx,ax ;BX=代表光标位置的16位数 | |||
64 | |||
65 0000002B 80F90D cmp cl,0x0d ;回车符? | |||
66 0000002E 750C jnz .put_0a ;不是。看看是不是换行等字符 | |||
67 00000030 89D8 mov ax,bx ;此句略显多余,但去掉后还得改书,麻烦 | |||
68 00000032 B350 mov bl,80 | |||
69 00000034 F6F3 div bl | |||
70 00000036 F6E3 mul bl | |||
71 00000038 89C3 mov bx,ax | |||
72 0000003A EB45 jmp .set_cursor | |||
73 | |||
74 .put_0a: | |||
75 0000003C 80F90A cmp cl,0x0a ;换行符? | |||
76 0000003F 7505 jnz .put_other ;不是,那就正常显示字符 | |||
77 00000041 83C350 add bx,80 | |||
78 00000044 EB0F jmp .roll_screen | |||
79 | |||
80 .put_other: ;正常显示字符 | |||
81 00000046 B800B8 mov ax,0xb800 | |||
82 00000049 8EC0 mov es,ax | |||
83 0000004B D1E3 shl bx,1 | |||
84 0000004D 26880F mov [es:bx],cl | |||
85 | |||
86 ;以下将光标位置推进一个字符 | |||
87 00000050 D1EB shr bx,1 | |||
88 00000052 83C301 add bx,1 | |||
89 | |||
90 .roll_screen: | |||
91 00000055 81FBD007 cmp bx,2000 ;光标超出屏幕?滚屏 | |||
92 00000059 7C26 jl .set_cursor | |||
93 | |||
94 0000005B B800B8 mov ax,0xb800 | |||
95 0000005E 8ED8 mov ds,ax | |||
96 00000060 8EC0 mov es,ax | |||
97 00000062 FC cld | |||
98 00000063 BEA000 mov si,0xa0 | |||
99 00000066 BF0000 mov di,0x00 | |||
100 00000069 B98007 mov cx,1920 | |||
101 0000006C F3A5 rep movsw | |||
102 0000006E BB000F mov bx,3840 ;清除屏幕最底一行 | |||
103 00000071 B95000 mov cx,80 | |||
104 .cls: | |||
105 00000074 26C7072007 mov word[es:bx],0x0720 | |||
106 00000079 83C302 add bx,2 | |||
107 0000007C E2F6 loop .cls | |||
108 | |||
109 0000007E BB8007 mov bx,1920 | |||
110 | |||
111 .set_cursor: | |||
112 00000081 BAD403 mov dx,0x3d4 | |||
113 00000084 B00E mov al,0x0e | |||
114 00000086 EE out dx,al | |||
115 00000087 BAD503 mov dx,0x3d5 | |||
116 0000008A 88F8 mov al,bh | |||
117 0000008C EE out dx,al | |||
118 0000008D BAD403 mov dx,0x3d4 | |||
119 00000090 B00F mov al,0x0f | |||
120 00000092 EE out dx,al | |||
121 00000093 BAD503 mov dx,0x3d5 | |||
122 00000096 88D8 mov al,bl | |||
123 00000098 EE out dx,al | |||
124 | |||
125 00000099 07 pop es | |||
126 0000009A 1F pop ds | |||
127 0000009B 5A pop dx | |||
128 0000009C 59 pop cx | |||
129 0000009D 5B pop bx | |||
130 0000009E 58 pop ax | |||
131 | |||
132 0000009F C3 ret | |||
133 | |||
134 ;------------------------------------------------------------------------------- | |||
135 start: | |||
136 ;初始执行时,DS和ES指向用户程序头部段 | |||
137 000000A0 A1[1C00] mov ax,[stack_segment] ;设置到用户程序自己的堆栈 | |||
138 000000A3 8ED0 mov ss,ax | |||
139 000000A5 BC[0001] mov sp,stack_end | |||
140 | |||
141 000000A8 A1[1400] mov ax,[data_1_segment] ;设置到用户程序自己的数据段 | |||
142 000000AB 8ED8 mov ds,ax | |||
143 | |||
144 000000AD BB[0000] mov bx,msg0 | |||
145 000000B0 E84DFF call put_string ;显示第一段信息 | |||
146 | |||
147 000000B3 26FF36[1000] push word [es:code_2_segment] | |||
148 000000B8 B8[0000] mov ax,begin | |||
149 000000BB 50 push ax ;可以直接push begin,80386+ | |||
150 | |||
151 000000BC CB retf ;转移到代码段2执行 | |||
152 | |||
153 continue: | |||
154 000000BD 26A1[1800] mov ax,[es:data_2_segment] ;段寄存器DS切换到数据段2 | |||
155 000000C1 8ED8 mov ds,ax | |||
156 | |||
157 000000C3 BB[0000] mov bx,msg1 | |||
158 000000C6 E837FF call put_string ;显示第二段信息 | |||
159 | |||
160 000000C9 EBFE jmp $ | |||
161 | |||
162 ;=============================================================================== | |||
163 SECTION code_2 align=16 vstart=0 ;定义代码段2(16字节对齐) | |||
164 | |||
165 begin: | |||
166 00000000 26FF36[0C00] push word [es:code_1_segment] | |||
167 00000005 B8[BD00] mov ax,continue | |||
168 00000008 50 push ax ;可以直接push continue,80386+ | |||
169 | |||
170 00000009 CB retf ;转移到代码段1接着执行 | |||
171 | |||
172 ;=============================================================================== | |||
173 SECTION data_1 align=16 vstart=0 | |||
174 | |||
175 00000000 202054686973206973- msg0 db ' This is NASM - the famous Netwide Assembler. ' | |||
176 00000009 204E41534D202D2074- | |||
177 00000012 68652066616D6F7573- | |||
178 0000001B 204E65747769646520- | |||
179 00000024 417373656D626C6572- | |||
180 0000002D 2E20 | |||
181 0000002F 4261636B2061742053- db 'Back at SourceForge and in intensive development! ' | |||
182 00000038 6F75726365466F7267- | |||
183 00000041 6520616E6420696E20- | |||
184 0000004A 696E74656E73697665- | |||
185 00000053 20646576656C6F706D- | |||
186 0000005C 656E742120 | |||
187 00000061 476574207468652063- db 'Get the current versions from http://www.nasm.us/.' | |||
188 0000006A 757272656E74207665- | |||
189 00000073 7273696F6E73206672- | |||
190 0000007C 6F6D20687474703A2F- | |||
191 00000085 2F7777772E6E61736D- | |||
192 0000008E 2E75732F2E | |||
193 00000093 0D0A0D0A db 0x0d,0x0a,0x0d,0x0a | |||
194 00000097 20204578616D706C65- db ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a | |||
195 000000A0 20636F646520666F72- | |||
196 000000A9 2063616C63756C6174- | |||
197 000000B2 6520312B322B2E2E2E- | |||
198 000000BB 2B313030303A0D0A0D- | |||
199 000000C4 0A | |||
200 000000C5 2020202020786F7220- db ' xor dx,dx',0x0d,0x0a | |||
201 000000CE 64782C64780D0A | |||
202 000000D5 2020202020786F7220- db ' xor ax,ax',0x0d,0x0a | |||
203 000000DE 61782C61780D0A | |||
204 000000E5 2020202020786F7220- db ' xor cx,cx',0x0d,0x0a | |||
205 000000EE 63782C63780D0A | |||
206 000000F5 202040403A0D0A db ' @@:',0x0d,0x0a | |||
207 000000FC 2020202020696E6320- db ' inc cx',0x0d,0x0a | |||
208 00000105 63780D0A | |||
209 00000109 202020202061646420- db ' add ax,cx',0x0d,0x0a | |||
210 00000112 61782C63780D0A | |||
211 00000119 202020202061646320- db ' adc dx,0',0x0d,0x0a | |||
212 00000122 64782C300D0A | |||
213 00000128 2020202020696E6320- db ' inc cx',0x0d,0x0a | |||
214 00000131 63780D0A | |||
215 00000135 2020202020636D7020- db ' cmp cx,1000',0x0d,0x0a | |||
216 0000013E 63782C313030300D0A | |||
217 00000147 20202020206A6C6520- db ' jle @@',0x0d,0x0a | |||
218 00000150 40400D0A | |||
219 00000154 20202020202E2E2E20- db ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a | |||
220 0000015D 2E2E2E28536F6D6520- | |||
221 00000166 6F7468657220636F64- | |||
222 0000016F 6573290D0A0D0A | |||
223 00000176 00 db 0 | |||
224 | |||
225 ;=============================================================================== | |||
226 SECTION data_2 align=16 vstart=0 | |||
227 | |||
228 00000000 20205468652061626F- msg1 db ' The above contents is written by LeeChung. ' | |||
229 00000009 766520636F6E74656E- | |||
230 00000012 747320697320777269- | |||
231 0000001B 7474656E206279204C- | |||
232 00000024 65654368756E672E20 | |||
233 0000002D 323031312D30352D30- db '2011-05-06' | |||
234 00000036 36 | |||
235 00000037 00 db 0 | |||
236 | |||
237 ;=============================================================================== | |||
238 SECTION stack align=16 vstart=0 | |||
239 | |||
240 00000000 <res 00000100> resb 256 | |||
241 ****************** warning: uninitialized space declared in stack section: zeroing | |||
242 | |||
243 stack_end: | |||
244 | |||
245 ;=============================================================================== | |||
246 SECTION trail align=16 | |||
247 program_end: |
@@ -0,0 +1,154 @@ | |||
;代码清单8-1 | |||
;文件名:c08_mbr.asm | |||
;文件说明:硬盘主引导扇区代码(加载程序) | |||
;创建日期:2011-5-5 18:17 | |||
app_lba_start equ 1 ;声明常数(用户程序起始逻辑扇区号) | |||
;常数的声明不会占用汇编地址 | |||
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 | |||
mov si,app_lba_start ;程序在硬盘上的起始逻辑扇区号 | |||
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 | |||
mov al,1 | |||
out dx,al ;读取的扇区数 | |||
inc dx ;0x1f3 | |||
mov ax,si ; read sector 1 | |||
out dx,al ;LBA地址7~0 | |||
inc dx ;0x1f4 | |||
mov al,0 ; 0, since lower 8bit is enough for sector 1 | |||
out dx,al ;LBA地址15~8 | |||
inc dx ;0x1f5 | |||
mov ax,0 ; 0, since lower 8bit is enough for sector 1 | |||
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 |
@@ -0,0 +1,154 @@ | |||
1 ;代码清单8-1 | |||
2 ;文件名:c08_mbr.asm | |||
3 ;文件说明:硬盘主引导扇区代码(加载程序) | |||
4 ;创建日期:2011-5-5 18:17 | |||
5 | |||
6 app_lba_start equ 1 ;声明常数(用户程序起始逻辑扇区号) | |||
7 ;常数的声明不会占用汇编地址 | |||
8 | |||
9 SECTION mbr align=16 vstart=0x7c00 | |||
10 | |||
11 ;设置堆栈段和栈指针 | |||
12 00000000 B80000 mov ax,0 | |||
13 00000003 8ED0 mov ss,ax | |||
14 00000005 89C4 mov sp,ax | |||
15 | |||
16 00000007 2EA1[C800] mov ax,[cs:phy_base] ;计算用于加载用户程序的逻辑段地址 | |||
17 0000000B 2E8B16[CA00] mov dx,[cs:phy_base+0x02] | |||
18 00000010 BB1000 mov bx,16 | |||
19 00000013 F7F3 div bx | |||
20 00000015 8ED8 mov ds,ax ;令DS和ES指向该段以进行操作 | |||
21 00000017 8EC0 mov es,ax | |||
22 | |||
23 ;以下读取程序的起始部分 | |||
24 00000019 31FF xor di,di | |||
25 0000001B BE0100 mov si,app_lba_start ;程序在硬盘上的起始逻辑扇区号 | |||
26 0000001E 31DB xor bx,bx ;加载到DS:0x0000处 | |||
27 00000020 E85100 call read_hard_disk_0 | |||
28 | |||
29 ;以下判断整个程序有多大 | |||
30 00000023 8B160200 mov dx,[2] ;曾经把dx写成了ds,花了二十分钟排错 | |||
31 00000027 A10000 mov ax,[0] | |||
32 0000002A BB0002 mov bx,512 ;512字节每扇区 | |||
33 0000002D F7F3 div bx | |||
34 0000002F 83FA00 cmp dx,0 | |||
35 00000032 7501 jnz @1 ;未除尽,因此结果比实际扇区数少1 | |||
36 00000034 48 dec ax ;已经读了一个扇区,扇区总数减1 | |||
37 @1: | |||
38 00000035 83F800 cmp ax,0 ;考虑实际长度小于等于512个字节的情况 | |||
39 00000038 7413 jz direct | |||
40 | |||
41 ;读取剩余的扇区 | |||
42 0000003A 1E push ds ;以下要用到并改变DS寄存器 | |||
43 | |||
44 0000003B 89C1 mov cx,ax ;循环次数(剩余扇区数) | |||
45 @2: | |||
46 0000003D 8CD8 mov ax,ds | |||
47 0000003F 83C020 add ax,0x20 ;得到下一个以512字节为边界的段地址 | |||
48 00000042 8ED8 mov ds,ax | |||
49 | |||
50 00000044 31DB xor bx,bx ;每次读时,偏移地址始终为0x0000 | |||
51 00000046 46 inc si ;下一个逻辑扇区 | |||
52 00000047 E82A00 call read_hard_disk_0 | |||
53 0000004A E2F1 loop @2 ;循环读,直到读完整个功能程序 | |||
54 | |||
55 0000004C 1F pop ds ;恢复数据段基址到用户程序头部段 | |||
56 | |||
57 ;计算入口点代码段基址 | |||
58 direct: | |||
59 0000004D 8B160800 mov dx,[0x08] | |||
60 00000051 A10600 mov ax,[0x06] | |||
61 00000054 E85800 call calc_segment_base | |||
62 00000057 A30600 mov [0x06],ax ;回填修正后的入口点代码段基址 | |||
63 | |||
64 ;开始处理段重定位表 | |||
65 0000005A 8B0E0A00 mov cx,[0x0a] ;需要重定位的项目数量 | |||
66 0000005E BB0C00 mov bx,0x0c ;重定位表首地址 | |||
67 | |||
68 realloc: | |||
69 00000061 8B5702 mov dx,[bx+0x02] ;32位地址的高16位 | |||
70 00000064 8B07 mov ax,[bx] | |||
71 00000066 E84600 call calc_segment_base | |||
72 00000069 8907 mov [bx],ax ;回填段的基址 | |||
73 0000006B 83C304 add bx,4 ;下一个重定位项(每项占4个字节) | |||
74 0000006E E2F1 loop realloc | |||
75 | |||
76 00000070 FF2E0400 jmp far [0x04] ;转移到用户程序 | |||
77 | |||
78 ;------------------------------------------------------------------------------- | |||
79 read_hard_disk_0: ;从硬盘读取一个逻辑扇区 | |||
80 ;输入:DI:SI=起始逻辑扇区号 | |||
81 ; DS:BX=目标缓冲区地址 | |||
82 00000074 50 push ax | |||
83 00000075 53 push bx | |||
84 00000076 51 push cx | |||
85 00000077 52 push dx | |||
86 | |||
87 00000078 BAF201 mov dx,0x1f2 | |||
88 0000007B B001 mov al,1 | |||
89 0000007D EE out dx,al ;读取的扇区数 | |||
90 | |||
91 0000007E 42 inc dx ;0x1f3 | |||
92 0000007F 89F0 mov ax,si ; read sector 100 | |||
93 00000081 EE out dx,al ;LBA地址7~0 | |||
94 | |||
95 00000082 42 inc dx ;0x1f4 | |||
96 00000083 B000 mov al,0 ; 0, since lower 8bit is enough for sector 100 | |||
97 00000085 EE out dx,al ;LBA地址15~8 | |||
98 | |||
99 00000086 42 inc dx ;0x1f5 | |||
100 00000087 B80000 mov ax,0 ; 0, since lower 8bit is enough for sector 100 | |||
101 0000008A EE out dx,al ;LBA地址23~16 | |||
102 | |||
103 0000008B 42 inc dx ;0x1f6 | |||
104 0000008C B0E0 mov al,0xe0 ;LBA28模式,主盘 | |||
105 0000008E 08E0 or al,ah ;LBA地址27~24 | |||
106 00000090 EE out dx,al | |||
107 | |||
108 00000091 42 inc dx ;0x1f7 | |||
109 00000092 B020 mov al,0x20 ;读命令 | |||
110 00000094 EE out dx,al | |||
111 | |||
112 .waits: | |||
113 00000095 EC in al,dx | |||
114 00000096 2488 and al,0x88 | |||
115 00000098 3C08 cmp al,0x08 | |||
116 0000009A 75F9 jnz .waits ;不忙,且硬盘已准备好数据传输 | |||
117 | |||
118 0000009C B90001 mov cx,256 ;总共要读取的字数 | |||
119 0000009F BAF001 mov dx,0x1f0 | |||
120 .readw: | |||
121 000000A2 ED in ax,dx | |||
122 000000A3 8907 mov [bx],ax | |||
123 000000A5 83C302 add bx,2 | |||
124 000000A8 E2F8 loop .readw | |||
125 | |||
126 000000AA 5A pop dx | |||
127 000000AB 59 pop cx | |||
128 000000AC 5B pop bx | |||
129 000000AD 58 pop ax | |||
130 | |||
131 000000AE C3 ret | |||
132 | |||
133 ;------------------------------------------------------------------------------- | |||
134 calc_segment_base: ;计算16位段地址 | |||
135 ;输入:DX:AX=32位物理地址 | |||
136 ;返回:AX=16位段基地址 | |||
137 000000AF 52 push dx | |||
138 | |||
139 000000B0 2E0306[C800] add ax,[cs:phy_base] | |||
140 000000B5 2E1316[CA00] adc dx,[cs:phy_base+0x02] | |||
141 000000BA C1E804 shr ax,4 | |||
142 000000BD C1CA04 ror dx,4 | |||
143 000000C0 81E200F0 and dx,0xf000 | |||
144 000000C4 09D0 or ax,dx | |||
145 | |||
146 000000C6 5A pop dx | |||
147 | |||
148 000000C7 C3 ret | |||
149 | |||
150 ;------------------------------------------------------------------------------- | |||
151 000000C8 00000100 phy_base dd 0x10000 ;用户程序被加载的物理起始地址 | |||
152 | |||
153 000000CC 00<rep 132h> times 510-($-$$) db 0 | |||
154 000001FE 55AA db 0x55,0xaa |
@@ -0,0 +1,304 @@ | |||
;代码清单9-1 | |||
;文件名:c09_1.asm | |||
;文件说明:用户程序 | |||
;创建日期:2011-4-16 22:03 | |||
;=============================================================================== | |||
SECTION header vstart=0 ;定义用户程序头部段 | |||
program_length dd program_end ;程序总长度[0x00] | |||
;用户程序入口点 | |||
code_entry dw start ;偏移地址[0x04] | |||
dd section.code.start ;段地址[0x06] | |||
realloc_tbl_len dw (header_end-realloc_begin)/4 | |||
;段重定位表项个数[0x0a] | |||
realloc_begin: | |||
;段重定位表 | |||
code_segment dd section.code.start ;[0x0c] | |||
data_segment dd section.data.start ;[0x14] | |||
stack_segment dd section.stack.start ;[0x1c] | |||
header_end: | |||
;=============================================================================== | |||
SECTION code align=16 vstart=0 ;定义代码段(16字节对齐) | |||
new_int_0x70: | |||
push ax | |||
push bx | |||
push cx | |||
push dx | |||
push es | |||
.w0: | |||
mov al,0x0a ;阻断NMI。当然,通常是不必要的 | |||
or al,0x80 | |||
out 0x70,al | |||
in al,0x71 ;读寄存器A | |||
test al,0x80 ;测试第7位UIP | |||
jnz .w0 ;以上代码对于更新周期结束中断来说 | |||
;是不必要的 | |||
xor al,al | |||
or al,0x80 | |||
out 0x70,al | |||
in al,0x71 ;读RTC当前时间(秒) | |||
push ax | |||
mov al,2 | |||
or al,0x80 | |||
out 0x70,al | |||
in al,0x71 ;读RTC当前时间(分) | |||
push ax | |||
mov al,4 | |||
or al,0x80 | |||
out 0x70,al | |||
in al,0x71 ;读RTC当前时间(时) | |||
push ax | |||
mov al,0x0c ;寄存器C的索引。且开放NMI | |||
out 0x70,al | |||
in al,0x71 ;读一下RTC的寄存器C,否则只发生一次中断 | |||
;此处不考虑闹钟和周期性中断的情况 | |||
mov ax,0xb800 | |||
mov es,ax | |||
pop ax | |||
call bcd_to_ascii | |||
mov bx,12*160 + 36*2 ;从屏幕上的12行36列开始显示 | |||
mov [es:bx],ah | |||
mov [es:bx+2],al ;显示两位小时数字 | |||
mov al,':' | |||
mov [es:bx+4],al ;显示分隔符':' | |||
not byte [es:bx+5] ;反转显示属性 | |||
pop ax | |||
call bcd_to_ascii | |||
mov [es:bx+6],ah | |||
mov [es:bx+8],al ;显示两位分钟数字 | |||
mov al,':' | |||
mov [es:bx+10],al ;显示分隔符':' | |||
not byte [es:bx+11] ;反转显示属性 | |||
pop ax | |||
call bcd_to_ascii | |||
mov [es:bx+12],ah | |||
mov [es:bx+14],al ;显示两位小时数字 | |||
mov al,0x20 ;中断结束命令EOI | |||
out 0xa0,al ;向从片发送 | |||
out 0x20,al ;向主片发送 | |||
pop es | |||
pop dx | |||
pop cx | |||
pop bx | |||
pop ax | |||
iret | |||
;------------------------------------------------------------------------------- | |||
bcd_to_ascii: ;BCD码转ASCII | |||
;输入:AL=bcd码 | |||
;输出:AX=ascii | |||
mov ah,al ;分拆成两个数字 | |||
and al,0x0f ;仅保留低4位 | |||
add al,0x30 ;转换成ASCII | |||
shr ah,4 ;逻辑右移4位 | |||
and ah,0x0f | |||
add ah,0x30 | |||
ret | |||
;------------------------------------------------------------------------------- | |||
start: | |||
mov ax,[stack_segment] | |||
mov ss,ax | |||
mov sp,ss_pointer | |||
mov ax,[data_segment] | |||
mov ds,ax | |||
mov bx,init_msg ;显示初始信息 | |||
call put_string | |||
mov bx,inst_msg ;显示安装信息 | |||
call put_string | |||
mov al,0x70 | |||
mov bl,4 | |||
mul bl ;计算0x70号中断在IVT中的偏移 | |||
mov bx,ax | |||
cli ;防止改动期间发生新的0x70号中断 | |||
push es | |||
mov ax,0x0000 | |||
mov es,ax | |||
mov word [es:bx],new_int_0x70 ;偏移地址。 | |||
mov word [es:bx+2],cs ;段地址 | |||
pop es | |||
mov al,0x0b ;RTC寄存器B | |||
or al,0x80 ;阻断NMI | |||
out 0x70,al | |||
mov al,0x12 ;设置寄存器B,禁止周期性中断,开放更 | |||
out 0x71,al ;新结束后中断,BCD码,24小时制 | |||
mov al,0x0c | |||
out 0x70,al | |||
in al,0x71 ;读RTC寄存器C,复位未决的中断状态 | |||
in al,0xa1 ;读8259从片的IMR寄存器 | |||
and al,0xfe ;清除bit 0(此位连接RTC) | |||
out 0xa1,al ;写回此寄存器 | |||
sti ;重新开放中断 | |||
mov bx,done_msg ;显示安装完成信息 | |||
call put_string | |||
mov bx,tips_msg ;显示提示信息 | |||
call put_string | |||
mov cx,0xb800 | |||
mov ds,cx | |||
mov byte [12*160 + 33*2],'@' ;屏幕第12行,35列 | |||
.idle: | |||
hlt ;使CPU进入低功耗状态,直到用中断唤醒 | |||
not byte [12*160 + 33*2+1] ;反转显示属性 | |||
jmp .idle | |||
;------------------------------------------------------------------------------- | |||
put_string: ;显示串(0结尾)。 | |||
;输入:DS:BX=串地址 | |||
mov cl,[bx] | |||
or cl,cl ;cl=0 ? | |||
jz .exit ;是的,返回主程序 | |||
call put_char | |||
inc bx ;下一个字符 | |||
jmp put_string | |||
.exit: | |||
ret | |||
;------------------------------------------------------------------------------- | |||
put_char: ;显示一个字符 | |||
;输入:cl=字符ascii | |||
push ax | |||
push bx | |||
push cx | |||
push dx | |||
push ds | |||
push es | |||
;以下取当前光标位置 | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
mov dx,0x3d5 | |||
in al,dx ;高8位 | |||
mov ah,al | |||
mov dx,0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
mov dx,0x3d5 | |||
in al,dx ;低8位 | |||
mov bx,ax ;BX=代表光标位置的16位数 | |||
cmp cl,0x0d ;回车符? | |||
jnz .put_0a ;不是。看看是不是换行等字符 | |||
mov ax,bx ; | |||
mov bl,80 | |||
div bl | |||
mul bl | |||
mov bx,ax | |||
jmp .set_cursor | |||
.put_0a: | |||
cmp cl,0x0a ;换行符? | |||
jnz .put_other ;不是,那就正常显示字符 | |||
add bx,80 | |||
jmp .roll_screen | |||
.put_other: ;正常显示字符 | |||
mov ax,0xb800 | |||
mov es,ax | |||
shl bx,1 | |||
mov [es:bx],cl | |||
;以下将光标位置推进一个字符 | |||
shr bx,1 | |||
add bx,1 | |||
.roll_screen: | |||
cmp bx,2000 ;光标超出屏幕?滚屏 | |||
jl .set_cursor | |||
mov ax,0xb800 | |||
mov ds,ax | |||
mov es,ax | |||
cld | |||
mov si,0xa0 | |||
mov di,0x00 | |||
mov cx,1920 | |||
rep movsw | |||
mov bx,3840 ;清除屏幕最底一行 | |||
mov cx,80 | |||
.cls: | |||
mov word[es:bx],0x0720 | |||
add bx,2 | |||
loop .cls | |||
mov bx,1920 | |||
.set_cursor: | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
mov dx,0x3d5 | |||
mov al,bh | |||
out dx,al | |||
mov dx,0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
mov dx,0x3d5 | |||
mov al,bl | |||
out dx,al | |||
pop es | |||
pop ds | |||
pop dx | |||
pop cx | |||
pop bx | |||
pop ax | |||
ret | |||
;=============================================================================== | |||
SECTION data align=16 vstart=0 | |||
init_msg db 'Starting...',0x0d,0x0a,0 | |||
inst_msg db 'Installing a new interrupt 70H...',0 | |||
done_msg db 'Done.',0x0d,0x0a,0 | |||
tips_msg db 'Clock is now working.',0 | |||
;=============================================================================== | |||
SECTION stack align=16 vstart=0 | |||
resb 256 | |||
ss_pointer: | |||
;=============================================================================== | |||
SECTION program_trail | |||
program_end: |
@@ -0,0 +1,71 @@ | |||
;代码清单9-2 | |||
;文件名:c09_2.asm | |||
;文件说明:用于演示BIOS中断的用户程序 | |||
;创建日期:2012-3-28 20:35 | |||
;=============================================================================== | |||
SECTION header vstart=0 ;定义用户程序头部段 | |||
program_length dd program_end ;程序总长度[0x00] | |||
;用户程序入口点 | |||
code_entry dw start ;偏移地址[0x04] | |||
dd section.code.start ;段地址[0x06] | |||
realloc_tbl_len dw (header_end-realloc_begin)/4 | |||
;段重定位表项个数[0x0a] | |||
realloc_begin: | |||
;段重定位表 | |||
code_segment dd section.code.start ;[0x0c] | |||
data_segment dd section.data.start ;[0x14] | |||
stack_segment dd section.stack.start ;[0x1c] | |||
header_end: | |||
;=============================================================================== | |||
SECTION code align=16 vstart=0 ;定义代码段(16字节对齐) | |||
start: | |||
mov ax,[stack_segment] | |||
mov ss,ax | |||
mov sp,ss_pointer | |||
mov ax,[data_segment] | |||
mov ds,ax | |||
mov cx,msg_end-message | |||
mov bx,message | |||
.putc: | |||
mov ah,0x0e | |||
mov al,[bx] | |||
int 0x10 | |||
inc bx | |||
loop .putc | |||
.reps: | |||
mov ah,0x00 | |||
int 0x16 | |||
mov ah,0x0e | |||
mov bl,0x07 | |||
int 0x10 | |||
jmp .reps | |||
;=============================================================================== | |||
SECTION data align=16 vstart=0 | |||
message db 'Hello, friend!',0x0d,0x0a | |||
db 'This simple procedure used to demonstrate ' | |||
db 'the BIOS interrupt.',0x0d,0x0a | |||
db 'Please press the keys on the keyboard ->' | |||
msg_end: | |||
;=============================================================================== | |||
SECTION stack align=16 vstart=0 | |||
resb 256 | |||
ss_pointer: | |||
;=============================================================================== | |||
SECTION program_trail | |||
program_end: |
@@ -0,0 +1,99 @@ | |||
;代码清单11-1 | |||
;文件名:c11_mbr.asm | |||
;文件说明:硬盘主引导扇区代码 | |||
;创建日期:2011-5-16 19:54 | |||
;设置堆栈段和栈指针 | |||
mov ax,cs | |||
mov ss,ax | |||
mov sp,0x7c00 | |||
;计算GDT所在的逻辑段地址 | |||
mov ax,[cs:gdt_base+0x7c00] ;低16位 | |||
mov dx,[cs:gdt_base+0x7c00+0x02] ;高16位 | |||
mov bx,16 | |||
div bx | |||
mov ds,ax ;令DS指向该段以进行操作 | |||
mov bx,dx ;段内起始偏移地址 | |||
;创建0#描述符,它是空描述符,这是处理器的要求 | |||
mov dword [bx+0x00],0x00 | |||
mov dword [bx+0x04],0x00 | |||
;创建#1描述符,保护模式下的代码段描述符 | |||
mov dword [bx+0x08],0x7c0001ff | |||
mov dword [bx+0x0c],0x00409800 | |||
;创建#2描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区) | |||
mov dword [bx+0x10],0x8000ffff | |||
mov dword [bx+0x14],0x0040920b | |||
;创建#3描述符,保护模式下的堆栈段描述符 | |||
mov dword [bx+0x18],0x00007a00 | |||
mov dword [bx+0x1c],0x00409600 | |||
;初始化描述符表寄存器GDTR | |||
mov word [cs: gdt_size+0x7c00],31 ;描述符表的界限(总字节数减一) | |||
lgdt [cs: gdt_size+0x7c00] | |||
in al,0x92 ;南桥芯片内的端口 | |||
or al,0000_0010B | |||
out 0x92,al ;打开A20 | |||
cli ;保护模式下中断机制尚未建立,应 | |||
;禁止中断 | |||
mov eax,cr0 | |||
or eax,1 | |||
mov cr0,eax ;设置PE位 | |||
;以下进入保护模式... ... | |||
jmp dword 0x0008:flush ;16位的描述符选择子:32位偏移 | |||
;清流水线并串行化处理器 | |||
[bits 32] | |||
flush: | |||
mov cx,00000000000_10_000B ;加载数据段选择子(0x10) | |||
mov ds,cx | |||
;以下在屏幕上显示"Protect mode OK." | |||
mov byte [0x00],'P' | |||
mov byte [0x02],'r' | |||
mov byte [0x04],'o' | |||
mov byte [0x06],'t' | |||
mov byte [0x08],'e' | |||
mov byte [0x0a],'c' | |||
mov byte [0x0c],'t' | |||
mov byte [0x0e],' ' | |||
mov byte [0x10],'m' | |||
mov byte [0x12],'o' | |||
mov byte [0x14],'d' | |||
mov byte [0x16],'e' | |||
mov byte [0x18],' ' | |||
mov byte [0x1a],'O' | |||
mov byte [0x1c],'K' | |||
;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 | |||
mov cx,00000000000_11_000B ;加载堆栈段选择子 | |||
mov ss,cx | |||
mov esp,0x7c00 | |||
mov ebp,esp ;保存堆栈指针 | |||
push byte '.' ;压入立即数(字节) | |||
sub ebp,4 | |||
cmp ebp,esp ;判断压入立即数时,ESP是否减4 | |||
jnz ghalt | |||
pop eax | |||
mov [0x1e],al ;显示句点 | |||
ghalt: | |||
hlt ;已经禁止中断,将不会被唤醒 | |||
;------------------------------------------------------------------------------- | |||
gdt_size dw 0 | |||
gdt_base dd 0x00007e00 ;GDT的物理地址 | |||
times 510-($-$$) db 0 | |||
db 0x55,0xaa |
@@ -0,0 +1,111 @@ | |||
;代码清单12-1 | |||
;文件名:c12_mbr.asm | |||
;文件说明:硬盘主引导扇区代码 | |||
;创建日期:2011-10-27 22:52 | |||
;设置堆栈段和栈指针 | |||
mov eax,cs | |||
mov ss,eax | |||
mov sp,0x7c00 | |||
;计算GDT所在的逻辑段地址 | |||
mov eax,[cs:pgdt+0x7c00+0x02] ;GDT的32位线性基地址 | |||
xor edx,edx | |||
mov ebx,16 | |||
div ebx ;分解成16位逻辑地址 | |||
mov ds,eax ;令DS指向该段以进行操作 | |||
mov ebx,edx ;段内起始偏移地址 | |||
;创建0#描述符,它是空描述符,这是处理器的要求 | |||
mov dword [ebx+0x00],0x00000000 | |||
mov dword [ebx+0x04],0x00000000 | |||
;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 | |||
mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xfffff | |||
mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 | |||
;创建保护模式下初始代码段描述符 | |||
mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,512字节 | |||
mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 | |||
;创建以上代码段的别名描述符 | |||
mov dword [ebx+0x18],0x7c0001ff ;基地址为0x00007c00,512字节 | |||
mov dword [ebx+0x1c],0x00409200 ;粒度为1个字节,数据段描述符 | |||
mov dword [ebx+0x20],0x7c00fffe | |||
mov dword [ebx+0x24],0x00cf9600 | |||
;初始化描述符表寄存器GDTR | |||
mov word [cs: pgdt+0x7c00],39 ;描述符表的界限 | |||
lgdt [cs: pgdt+0x7c00] | |||
in al,0x92 ;南桥芯片内的端口 | |||
or al,0000_0010B | |||
out 0x92,al ;打开A20 | |||
cli ;中断机制尚未工作 | |||
mov eax,cr0 | |||
or eax,1 | |||
mov cr0,eax ;设置PE位 | |||
;以下进入保护模式... ... | |||
jmp dword 0x0010:flush ;16位的描述符选择子:32位偏移 | |||
[bits 32] | |||
flush: | |||
mov eax,0x0018 | |||
mov ds,eax | |||
mov eax,0x0008 ;加载数据段(0..4GB)选择子 | |||
mov es,eax | |||
mov fs,eax | |||
mov gs,eax | |||
mov eax,0x0020 ;0000 0000 0010 0000 | |||
mov ss,eax | |||
xor esp,esp ;ESP <- 0 | |||
mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性 | |||
mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性 | |||
mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性 | |||
mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性 | |||
;开始冒泡排序 | |||
mov ecx,pgdt-string-1 ;遍历次数=串长度-1 | |||
@@1: | |||
push ecx ;32位模式下的loop使用ecx | |||
xor bx,bx ;32位模式下,偏移量可以是16位,也可以 | |||
@@2: ;是后面的32位 | |||
mov ax,[string+bx] | |||
cmp ah,al ;ah中存放的是源字的高字节 | |||
jge @@3 | |||
xchg al,ah | |||
mov [string+bx],ax | |||
@@3: | |||
inc bx | |||
loop @@2 | |||
pop ecx | |||
loop @@1 | |||
mov ecx,pgdt-string | |||
xor ebx,ebx ;偏移地址是32位的情况 | |||
@@4: ;32位的偏移具有更大的灵活性 | |||
mov ah,0x07 | |||
mov al,[string+ebx] | |||
mov [es:0xb80a0+ebx*2],ax ;演示0~4GB寻址。 | |||
inc ebx | |||
loop @@4 | |||
hlt | |||
;------------------------------------------------------------------------------- | |||
string db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.' | |||
;------------------------------------------------------------------------------- | |||
pgdt dw 0 | |||
dd 0x00007e00 ;GDT的物理地址 | |||
;------------------------------------------------------------------------------- | |||
times 510-($-$$) db 0 | |||
db 0x55,0xaa |
@@ -0,0 +1,87 @@ | |||
;代码清单13-3 | |||
;文件名:c13.asm | |||
;文件说明:用户程序 | |||
;创建日期:2011-10-30 15:19 | |||
;=============================================================================== | |||
SECTION header vstart=0 | |||
program_length dd program_end ;程序总长度#0x00 | |||
head_len dd header_end ;程序头部的长度#0x04 | |||
stack_seg dd 0 ;用于接收堆栈段选择子#0x08 | |||
stack_len dd 1 ;程序建议的堆栈大小#0x0c | |||
;以4KB为单位 | |||
prgentry dd start ;程序入口#0x10 | |||
code_seg dd section.code.start ;代码段位置#0x14 | |||
code_len dd code_end ;代码段长度#0x18 | |||
data_seg dd section.data.start ;数据段位置#0x1c | |||
data_len dd data_end ;数据段长度#0x20 | |||
;------------------------------------------------------------------------------- | |||
;符号地址检索表 | |||
salt_items dd (header_end-salt)/256 ;#0x24 | |||
salt: ;#0x28 | |||
PrintString db '@PrintString' | |||
times 256-($-PrintString) db 0 | |||
TerminateProgram db '@TerminateProgram' | |||
times 256-($-TerminateProgram) db 0 | |||
ReadDiskData db '@ReadDiskData' | |||
times 256-($-ReadDiskData) db 0 | |||
header_end: | |||
;=============================================================================== | |||
SECTION data vstart=0 | |||
buffer times 1024 db 0 ;缓冲区 | |||
message_1 db 0x0d,0x0a,0x0d,0x0a | |||
db '**********User program is runing**********' | |||
db 0x0d,0x0a,0 | |||
message_2 db ' Disk data:',0x0d,0x0a,0 | |||
data_end: | |||
;=============================================================================== | |||
[bits 32] | |||
;=============================================================================== | |||
SECTION code vstart=0 | |||
start: | |||
mov eax,ds | |||
mov fs,eax | |||
mov eax,[stack_seg] | |||
mov ss,eax | |||
mov esp,0 | |||
mov eax,[data_seg] | |||
mov ds,eax | |||
mov ebx,message_1 | |||
call far [fs:PrintString] | |||
mov eax,100 ;逻辑扇区号100 | |||
mov ebx,buffer ;缓冲区偏移地址 | |||
call far [fs:ReadDiskData] ;段间调用 | |||
mov ebx,message_2 | |||
call far [fs:PrintString] | |||
mov ebx,buffer | |||
call far [fs:PrintString] ;too. | |||
jmp far [fs:TerminateProgram] ;将控制权返回到系统 | |||
code_end: | |||
;=============================================================================== | |||
SECTION trail | |||
;------------------------------------------------------------------------------- | |||
program_end: |
@@ -0,0 +1,95 @@ | |||
1 ;代码清单13-3 | |||
2 ;文件名:c13.asm | |||
3 ;文件说明:用户程序 | |||
4 ;创建日期:2011-10-30 15:19 | |||
5 | |||
6 ;=============================================================================== | |||
7 SECTION header vstart=0 | |||
8 | |||
9 00000000 [00000000] program_length dd program_end ;程序总长度#0x00 | |||
10 | |||
11 00000004 [28030000] head_len dd header_end ;程序头部的长度#0x04 | |||
12 | |||
13 00000008 00000000 stack_seg dd 0 ;用于接收堆栈段选择子#0x08 | |||
14 0000000C 01000000 stack_len dd 1 ;程序建议的堆栈大小#0x0c | |||
15 ;以4KB为单位 | |||
16 | |||
17 00000010 [00000000] prgentry dd start ;程序入口#0x10 | |||
18 00000014 [00000000] code_seg dd section.code.start ;代码段位置#0x14 | |||
19 00000018 [53000000] code_len dd code_end ;代码段长度#0x18 | |||
20 | |||
21 0000001C [00000000] data_seg dd section.data.start ;数据段位置#0x1c | |||
22 00000020 [40040000] data_len dd data_end ;数据段长度#0x20 | |||
23 | |||
24 ;------------------------------------------------------------------------------- | |||
25 ;符号地址检索表 | |||
26 00000024 03000000 salt_items dd (header_end-salt)/256 ;#0x24 | |||
27 | |||
28 salt: ;#0x28 | |||
29 00000028 405072696E74537472- PrintString db '@PrintString' | |||
30 00000031 696E67 | |||
31 00000034 00<rept> times 256-($-PrintString) db 0 | |||
32 | |||
33 00000128 405465726D696E6174- TerminateProgram db '@TerminateProgram' | |||
34 00000131 6550726F6772616D | |||
35 00000139 00<rept> times 256-($-TerminateProgram) db 0 | |||
36 | |||
37 00000228 40526561644469736B- ReadDiskData db '@ReadDiskData' | |||
38 00000231 44617461 | |||
39 00000235 00<rept> times 256-($-ReadDiskData) db 0 | |||
40 | |||
41 header_end: | |||
42 | |||
43 ;=============================================================================== | |||
44 SECTION data vstart=0 | |||
45 | |||
46 00000000 00<rept> buffer times 1024 db 0 ;缓冲区 | |||
47 | |||
48 00000400 0D0A0D0A message_1 db 0x0d,0x0a,0x0d,0x0a | |||
49 00000404 2A2A2A2A2A2A2A2A2A- db '**********User program is runing**********' | |||
50 0000040D 2A557365722070726F- | |||
51 00000416 6772616D2069732072- | |||
52 0000041F 756E696E672A2A2A2A- | |||
53 00000428 2A2A2A2A2A2A | |||
54 0000042E 0D0A00 db 0x0d,0x0a,0 | |||
55 00000431 20204469736B206461- message_2 db ' Disk data:',0x0d,0x0a,0 | |||
56 0000043A 74613A0D0A00 | |||
57 | |||
58 data_end: | |||
59 | |||
60 ;=============================================================================== | |||
61 [bits 32] | |||
62 ;=============================================================================== | |||
63 SECTION code vstart=0 | |||
64 start: | |||
65 00000000 8CD8 mov eax,ds | |||
66 00000002 8EE0 mov fs,eax | |||
67 | |||
68 00000004 A1[08000000] mov eax,[stack_seg] | |||
69 00000009 8ED0 mov ss,eax | |||
70 0000000B BC00000000 mov esp,0 | |||
71 | |||
72 00000010 A1[1C000000] mov eax,[data_seg] | |||
73 00000015 8ED8 mov ds,eax | |||
74 | |||
75 00000017 BB[00040000] mov ebx,message_1 | |||
76 0000001C 64FF1D[28000000] call far [fs:PrintString] | |||
77 | |||
78 00000023 B864000000 mov eax,100 ;逻辑扇区号100 | |||
79 00000028 BB[00000000] mov ebx,buffer ;缓冲区偏移地址 | |||
80 0000002D 64FF1D[28020000] call far [fs:ReadDiskData] ;段间调用 | |||
81 | |||
82 00000034 BB[31040000] mov ebx,message_2 | |||
83 00000039 64FF1D[28000000] call far [fs:PrintString] | |||
84 | |||
85 00000040 BB[00000000] mov ebx,buffer | |||
86 00000045 64FF1D[28000000] call far [fs:PrintString] ;too. | |||
87 | |||
88 0000004C 64FF2D[28010000] jmp far [fs:TerminateProgram] ;将控制权返回到系统 | |||
89 | |||
90 code_end: | |||
91 | |||
92 ;=============================================================================== | |||
93 SECTION trail | |||
94 ;------------------------------------------------------------------------------- | |||
95 program_end: |
@@ -0,0 +1,601 @@ | |||
;代码清单13-2 | |||
;文件名:c13_core.asm | |||
;文件说明:保护模式微型核心程序 | |||
;创建日期:2011-10-26 12:11 | |||
;以下常量定义部分。内核的大部分内容都应当固定 | |||
core_code_seg_sel equ 0x38 ;内核代码段选择子 | |||
core_data_seg_sel equ 0x30 ;内核数据段选择子 | |||
sys_routine_seg_sel equ 0x28 ;系统公共例程代码段的选择子 | |||
video_ram_seg_sel equ 0x20 ;视频显示缓冲区的段选择子 | |||
core_stack_seg_sel equ 0x18 ;内核堆栈段选择子 | |||
mem_0_4_gb_seg_sel equ 0x08 ;整个0-4GB内存的段的选择子 | |||
;------------------------------------------------------------------------------- | |||
;以下是系统核心的头部,用于加载核心程序 | |||
core_length dd core_end ;核心程序总长度#00 | |||
sys_routine_seg dd section.sys_routine.start | |||
;系统公用例程段位置#04 | |||
core_data_seg dd section.core_data.start | |||
;核心数据段位置#08 | |||
core_code_seg dd section.core_code.start | |||
;核心代码段位置#0c | |||
core_entry dd start ;核心代码段入口点#10 | |||
dw core_code_seg_sel | |||
;=============================================================================== | |||
[bits 32] | |||
;=============================================================================== | |||
SECTION sys_routine vstart=0 ;系统公共例程代码段 | |||
;------------------------------------------------------------------------------- | |||
;字符串显示例程 | |||
put_string: ;显示0终止的字符串并移动光标 | |||
;输入:DS:EBX=串地址 | |||
push ecx | |||
.getc: | |||
mov cl,[ebx] | |||
or cl,cl | |||
jz .exit | |||
call put_char | |||
inc ebx | |||
jmp .getc | |||
.exit: | |||
pop ecx | |||
retf ;段间返回 | |||
;------------------------------------------------------------------------------- | |||
put_char: ;在当前光标处显示一个字符,并推进 | |||
;光标。仅用于段内调用 | |||
;输入:CL=字符ASCII码 | |||
pushad | |||
;以下取当前光标位置 | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
inc dx ;0x3d5 | |||
in al,dx ;高字 | |||
mov ah,al | |||
dec dx ;0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
inc dx ;0x3d5 | |||
in al,dx ;低字 | |||
mov bx,ax ;BX=代表光标位置的16位数 | |||
cmp cl,0x0d ;回车符? | |||
jnz .put_0a | |||
mov ax,bx | |||
mov bl,80 | |||
div bl | |||
mul bl | |||
mov bx,ax | |||
jmp .set_cursor | |||
.put_0a: | |||
cmp cl,0x0a ;换行符? | |||
jnz .put_other | |||
add bx,80 | |||
jmp .roll_screen | |||
.put_other: ;正常显示字符 | |||
push es | |||
mov eax,video_ram_seg_sel ;0xb8000段的选择子 | |||
mov es,eax | |||
shl bx,1 | |||
mov [es:bx],cl | |||
pop es | |||
;以下将光标位置推进一个字符 | |||
shr bx,1 | |||
inc bx | |||
.roll_screen: | |||
cmp bx,2000 ;光标超出屏幕?滚屏 | |||
jl .set_cursor | |||
push ds | |||
push es | |||
mov eax,video_ram_seg_sel | |||
mov ds,eax | |||
mov es,eax | |||
cld | |||
mov esi,0xa0 ;小心!32位模式下movsb/w/d | |||
mov edi,0x00 ;使用的是esi/edi/ecx | |||
mov ecx,1920 | |||
rep movsd | |||
mov bx,3840 ;清除屏幕最底一行 | |||
mov ecx,80 ;32位程序应该使用ECX | |||
.cls: | |||
mov word[es:bx],0x0720 | |||
add bx,2 | |||
loop .cls | |||
pop es | |||
pop ds | |||
mov bx,1920 | |||
.set_cursor: | |||
mov dx,0x3d4 | |||
mov al,0x0e | |||
out dx,al | |||
inc dx ;0x3d5 | |||
mov al,bh | |||
out dx,al | |||
dec dx ;0x3d4 | |||
mov al,0x0f | |||
out dx,al | |||
inc dx ;0x3d5 | |||
mov al,bl | |||
out dx,al | |||
popad | |||
ret | |||
;------------------------------------------------------------------------------- | |||
read_hard_disk_0: ;从硬盘读取一个逻辑扇区 | |||
;EAX=逻辑扇区号 | |||
;DS:EBX=目标缓冲区地址 | |||
;返回:EBX=EBX+512 | |||
push eax | |||
push ecx | |||
push edx | |||
push eax | |||
mov dx,0x1f2 | |||
mov al,1 | |||
out dx,al ;读取的扇区数 | |||
inc dx ;0x1f3 | |||
pop eax | |||
out dx,al ;LBA地址7~0 | |||
inc dx ;0x1f4 | |||
mov cl,8 | |||
shr eax,cl | |||
out dx,al ;LBA地址15~8 | |||
inc dx ;0x1f5 | |||
shr eax,cl | |||
out dx,al ;LBA地址23~16 | |||
inc dx ;0x1f6 | |||
shr eax,cl | |||
or al,0xe0 ;第一硬盘 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 ecx,256 ;总共要读取的字数 | |||
mov dx,0x1f0 | |||
.readw: | |||
in ax,dx | |||
mov [ebx],ax | |||
add ebx,2 | |||
loop .readw | |||
pop edx | |||
pop ecx | |||
pop eax | |||
retf ;段间返回 | |||
;------------------------------------------------------------------------------- | |||
;汇编语言程序是极难一次成功,而且调试非常困难。这个例程可以提供帮助 | |||
put_hex_dword: ;在当前光标处以十六进制形式显示 | |||
;一个双字并推进光标 | |||
;输入:EDX=要转换并显示的数字 | |||
;输出:无 | |||
pushad | |||
push ds | |||
mov ax,core_data_seg_sel ;切换到核心数据段 | |||
mov ds,ax | |||
mov ebx,bin_hex ;指向核心数据段内的转换表 | |||
mov ecx,8 | |||
.xlt: | |||
rol edx,4 | |||
mov eax,edx | |||
and eax,0x0000000f | |||
xlat | |||
push ecx | |||