Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
实
实验2 任务(一)模板
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
实验2 任务(一)模板
提交
f4829d6e
提交
f4829d6e
6月 29, 2020
创建
作者:
王晓庆
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
调整模板
上级
67620e87
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
18 行增加
和
259 行删除
+18
-259
boot.asm
boot.asm
+10
-216
loader.asm
loader.asm
+3
-43
readme.md
readme.md
+5
-0
没有找到文件。
boot.asm
浏览文件 @
f4829d6e
...
...
@@ -73,41 +73,7 @@
jmp
short
Start
nop
; 这个 nop 不可少
; ----------------------------------------------------------------------
; FAT12 引导扇区头
Oem
db
'
Engintim
'
; OEM String,必须 8 个字节
BytesPerSector
dw
512
; 每扇区字节数 ----+
SectorsPerCluster
db
1
; 每簇多少扇区 |
ReservedSectors
dw
1
; Boot 记录占用多少扇区 |
Fats
db
2
; FAT 表数 |
RootEntries
dw
224
; 根目录文件数最大值 |
Sectors
dw
2880
; 扇区总数 \\ BPB
Media
db
0xF0
; 介质描述 // BIOS Parameter Block
SectorsPerFat
dw
9
; 每 FAT 扇区数 |
SectorsPerTrack
dw
18
; 每磁道扇区数 |
Heads
dw
2
; 磁头数 |
HiddenSectors
dd
0
; 隐藏扇区数 |
LargeSectors
dd
0
; 扇区总数,Sectors 为 0 时使用 ----+
DriveNumber
db
0
; 驱动器号
Reserved
db
0
; 保留未用
Signature
db
0x29
; 引导标记 (0x29)
Id
dd
0
; 卷序列号
VolumeLabel
db
'
EOS
'
; 卷标,必须 11 个字节
SystemId
db
'
FAT12
'
; 文件系统类型,必须 8 个字节
;------------------------------------------------------------------------
; FAT12 文件系统相关的一些变量
FirstSectorOfRootDir
dw
0
; 根目录的起始扇区号
RootDirectorySectors
dw
0
; 根目录占用的扇区数量
FirstSectorOfFileArea
dw
0
; 数据区的起始扇区号
BufferOfFat
dw
0
; FAT 表缓冲区地址
BufferOfRootDir
dw
0
; 根目录缓冲区地址
LOADER_ORG
equ
0x1000
; Loader.bin 的起始地址
MAX_FILE_SIZE
equ
0x6C00
; Loader.bin 只占用 0x1000 到 0x7C00 的空间
wFilePos
dw
LOADER_ORG
; 用于加载 Loader.bin 的游标
LoaderFileName
db
"LOADER BIN"
; Loader.bin 的文件名
strError
:
db
"File Loader.bin not found!"
Start
:
; 初始化 CPU 的段寄存器为 CS 的值(0),堆栈从 64K 向下增长
...
...
@@ -130,140 +96,19 @@ Start:
xor
dl
,
dl
int
0x13
;
; 计算根目录的起始扇区号
; FirstSectorOfRootDir = ReservedSectors + SectorsPerFat * Fats
;
mov
ax
,
word
[SectorsPerFat]
movzx
bx
,
byte
[Fats]
mul
bx
add
ax
,
word
[ReservedSectors]
mov
word
[FirstSectorOfRootDir],
ax
;
; 计算根目录占用的扇区数量
; RootDirectorySectors = RootEntries * 32 / BytesPerSector
;
mov
ax
,
word
[RootEntries]
shl
ax
,
5
mov
bx
,
word
[BytesPerSector]
div
bx
mov
word
[RootDirectorySectors],
ax
;
; 计算数据区域的起始扇区号
; FirstSectorOfFileArea = FirstSectorOfRootDir + RootDirectorySectors
;
add
ax
,
word
[FirstSectorOfRootDir]
mov
word
[FirstSectorOfFileArea],
ax
;
; 计算 FAT 缓冲区地址(紧接在引导扇区后)
; BufferOfFat = 0x7C00 + BytesPerSector * ReservedSectors
;
mov
ax
,
word
[BytesPerSector]
mul
word
[ReservedSectors]
add
ax
,
0x7C00
mov
word
[BufferOfFat],
ax
;
; 计算根目录缓冲区地址(紧接在 FAT 缓冲区后)
; BufferOfRootDir = BufferOfFat + BytesPerSector * SectorsPerFat
;
mov
ax
,
word
[BytesPerSector]
mul
word
[SectorsPerFat]
add
ax
,
word
[BufferOfFat]
mov
word
[BufferOfRootDir],
ax
; 将 FAT1 读入 FAT 缓冲区
mov
ax
,
word
[ReservedSectors]
;
mov
cx
,
word
[SectorsPerFat]
; 一个 FAT 表的扇区数量
mov
bx
,
word
[BufferOfFat]
; es:bx 指向 FAT 表缓冲区
call
ReadSector
; 将根目录读入缓冲区
mov
ax
,
word
[FirstSectorOfRootDir]
mov
cx
,
word
[RootDirectorySectors]
mov
bx
,
word
[BufferOfRootDir]
call
ReadSector
; 在根目录中查找 Loader.bin 文件
FindFile
:
mov
bx
,
word
[BufferOfRootDir]
; bx 指向第一个根目录项
mov
dx
,
word
[RootEntries]
; 根目录项总数
cld
CompareNextDirEntry
:
mov
si
,
LoaderFileName
; si -> "LOADER BIN"
mov
di
,
bx
; di -> 目录项中文件名字符串
mov
cx
,
11
; 文件名字符串的长度
repe
cmpsb
; 字符串比较
cmp
cx
,
0
je
CheckFileSize
; 如果比较了 11 个字符都相等, 表示找到文件
; 文件名不一致,继续比较下一个目录项
add
bx
,
0x20
; bx 指向下一个目录项
dec
dx
; 减小剩余目录项
jnz
CompareNextDirEntry
; 查找完所有目录项仍没有找到文件,提示出错
jmp
Error
; 找到文件后,检查文件的大小
CheckFileSize
:
mov
eax
,
dword
[
bx
+
0x1C
]
; 得到文件的大小
test
eax
,
eax
jz
Error
cmp
eax
,
MAX_FILE_SIZE
ja
Error
; 开始加载文件
mov
ax
,
word
[
bx
+
0x1A
]
; 初始化 ax 为文件的第一个簇号
ReadNextCluster
:
push
ax
; 保存要读取的簇号
;
; 计算 ax 号簇对应的扇区号,扇区号 = 数据区起始扇区号 + (簇号 - 2) * 每簇扇区数
;
sub
ax
,
2
movzx
cx
,
byte
[SectorsPerCluster]
mul
cx
add
ax
,
word
[FirstSectorOfFileArea]
mov
bx
,
word
[wFilePos]
; ; 文件缓冲区地址
; 将floppy.img中第2~5扇区(loader)的内容加载到0x1000处,共4个扇区
call
ReadSector
; 读一个簇
;
; 文件位置向后移动一个簇的大小
; wFilePos = wFilePos + BytesPerSector * SectorsPerCluster
;
mov
ax
,
word
[BytesPerSector]
movzx
bx
,
byte
[SectorsPerCluster]
mul
bx
add
ax
,
word
[wFilePos]
;
mov
word
[wFilePos],
ax
mov
bx
,
LOADER_ORG
; es:bx 指向 0:0x1000
; 查找 FAT 表,获得下一个要读取的簇
pop
ax
; 刚读取的簇号
mov
bx
,
3
mul
bx
mov
bx
,
2
div
bx
mov
bx
,
word
[BufferOfFat]
add
bx
,
ax
mov
ax
,
word
[bx]
test
dx
,
dx
jz
EvenClusterNo
shr
ax
,
4
jmp
CheckEOC
EvenClusterNo
:
and
ax
,
0x0FFF
mov
al
,
4
;读取的扇区数(拟定loader占用4个扇区)
mov
ch
,
0
;磁道
mov
cl
,
2
;扇区号(读第二个扇区)
mov
dl
,
0
;软驱A
mov
dh
,
0
;0面
; 根据簇号判断文件是否结束,如没结束则继续读取
CheckEOC
:
cmp
ax
,
0x0FF7
jb
ReadNextCluster
mov
ah
,
2
;读扇区
int
13
h
; 文件读取完毕,关闭软驱马达
mov
dx
,
0x03F2
...
...
@@ -272,57 +117,6 @@ CheckEOC:
; Loader.bin 加载完毕,跳转到 Loader.bin 执行
jmp
0
:
LOADER_ORG
; 出错处理:在屏幕左上角显示错误信息字符串,并且死循环
Error
:
mov
bp
,
strError
mov
ax
,
0x1301
; AH = 0x13, AL = 0x01
mov
bx
,
0x0007
; 页号为 0 (BH = 0x00),黑底白字 (BL = 0x07)
mov
cx
,
26
; 字符串长度
xor
dx
,
dx
int
0x10
jmp
$
;----------------------------------------------------------------------------
; 函数名: ReadSector
; 作 用: 从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
;----------------------------------------------------------------------------
ReadSector
:
push
bp
mov
bp
,
sp
push
cx
; 保存 cl
push
bx
; 保存 bx
;
; 计算 柱面号、起始扇区 和 磁头号
; 设扇区号为 x
; ┌ 柱面号 = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁头号 = y & 1
; 每磁道扇区数 │
; └ 余 z => 起始扇区号 = z + 1
;
mov
bl
,
[SectorsPerTrack]
; bl: 除数
div
bl
; y 在 al 中, z 在 ah 中
inc
ah
; z ++
mov
cl
,
ah
; cl <- 起始扇区号
mov
dh
,
al
; dh <- y
shr
al
,
1
; y >> 1 (其实是 y / Heads, 这里 Heads = 2)
mov
ch
,
al
; ch <- 柱面号
and
dh
,
1
; dh & 1 = 磁头号
mov
dl
,
[DriveNumber]
; 驱动器号 (0 表示 A 盘)
pop
bx
; 恢复 bx
.
GoOnReading
:
mov
ah
,
2
; 读
mov
al
,
byte
[
bp
-
2
]
; 读 al 个扇区
int
0x13
jc
.
GoOnReading
; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
; 恢复堆栈并返回
pop
cx
pop
bp
ret
;
; 引导扇区代码结束,填充剩下的空间,使生成的二进制代码恰好为 512 字节
...
...
loader.asm
浏览文件 @
f4829d6e
...
...
@@ -142,49 +142,9 @@ Start:
call
GetMemorySize
mov
dword
[PhysicalMemorySize],
eax
;
; 初始化和 FAT12 文件系统相关的变量
call
InitFAT12
;
; 在根目录中查找文件名为 szKernelFileName 的文件,返回文件的目录项指针
push
word
szKernelFileName
call
OpenFile
mov
[DirectoryEntry],
ax
;
; 如果文件不存在,则提示错误并死循环
cmp
ax
,
0
jne
.
FILE_EXIST
push
word
szNoKernel
call
TextOut
jmp
$
;
; 检查文件的大小,如果大小不在区间 (0,MAX_IMAGE_SIZE]
; 之内,则提示错误并死循环
.
FILE_EXIST
:
mov
bx
,
ax
mov
ecx
,
dword
[
bx
+
0x1C
]
cmp
ecx
,
0
je
.
INVALID_FILE_SIZE
cmp
ecx
,
MAX_IMAGE_SIZE
jbe
.
VALID_FILE_SIZE
.
INVALID_FILE_SIZE
:
push
word
szInvalidFileSize
call
TextOut
jmp
$
;
; 加载内核文件到其虚拟基址对应的物理内存中
.
VALID_FILE_SIZE
:
push
dword
szLoading
call
TextOut
push
word
0
push
word
(
IMAGE_VIRTUAL_BASE
-
SYSTEM_VIRTUAL_BASE
)
>>
4
push
word
[DirectoryEntry]
call
ReadFile
; ######################################################
; 在此处编辑代码,功能是:从镜像文件读600个扇区到物理内存0x10000处
; ######################################################
;
; 检查内核映像的虚拟基址及映像大小是否符合约定,Loader 不支持内核重定位。
...
...
readme.md
0 → 100644
浏览文件 @
f4829d6e
本项目用于完成OS Lab奖励实验 从平坦软盘镜像引导加载内核程序
# 教师参考答案
请教师用户首先访问
[
教师项目群组
](
https://www.codecode.net/engintime/os-lab/bonus-lab-answer
)
,申请权限并审核通过后,再
[
domain relative url
](
/engintime/os-lab/bonus-lab-answer/lab02-mission1.git
)
访问本项目的参考答案。
\ No newline at end of file
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论