操作系统真象还原第3章:完善MBR

前言

这次我出现了一些BUG,导致我忙活了一阵子,还好的是解决了
老规矩还是把整个流程过一遍,当MBR忙活完后,就需要把自己手中的棒交给loader了,MBR的作用就是从硬盘中的内核加载器移动到内存中,然后跳转到内核加载器的地址去让内核加载器运行,在这方面需要对硬件需要一些了解特别是in out指令,还有个各个端口访问(端口就是寄存器),因为需要通过这些端口读取数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验

书中也说了需要对rd_disk_m_16函数要比较了解,所以我给出我的一些注释
mbr.S

%include "boot.inc" ;预处理
SECTION MBR vstart=0x7c00 ;设置段基址

	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov fs,ax
	mov sp,0x7c00
	mov ax,0xb800
	mov gs,ax
	
	mov ax,0x600
	mov bx,0x700
	mov cx,0
	mov dx,0x184f
	
	int 0x10
    ;以下都是显存的设置 gs=0xb800 就是可以显示字符的内存地址
	mov byte [gs:0x00],'1'
	mov byte [gs:0x01],0xA4
	
	mov byte [gs:0x02],' '
	mov byte [gs:0x03],0xA4
	
	mov byte [gs:0x04],'M'
	mov byte [gs:0x05],0xA4
	
	mov byte [gs:0x06],'B'
	mov byte [gs:0x07],0xA4
	
	mov byte [gs:0x08],'R'
	mov byte [gs:0x09],0xA4
	
	mov eax,LOADER_START_SECTOR ;起始扇区Lba地址
    mov bx,LOADER_BASE_ADDR    ;写入的地址
    mov cx,1                   ;待读入的扇区
    call rd_disk_m_16          ;以下读程序的起始部分
    
    jmp LOADER_BASE_ADDR       ;将数据加载到内存中后就会转而执行这个,其实也就是loader.bin
    
    ;----功能:读取硬盘第n个扇区----
    ;eax LBA扇区号
    ;bx=将内存写入的地址
    ;cx=读入的扇区数
rd_disk_m_16:

    mov esi,eax ;用来备份eax,di
    mov di,cx   ;di=1

    mov dx,0x1f2 ;设置扇区的数量的端口
    mov al,cl    ;al=1,只需要8位
    out dx,al    ;将al写入dx寄存器中,dx寄存器就是端口

    mov eax,esi  ;将eax复位

    mov dx,0x1f3 ;设置LBA的端口
    out dx,al    ;将LBA的7-0位读入端口去

    mov cl,8     ;
    shr eax,cl   ;右移8位
    mov dx,0x1f4
    out dx,al    ;将LBA的15-8位存入端口中去

    shr eax,cl   ;右移8位
    mov dx,0x1f5 
    out dx,al    ;将LBA的23-16位存入端口中去

    shr eax,cl   ;再次右移8位
    and al,0x0f  ;让低4位不变,因为低4位需要保存LBA的28-24位(LBA总共28位)
    or al,0xe0   ;将前四位与1110取或,也就是前三位直接固定,保证寻址模式一定是LBA
    mov dx,0x1f6 ;进入device端口
    out dx,al    ;将信息读给端口

    mov dx,0x1f7 ;命令端口
    mov al,0x20  ;读入扇区的命令
    out dx,al    ;将命令读入端口

    .not_ready:
        nop
        in al,dx ;将端口中的信息读到al中,注意此时dx=0x1f7不变,此时是status寄存器,也就是状态端口
        and al,0x88 ;通过第7位(从0开始),也就是第8位(从1开始),判断硬盘是不是忙碌的,也就是是否被占了,1代表被占
        cmp al,0x08  ;
        jnz .not_ready ;如果被占取了,就循环  jnz=jmp not equal

        mov ax,di  ;di=1
        mov dx,256 
        mul dx     ;dx=ax*dx 每次读取1个字,也就是两字节,一共512字节,所以需要256次
        mov cx,ax  ;cx指定循环的次数
        mov dx,0x1f0 ;数据端口,终于开始读取数据了
        
    .go_on_read:     
        in ax,dx      ;将端口中指定的数据,也就是指定的扇区的数据读入到ax中
        mov [bx],ax   ;bx寄存器存储的就是0x900也就是loader的内存地址
        add bx,2      ;每次读两字节
        loop .go_on_read

        ret            ;返回后就会执行jmp跳转到0x900去了,此时机会执行loader.bin
	
	times 510-($-$$) db 0 ;剩下的数据填充为0
	db 0x55,0xaa        ;魔数,判断是否为mbr

loader.S

%include "boot.inc"
SECTION LOADER vstart=LOADER_BASE_ADDR

mov byte [gs:0x00],'2'
mov byte [gs:0x01],0xA4

mov byte [gs:0x02],' '
mov byte [gs:0x03],0xA4

mov byte [gs:0x04],'L'
mov byte [gs:0x05],0xA4

mov byte [gs:0x06],'O'
mov byte [gs:0x07],0xA4

mov byte [gs:0x08],'A'
mov byte [gs:0x09],0xA4

mov byte [gs:0x0a],'D'
mov byte [gs:0x0b],0xA4

mov byte [gs:0x0c],'E'
mov byte [gs:0x0d],0xA4

mov byte [gs:0x0e],'R'
mov byte [gs:0x0f],0xA4

jmp $    ;通过死循环使程序悬停

实验结果&&出现的问题

在使用dd命令写入磁盘的时候要尽量使用conv=notrunc,这代表不截断数据的意思,一开始你不是给hd60M.img文件分配60M的大小吗,此时文件大小是512字节的整数倍,并且那个bochsrc数据中的CHS配置也是根据你自己create时配置的,其实也就是代表hd60M.img的大小,如果你在dd命令后使hd60M.img大小变了,如果不是512字节的整数倍,就会panic错误,同时大小变了也就对不上bochsrcCHS配置了,就会panic not fit disk image错误
在这里插入图片描述

参考

操作系统真象还原

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值