实验1:操作系统的引导
本章是操作系统实验1的实验记录,对应的课程笔记为:L1 操作系统的启动
! bootsect.s 的任务
! 1.将自己从内存的 0x7c00 搬移到 0x90000 处
! 2.屏幕上打印操作系统正在启动
! 3.将setup.s 从磁盘的第2个扇区,搬移到内存中(bootsect.s的后面)
! as86 linux 汇编语法 : https://blog.csdn.net/qq_26025363/article/details/72566093
! #表示立即数寻址bai。采用立即寻du址方式zhi的指令,在立即dao数前面加上立即zhuan寻址符“#”。
! 例如shu指令MOV A,#30H中30H就是立即数,指令功能为将30H赋给累加器A。
! @表示寄存器的间接寻址。
! 例如指令MOV A,@R0就使用了寄存器间接寻址方式,这条指令的意义为将地址指针R0指向的内部数据存储器单元中的数据送入累加器A中。
! 假设R0中内容为30H,则此指令的功能是以R0寄存器的内容30H为地址,把内部RAM 30H单元中的内容传送给累加器A。
! 一些调试方法:
! ./dbg-asm(启动调试)、reg(查看寄存器)、sreg(查看段寄存器)、xp /nuf addr(查看内存,如 xp /5wc 0x9000:0x0033)
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
BOOTSEG = 0x07c0 ! bootsect.s 起始段地址(偏移地址为0)
INITSEG = 0x9000 ! bootsect.s 搬移后的段地址(偏移地址为0)
SETUP_OFFSET = 0x0200! setup.s 在内存中存放的偏移地址
YELLOW = 0x0e ! 淡青色
LIGHT_RED = 0x0c ! 淡红色
entry _start !程序入口
_start:
mov ax, #BOOTSEG ! 记得加 # ,表示立即数
mov ds, ax
mov ax, #INITSEG
mov es, ax
mov si, #0
mov di, #0
mov cx, #256
cld
rep
movw
jmpi go, #INITSEG ! 跳转到0x9000:go处
go:
mov ax, cs
mov es, ax
mov ds, ax
! load setup.s int 0x13中断:https://blog.csdn.net/xianjian1990/article/details/78559879
! https://blog.csdn.net/nwpulei/article/details/5757309
mov ah, 0x00
mov dl, 0x00
int 0x13 ! 复位磁盘
mov al, #0xff
mov ah, #0x01
mov dl, #0x00
int 0x13 ! 读磁盘状态信息 ! 注意这里不要有加“ # ”
and ah, #0xff ! 传出参数 成功:ah = 0x00 ; 错误:al为错误代码;这里注意正常情况用ah作为成功的判断条件,不要用al
jnz go ! 读磁盘失败了就跳回go
mov bx, #SETUP_OFFSET
mov al, #0x04 ! 读4个扇区
mov ch, #0x00 ! 0柱面
mov cl, #0x02 ! 第2个扇区
mov dh, #0x00 ! 0磁头
mov dl, #0x00 ! 软盘,0盘(应该类似于c盘吧)
mov ah, #0x02
int 0x13 ! 将setup.s读/加载 到内存中取
and ah, #0xff
jnz go ! 若失败则跳回go处。 linux0.11中使用 jnc ok_load_setup 做跳转,jnc不是cf不为0跳转吗?有点怪怪的
ok_load_setup: ! 到这里setup.s已经加载到了内存中 0x9000:0x0200
! print "hello OS is running !!!" int 0x10 中断功能: https://blog.csdn.net/trochiluses/article/details/8970835
mov ah, #3
mov bh, #0
int 0x10 ! 读光标位置 特别注意这里是0x10!!!
mov ax, cs
mov es, ax
mov bp, #print ! print 标签应该就是偏移地址(相对于本程序的偏移地址)
add dh, #1
mov dl, #0
mov bl, #YELLOW
mov cx, #23
mov bh, #0
mov al, #1
mov ah, #0x13
int 0x10
mov ah, #2
mov bh, #0
add dh, #1
mov dl, #0
int 0x10 ! 置光标位置
jmpi #SETUP_OFFSET, #INITSEG ! 跳转到setup.s
print:
.ascii "hello OS is running !!!" ! 23 byte
.org 510 ! 这里也要注意一下,表示这里是从地址510处开始的
.word 0xaa55 ! 特别注意这里,引导程序的结尾要有这个
.text
endtext:
.data
enddata:
.bss
endbss:
! setup.s的任务
! 1、打印"Now we are in SETUP"
! 2、setup.s能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。
! 3、setup.s不再加载Linux内核,保持上述信息显示在屏幕上即可。
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
INITSEG = 0x9000 ! bootsect.s 搬移后的段地址(偏移地址为0)
SETUP_OFFSET = 0x0200! setup.s 在内存中存放的偏移地址
entry start
start:
! print "Now we are in SETUP"
mov ah, #3
mov bh, #0
int 0x10 ! 读光标位置
mov ax, cs
mov es, ax
mov ax, #print1
add ax, #SETUP_OFFSET
mov bp, ax ! 记住要加0x200
mov al, #0x01
mov bl, #0x0c
mov bh, #0
mov cx, #20 ! 20 byte
mov ah, #0x13
int 0x10
mov ah, #2
mov bh, #0
add dh, #1
mov dl, #0
int 0x10 ! 置光标位置
mov ax, #print2
add ax, #SETUP_OFFSET
mov bp, ax ! 记住要加0x200
mov al, #0x01
mov bl, #0x0f
mov bh, #0
mov cx, #27 ! 27 byte
mov ah, #0x13
int 0x10
mov ah, #2
mov bh, #0
mov dl, #17
int 0x10 ! 置光标位置
! 设置寄存器
mov ax, #INITSEG
mov ds, ax
mov es, ax
mov ss, ax
mov sp, #SETUP_OFFSET
! 获取扩展内存大小 int 15h 中断 : https://blog.csdn.net/Yes_life/article/details/6839453
mov ah, #0x88
int 0x15
mov [2], ax
! 把扩展内存大小打印出来,
mov dx, ax
mov cl, #0x04
mov bx, #0x04
to_char:
rol dx, cl
mov ax, dx
and ax, #0x000f
cmp ax, #0x0a
jl less
add al,#0x37
jmp continue
less:
add al, #0x30
continue:
mov ah, #0x0e
int 0x10
!loop to_char ! 不用loop,不知道为什么 loop 不能跳转
dec bx
jnz to_char
! 程序在这里停下
l: jmp l
print1:
.ascii "Now we are in setup!" ! 20 byte
print2:
.ascii "extern memory: 0x KB" ! 27 byte
.text
endtext:
.data
enddata:
.bss
endbss: