1. 重复的rd_disk_m
a. 《操作系统还原真相》书中在读取kernel时,在32位模式下重新写了一个rd_disk_m_32,
这个函数本身与rd_disk_m_16类似没有多大差别。
b. 我想为什么要再写一个重复的函数,能不能用rd_disk_m_16呢,
能不能读完loader.bin之后接着再读kernel不就行了?
2. 下面是读kernel的代码
-
cong@msi:/work/os/code/5kernel$ cat mbr.S
-
org 0x7C00
-
mov ax, cs
-
mov ds, ax
-
mov es, ax
-
mov ss, ax
-
mov ax, 0xb800
-
mov gs, ax
-
-
;print 1MBR
-
mov byte [gs:0x00], '1'
-
mov byte [gs:0x01], 0xA4
-
-
mov byte [gs:0x02], 'M'
-
mov byte [gs:0x03], 0xA4
-
-
mov byte [gs:0x04], 'B'
-
mov byte [gs:0x05], 0xA4
-
-
mov byte [gs:0x06], 'R'
-
mov byte [gs:0x07], 0xA4
-
-
;loader loader.bin to 0x9000
-
xor ax,ax
-
mov es, ax
-
mov bx, 0x500 ;dst_add in memory ;将loader.bin读到内存的[0x500-0x700]
-
mov cl, 1 ;sector cnt of disk
-
mov eax, 2 ;LBA addr
-
call load_disk
-
-
;loader kernel.bin to [0x1000:bx]处 ;将kernel.bin读到内存的[0x1000-0x1000+dx]处
-
mov ax, 0x1000
-
mov es, ax
-
mov bx, 0x00 ;dst_add in memory
-
mov cx, 0x81 ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x80-->ok 0x81-->not ok
-
mov eax, 10 ;LBA addr
-
call load_disk
-
-
;jmp to 0x9000
-
jmp 0x500
-
-
load_disk:
-
;eax --> src_addr of disk, in the format of LBA
-
;bx --> memory dst_addr
-
;cx --> sector_count
-
mov esi, eax
-
mov di, cx
-
-
mov dx, 0x1f2 ;sector count
-
mov al, cl
-
out dx, al
-
-
mov eax, esi ;LBA-->0-8
-
mov dx, 0x1f3
-
out dx, al
-
-
mov cl, 8
-
shr eax, cl ;LBA--> 8-16
-
mov dx, 0x1f4
-
out dx, al
-
-
shr eax, cl ;LBA-->16-24
-
mov dx, 0x1f5
-
out dx, al
-
-
shr eax, cl ;LBA-->16-24
-
and al, 0x0f
-
or al, 0xe0
-
mov dx, 0x1f6
-
out dx, al
-
-
mov dx,0x1f7 ;send read cmd
-
mov al, 0x20
-
out dx, al
-
-
not_ready:
-
nop
-
in al, dx
-
and al,0x88
-
cmp al,0x08
-
jnz not_ready
-
-
mov ax, di
-
mov dx, 256
-
mul dx
-
mov cx, ax
-
mov dx, 0x1f0
-
goon_read:
-
in ax, dx
-
mov [es:bx], ax -->这儿多加了一个es
-
add bx, 2
-
loop goon_read
-
ret
-
-
jmp $
-
times 510-($-$$) db 0
-
dw 0xaa55
上面棕底的字体,说明了一个问题: 当sector_cnt=0x80时是ok的,但是sector_cnt=0x81就不对了,
这是为什么呢?
因为我在调试时 xp /32 0x10000 只打印出32个字节,一看全是0
但是 xp /1024 0x10000 时,发现后面的数据是正确的前面的数据有错误,
原来是这样
0x81*256*2 = 0x10200 大于64K=0x10000了
1.3 改正后的代码
-
org 0x7C00
-
mov ax, cs
-
mov ds, ax
-
mov es, ax
-
mov ss, ax
-
mov ax, 0xb800
-
mov gs, ax
-
-
;print 1MBR
-
mov byte [gs:0x00], '1'
-
mov byte [gs:0x01], 0xA4
-
-
mov byte [gs:0x02], 'M'
-
mov byte [gs:0x03], 0xA4
-
-
mov byte [gs:0x04], 'B'
-
mov byte [gs:0x05], 0xA4
-
-
mov byte [gs:0x06], 'R'
-
mov byte [gs:0x07], 0xA4
-
-
;loader loader.bin to 0x9000
-
xor ax,ax
-
mov es, ax
-
mov bx, 0x500 ;dst_add in memory
-
mov cl, 1 ;sector cnt of disk
-
mov eax, 2 ;LBA addr
-
call load_disk
-
-->如果大于128个sector就读两次,一共读0x80+0x48=0xc8=200个sector
-
;loader kernel.bin to 0x500 -->如果大于128个sector就读两次
-
mov ax, 0x1000
-
mov es, ax
-
mov bx, 0x00 ;dst_add in memory
-
mov cx, 0x80 ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x84-->not ok
-
mov eax, 10 ;LBA addr
-
call load_disk
-
-
mov ax, 0x2000 -->如果大于128个sector就读两次,读第二次时自己控制好es
-
mov es, ax
-
mov bx, 0x00 ;dst_add in memory
-
mov cx, 0x48 ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x84-->not ok
-
mov eax, 10 ;LBA addr
-
call load_disk
-
;jmp to 0x9000
-
jmp 0x500
-
-
load_disk:
-
;eax --> src_addr of disk, in the format of LBA
-
;bx --> memory dst_addr
-
;cx --> sector_count
-
mov esi, eax
-
mov di, cx
-
-
mov dx, 0x1f2 ;sector count
-
mov al, cl
-
out dx, al
-
-
mov eax, esi ;LBA-->0-8
-
mov dx, 0x1f3
-
out dx, al
-
-
mov cl, 8
-
shr eax, cl ;LBA--> 8-16
-
mov dx, 0x1f4
-
out dx, al
-
-
shr eax, cl ;LBA-->16-24
-
mov dx, 0x1f5
-
out dx, al
-
-
shr eax, cl ;LBA-->16-24
-
and al, 0x0f
-
or al, 0xe0
-
mov dx, 0x1f6
-
out dx, al
-
-
mov dx,0x1f7 ;send read cmd
-
mov al, 0x20
-
out dx, al
-
-
not_ready:
-
nop
-
in al, dx
-
and al,0x88
-
cmp al,0x08
-
jnz not_ready
-
-
mov ax, di
-
mov dx, 256
-
mul dx
-
mov cx, ax
-
mov dx, 0x1f0
-
goon_read:
-
in ax, dx
-
mov [es:bx], ax
-
add bx, 2
-
loop goon_read
-
ret
-
-
jmp $
-
times 510-($-$$) db 0
-
dw 0xaa55
最好的方法是在函数load_disk中添加判断条件,如果要读取的sector>0x80,es也要加0x1000
我的目的是要研究操作系统,不细究这儿的细节了。
方法是这样的,如果大于0x80就直接读两次,读第二次的时候控制好es
1.4 代码下载
5kernel.rar(下载后改名为5kernel.tar.gz)
附录: 如何在64位下编出32位的代码?
-
kernel:
-
gcc -c -m32 -o main.o main.c
-
ld -m elf_i386 main.o -Ttext 0xc0001500 -e main -o kernel.bin
即编译时加 -m32
链接时加-m elf_i386
阅读(1111) | 评论(0) | 转发(0) |