写操作系统----5.解决读取kernel跨段

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的代码
  1. cong@msi:/work/os/code/5kernel$ cat mbr.
  2. org 0x7C00
  3.     mov ax, cs
  4.     mov ds, ax
  5.     mov es, ax
  6.     mov ss, ax
  7.     mov ax, 0xb800
  8.     mov gs, ax

  9.     ;print 1MBR
  10.     mov byte [gs:0x00], '1'
  11.     mov byte [gs:0x01], 0xA4
  12.     
  13.     mov byte [gs:0x02], 'M'
  14.     mov byte [gs:0x03], 0xA4

  15.     mov byte [gs:0x04], 'B'
  16.     mov byte [gs:0x05], 0xA4
  17.     
  18.     mov byte [gs:0x06], 'R'
  19.     mov byte [gs:0x07], 0xA4
  20.     
  21.     ;loader loader.bin to 0x9000
  22.     xor ax,ax
  23.     mov es, ax
  24.     mov bx, 0x500       ;dst_add in memory    ;将loader.bin读到内存的[0x500-0x700]  
  25.     mov cl, 1           ;sector cnt of disk
  26.     mov eax, 2          ;LBA addr
  27.     call load_disk

  28.     ;loader kernel.bin to [0x1000:bx]处       ;将kernel.bin读到内存的[0x1000-0x1000+dx]处  
  29.     mov ax, 0x1000    
  30.     mov es, ax
  31.     mov bx, 0x00          ;dst_add in memory
  32.     mov cx, 0x81          ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x80-->ok 0x81-->not ok
  33.     mov eax, 10           ;LBA addr
  34.     call load_disk

  35.     ;jmp to 0x9000
  36.     jmp 0x500

  37. load_disk:
  38.     ;eax --> src_addr of disk, in the format of LBA
  39.     ;bx --> memory dst_addr 
  40.     ;cx --> sector_count 
  41.     mov esi, eax
  42.     mov di, cx

  43.     mov dx, 0x1f2 ;sector count
  44.     mov al, cl
  45.     out dx, al
  46.     
  47.     mov eax, esi ;LBA-->0-8
  48.     mov dx, 0x1f3
  49.     out dx, al
  50.     
  51.     mov cl, 8
  52.     shr eax, cl ;LBA--> 8-16
  53.     mov dx, 0x1f4
  54.     out dx, al    

  55.     shr eax, cl ;LBA-->16-24
  56.     mov dx, 0x1f5
  57.     out dx, al

  58.     shr eax, cl ;LBA-->16-24
  59.     and al, 0x0f
  60.     or al, 0xe0
  61.     mov dx, 0x1f6
  62.     out dx, al

  63.     mov dx,0x1f7 ;send read cmd
  64.     mov al, 0x20
  65.     out dx, al

  66. not_ready:
  67.     nop
  68.     in al, dx
  69.     and al,0x88
  70.     cmp al,0x08
  71.     jnz not_ready
  72.     
  73.     mov ax, di
  74.     mov dx, 256
  75.     mul dx
  76.     mov cx, ax
  77.     mov dx, 0x1f0
  78. goon_read:
  79.     in ax, dx
  80.     mov [es:bx], ax                  -->这儿多加了一个es
  81.     add bx, 2
  82.     loop goon_read
  83.     ret

  84.     jmp $
  85. times 510-($-$$) db 0
  86. 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 改正后的代码

  1. org 0x7C00
  2.     mov ax, cs
  3.     mov ds, ax
  4.     mov es, ax
  5.     mov ss, ax
  6.     mov ax, 0xb800
  7.     mov gs, ax

  8.     ;print 1MBR
  9.     mov byte [gs:0x00], '1'
  10.     mov byte [gs:0x01], 0xA4
  11.     
  12.     mov byte [gs:0x02], 'M'
  13.     mov byte [gs:0x03], 0xA4

  14.     mov byte [gs:0x04], 'B'
  15.     mov byte [gs:0x05], 0xA4
  16.     
  17.     mov byte [gs:0x06], 'R'
  18.     mov byte [gs:0x07], 0xA4
  19.     
  20.     ;loader loader.bin to 0x9000
  21.     xor ax,ax
  22.     mov es, ax
  23.     mov bx, 0x500 ;dst_add in memory
  24.     mov cl, 1 ;sector cnt of disk
  25.     mov eax, 2 ;LBA addr
  26.     call load_disk
  27.     -->如果大于128个sector就读两次,一共读0x80+0x48=0xc8=200个sector
  28.     ;loader kernel.bin to 0x500           -->如果大于128个sector就读两次
  29.     mov ax, 0x1000    
  30.     mov es, ax
  31.     mov bx, 0x00 ;dst_add in memory
  32.     mov cx, 0x80 ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x84-->not ok
  33.     mov eax, 10 ;LBA addr
  34.     call load_disk

  35.     mov ax, 0x2000                        -->如果大于128个sector就读两次,读第二次时自己控制好es   
  36.     mov es, ax
  37.     mov bx, 0x00 ;dst_add in memory
  38.     mov cx, 0x48 ;sector cnt of disk 80-->ok 0x64-->ok 0x7F-->Ok 0x84-->not ok
  39.     mov eax, 10 ;LBA addr
  40.     call load_disk
  41.     ;jmp to 0x9000
  42.     jmp 0x500

  43. load_disk:
  44.     ;eax --> src_addr of disk, in the format of LBA
  45.     ;bx --> memory dst_addr 
  46.     ;cx --> sector_count 
  47.     mov esi, eax
  48.     mov di, cx

  49.     mov dx, 0x1f2 ;sector count
  50.     mov al, cl
  51.     out dx, al
  52.     
  53.     mov eax, esi ;LBA-->0-8
  54.     mov dx, 0x1f3
  55.     out dx, al
  56.     
  57.     mov cl, 8
  58.     shr eax, cl ;LBA--> 8-16
  59.     mov dx, 0x1f4
  60.     out dx, al    

  61.     shr eax, cl ;LBA-->16-24
  62.     mov dx, 0x1f5
  63.     out dx, al

  64.     shr eax, cl ;LBA-->16-24
  65.     and al, 0x0f
  66.     or al, 0xe0
  67.     mov dx, 0x1f6
  68.     out dx, al

  69.     mov dx,0x1f7 ;send read cmd
  70.     mov al, 0x20
  71.     out dx, al

  72. not_ready:
  73.     nop
  74.     in al, dx
  75.     and al,0x88
  76.     cmp al,0x08
  77.     jnz not_ready

  78.     mov ax, di
  79.     mov dx, 256
  80.     mul dx
  81.     mov cx, ax
  82.     mov dx, 0x1f0
  83. goon_read:
  84.     in ax, dx
  85.     mov [es:bx], ax
  86.     add bx, 2
  87.     loop goon_read
  88.     ret

  89.     jmp $
  90. times 510-($-$$) db 0
  91. dw 0xaa55
最好的方法是在函数load_disk中添加判断条件,如果要读取的sector>0x80,es也要加0x1000
我的目的是要研究操作系统,不细究这儿的细节了。
方法是这样的,如果大于0x80就直接读两次,读第二次的时候控制好es
1.4 代码下载
5kernel.rar (下载后改名为5kernel.tar.gz)
附录: 如何在64位下编出32位的代码?
  1. kernel:
  2.     gcc --m32 -o main.o main.c
  3.     ld -m elf_i386 main.-Ttext 0xc0001500 -e main -o kernel.bin
即编译时加 -m32  
  链接时加-m elf_i386
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值