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的代码
上面棕底的字体,说明了一个问题: 当sector_cnt=0x80时是ok的,但是sector_cnt=0x81就不对了,
这是为什么呢?
因为我在调试时 xp /32 0x10000 只打印出32个字节,一看全是0
但是 xp /1024 0x10000 时,发现后面的数据是正确的前面的数据有错误, 原来是 这样
0x81*256*2 = 0x10200 大于64K=0x10000了
1.3 改正后的代码
最好的方法是在函数load_disk中添加判断条件,如果要读取的sector>0x80,es也要加0x1000
我的目的是要研究操作系统,不细究这儿的细节了。
方法是这样的,如果大于0x80就直接读两次,读第二次的时候控制好es
1.4 代码下载
5kernel.rar (下载后改名为5kernel.tar.gz)
附录: 如何在64位下编出32位的代码?
即编译时加 -m32
链接时加-m elf_i386
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
这是为什么呢?
因为我在调试时 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
我的目的是要研究操作系统,不细究这儿的细节了。
方法是这样的,如果大于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
链接时加-m elf_i386