实验4.保护模式

简介

实验:编写boot.inc和loader.s,完成在内存里写好3个段描述符(代码段、数据段、显存段)、赋值好GDTR寄存器、创建好表示3个选择子的字段后,进入保护模式

注意:此时loader.bin大于512字节,mbr要读取2个分区,dd也要复制2个分区

代码

boot/mbr.s

; boot/mbr.s
; 功能:读取磁盘,加载loader到内存并跳转到loader

%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

; 清屏利用0x06号功能,上卷全部行,则可清屏。
; 输入:
; AH 功能号=0x06
; AL = 上卷的行数(如果为0,表示全部)
; BH = 上卷行属性
; (CL,CH) = 窗口的左上角的(X,Y)位置
; (DL,DH) = 窗口的右上角的(X,Y)位置
; 无返回值:
    mov ax,0x600
    mov bx,0x700
    mov cx,0
    mov dx,0x184f
    int 0x10

    mov eax,LOADER_START_SECTOR
    mov bx,LOADER_BASE_ADDR
    mov cx,2
    call rd_disk_m_16
    jmp LOADER_BASE_ADDR

; 读取硬盘n个扇区
; eax = LBA扇区号
; bx = 将数据写入的内存地址
; cx=读入的扇区数
rd_disk_m_16:
; 备份
    mov esi,eax
    mov di,cx

; 设置要读取的扇区数
    mov cl,0x8
    mov dx,0x1f2
    mov al,cl
    out dx,al
    mov eax,esi

; 设置要读取的地址
    mov dx,0x1f3 ; 写入0-7位
    out dx,al

    mov cl,0x8
    shr eax,cl
    mov dx,0x1f4 ; 写入8-15位
    out dx,al

    shr eax,cl
    mov dx,0x1f5 ; 写入16-23位
    out dx,al

    shr eax,cl
    and al,0x0f ; 24~27位
    or  al,0xe0 ; 设置7~4位为1110,表示lba模式
    mov dx,0x1f6
    out dx,al

; 写入读命令
    mov dx,0x1f7
    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
.go_on_read:
    in ax,dx
    mov [bx],ax
    add bx,2
    loop .go_on_read
    ret

    times 510-($-$$) db 0
    db 0x55,0xaa

boot/loader.s

; boot/loader.s
; 功能:完成在内存里写好3个段描述符(代码段、数据段、显存段)、赋值好GDTR寄存器、创建好表示3个选择子的字段后,进入保护模式,在保护模式下执行最后三句代码

%include "boot.inc"
SECTION loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR
jmp loader_start

; ---构建gdt---
GDT_BASE:
    dd 0x0000_0000
    dd 0x0000_0000

CODE_DESC:
    dd 0x0000_ffff
    dd DESC_CODE_HIGH4

DATA_STARK_DESC:
    dd 0x0000_ffff
    dd DESC_DATA_HIGH4

VEDIO_DESC:
    dd 0x8000_0007 ; limit=(0xbffff-0xb8000)/4k=0x7
    dd DESC_VIDEO_HIGH4

    GDT_SIZE equ $ - GDT_BASE
    GDT_LIMIT equ GDT_SIZE - 1
    times 60 dq 0
    SELECTOR_CODE equ  (0x0001<<3) + TI_GDT + RPL0
    SELECTOR_DATA equ  (0x0002<<3) + TI_GDT + RPL0
    SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0

    gdt_ptr dw GDT_LIMIT
            dd GDT_BASE


loadermsg db '2 loader in real.'
loader_start:
  mov sp,LOADER_BASE_ADDR
; 调用13号子功能打印字符串
; 输入:
; ah 功能号13
; al设置写字符方式 ah=01:显示字符串,光标跟随移动
; bh设置要显示的页号,此处是第0页
; ;bl中是字符属性,属性是黑底绿字(bl=02h)
; es:bp为串首地址
; cx为串长度,不包括结束符0
; dh 行
; dl 列
    mov bp,loadermsg
    mov cx,17
    mov ax,0x1301
    mov bx,0x001f
    mov dx,0x1800
    int 0x10

; ---进入保护模式---
; 打开A20
    in al,0x92
    or al,0000_0010B
    out 0x92,al
; 加载gdt
    lgdt [gdt_ptr]
; cr0第0位给1
    mov eax,cr0
    or eax,0x00000001
    mov cr0,eax

; 刷新流水线
 jmp  SELECTOR_CODE:p_mode_start

[bits 32]
p_mode_start:
    mov ax,SELECTOR_DATA
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov esp,LOADER_STACK_TOP

    mov ax,SELECTOR_VIDEO
    mov gs,ax
    mov byte [gs:160], 'P'
    jmp $

编译

Makefile

BUILD_DIR = ./build

.PHONY : mk_dir bootloader clean all

mk_dir: #创建build目录
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

bootloader: #编译启动内核的文件 bootloader
	nasm -I include/ -o $(BUILD_DIR)/mbr.bin boot/mbr.s
	nasm -I include/ -o $(BUILD_DIR)/loader.bin boot/loader.s
	dd if=/home/c/tityos/build/mbr.bin of=/home/c/tityos/hd60M.img bs=512 count=1 conv=notrunc
	dd if=/home/c/tityos/build/loader.bin of=/home/c/tityos/hd60M.img bs=512 count=2 seek=2 conv=notrunc

clean: #删除build目录里的全部文件
	cd $(BUILD_DIR) && rm -f  ./*

# 创建build目录。编译启动内核的文件。
all: mk_dir bootloader

运行

start.sh

# !/bin/bash
# 功能:启动bochs

bin/bochs -f bochsrc.disk

在这里插入图片描述

  • 40
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值