超详细汇编注释 操作系统实验二 操作系统的引导(哈工大李治军)(二)

简介: 超详细汇编注释 操作系统实验二 操作系统的引导(哈工大李治军)(二)

bootsect.s读入setup.s


首先编写一个 setup.s,该 setup.s 可以就直接拷贝前面的 bootsect.s(还需要简单的调整),然后将其中的显示的信息改为:“Now we are in SETUP”。


和前面基本一样,就不注释了。

entry _start
_start:
  mov ah,#0x03
  xor bh,bh
  int 0x10
  mov cx,#25
  mov bx,#0x0007
  mov bp,#msg2
  mov ax,cs    ! 这里的cs其实就是这段代码的段地址
  mov es,ax
  mov ax,#0x1301
  int 0x10
inf_loop:
  jmp inf_loop
msg2:
  .byte 13,10
  .ascii  "Now we are in SETUP"
  .byte 13,10,13,10
.org 510
boot_flag:
  .word 0xAA55


接下来需要编写 bootsect.s 中载入 setup.s 的关键代码


所有需要的功能在原版 bootsect.s 中都是存在的,我们要做的仅仅是将这些代码添加到新的 bootsect.s 中去。


除了新增代码,我们还需要去掉在 bootsect.s 添加的无限循环。

SETUOLEN=2              ! 读入的扇区数
SETUPSEG=0x07e0         ! setup代码的段地址
entry _start
_start:
    mov ah,#0x03        ! 设置功能号
    xor bh,bh           ! 将bh置0
    int 0x10            ! 返回行号和列号,供显示串用
    mov cx,#52          !要显示的字符串长度
    mov bx,#0x0007      ! bh=0,bl=07(正常的黑底白字)
    mov bp,#msg1        ! es:bp 要显示的字符串物理地址
    mov ax,#0x07c0      ! 将es段寄存器置为#0x07c0
    mov es,ax           
    mov ax,#0x1301      ! ah=13(设置功能号),al=01(目标字符串仅仅包含字符,属性在BL中包含,光标停在字符串结尾处)
    int 0x10            ! 显示字符串
! 将setup模块从磁盘的第二个扇区开始读到0x7e00
load_setup:
    mov dx,#0x0000                  ! 磁头=0;驱动器号=0
    mov cx,#0x0002                  ! 磁道=0;扇区=2
    mov bx,#0x0200                  ! 偏移地址
    mov ax,#0x0200+SETUPLEN         ! 设置功能号;需要读出的扇区数量
    int 0x13                        ! 读磁盘扇区到内存
    jnc ok_load_setup               ! CF=0(读入成功)跳转到ok_load_setup  
    mov dx,#0x0000                  ! 如果读入失败,使用功能号ah=0x00————磁盘系统复位
    mov ax,#0x0000
    int 0x13
    jmp load_setup                  ! 尝试重新读入
ok_load_setup:
    jmpi    0,SETUPSEG              ! 段间跳转指令,跳转到setup模块处(0x07e0:0000)
! 字符串信息
msg1:
    .byte   13,10           ! 换行+回车
    .ascii  "Welcome to the world without assembly language"
    .byte   13,10,13,10     ! 换行+回车
! 将
.org 510
! 启动盘具有有效引导扇区的标志。仅供BIOS中的程序加载引导扇区时识别使用。它必须位于引导扇区的最后两个字节中
boot_flag:
    .word   0xAA55


再次编译

$ make BootImage

有 Error!这是因为 make 根据 Makefile 的指引执行了 tools/build.c,它是为生成整个内核的镜像文件而设计的,没考虑我们只需要 bootsect.s 和 setup.s 的情况。它在向我们要 “系统” 的核心代码。为完成实验,接下来给它打个小补丁。c


build.c 从命令行参数得到 bootsect、setup 和 system 内核的文件名,将三者做简单的整理后一起写入 Image。其中 system 是第三个参数(argv[3])。当 “make all” 或者 “makeall” 的时候,这个参数传过来的是正确的文件名,build.c 会打开它,将内容写入 Image。而 “make BootImage” 时,传过来的是字符串 “none”。所以,改造 build.c 的思路就是当 argv[3] 是"none"的时候,只写 bootsect 和 setup,忽略所有与 system 有关的工作,或者在该写 system 的位置都写上 “0”。


修改工作主要集中在 build.c 的尾部,可长度以参考下面的方式,将圈起来的部分注释掉。



重新编译

$ cd ~/oslab/linux-0.11
$ make BootImage
$ ../run


setup.s获取基本硬件参数


这里把一些难以理解的代码单独列出来


1.获得磁盘参数

这里花了我很长时间,原因是概念没有搞清楚,我觉得老师在实验指导书上写的也不是很清楚,CSDN上都只是草草复制的代码,感觉他们可以压根没有理解这一段。


先来回顾一下上文的一个概念:int 0x41


在PC机中BIOS设定的中断向量表中int 0x41的中断向量位置 (4 ∗ 0 x 41 = 0 x 0000 : 0 x 0104 4*0x41 = 0x0000:0x01044∗0x41=0x0000:0x0104)存放的并不是中断程序的地址,而是第一个硬盘的基本参数表。对于100%兼容的BIOS来说,这里存放着硬盘参数表阵列的首地址0xF000:0E401,第二个硬盘的基本参数表入口地址存于int 0x46中断向量位置处.每个硬盘参数表有16个字节大小.


这段话是重点,我之前误理解为磁盘参数就存放在以0x0000:0x0104为首地址的单元中,总共占16个字节,但实际上,只存了4个字节,里面存放的是磁盘参数表的偏移地址和段地址,也就是上文所说这里存放着硬盘参数表阵列的首地址0xF000:0E401。

lds    si,[4*0x41]

再看这行代码就可以理解了,这里是把0x0000:0x0104单元存放的值(表示硬盘参数表阵列的首地址的偏移地址)赋给si寄存器,把0x0000:0x0106单元存放的值(表示硬盘参数表阵列的首地址的段地址)赋给ds寄存器。


2.参数以十六进制方式显示

先说说浪费我很长时间的我的错误:我想的是一个ASCII码8位,为什么答案里是4位4位输出,这里是搞清楚显示的目的。显示的是存在内存单元里的16进制数,例如某个字(2个字节)中的数值为 019 A 019A019A,我所要显示的不是01和9A表示的ASCII码,而是显示019A本身,所以要4位4位显示。


以十六进制方式显示比较简单。这是因为十六进制与二进制有很好的对应关系(每 4 位二进制数和 1 位十六进制数存在一一对应关系),显示时只需将原二进制数每 4 位划成一组,按组求对应的 ASCII 码送显示器即可。ASCII 码与十六进制数字的对应关系为:0x30 ~ 0x39 对应数字 0 ~ 9,0x41 ~ 0x46 对应数字 a ~ f。从数字 9 到 a,其 ASCII 码间隔了 7h,这一点在转换时要特别注意。为使一个十六进制数能按高位到低位依次显示,实际编程中,需对 bx 中的数每次循环左移一组(4 位二进制),然后屏蔽掉当前高 12 位,对当前余下的 4 位(即 1 位十六进制数)求其 ASCII 码,要判断它是 0 ~ 9 还是 a ~ f,是前者则加 0x30 得对应的 ASCII 码,后者则要加 0x37 才行,最后送显示器输出。以上步骤重复 4 次,就可以完成 bx 中数以 4 位十六进制的形式显示出来。


下面是提供的参考代码

INITSEG  = 0x9000                   ! 参数存放位置的段地址
entry _start
_start:
! 打印 "NOW we are in SETUP"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#25
    mov bx,#0x0007
    mov bp,#msg2
    mov ax,cs
    mov es,ax
    mov ax,#0x1301
    int 0x10
! 获取光标位置
    mov ax,#INITSEG
    mov ds,ax
    mov ah,#0x03
    xor bh,bh
    int 0x10                        ! 返回:dh = 行号;dl = 列号
    mov [0],dx                      ! 存储到内存0x9000:0处
! 获取内存大小
    mov ah,#0x88
    int 0x15                        ! 返回:ax = 从0x100000(1M)处开始的扩展内存大小(KB)
    mov [2],ax                      ! 将扩展内存数值存放在0x90002处(1个字)
! 读第一个磁盘参数表复制到0x90004处
    mov ax,#0x0000
    mov ds,ax
    lds si,[4*0x41]                 ! 把低字(2B)置为偏移地址,高字(2B)置为段地址
    mov ax,#INITSEG
    mov es,ax
    mov di,#0x0004
    mov cx,#0x10                    ! 重复16次,即传送16B
    rep
    movsb                           ! 按字节传送
! 打印前的准备
    mov ax,cs
    mov es,ax
    mov ax,#INITSEG
    mov ds,ax
! 打印"Cursor position:"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#18
    mov bx,#0x0007
    mov bp,#msg_cursor
    mov ax,#0x1301
    int 0x10
! 打印光标位置
    mov dx,[0]
    call    print_hex
! 打印"Memory Size:"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#14
    mov bx,#0x0007
    mov bp,#msg_memory
    mov ax,#0x1301
    int 0x10
! 打印内存大小
    mov dx,[2]
    call    print_hex
! 打印"KB"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#2
    mov bx,#0x0007
    mov bp,#msg_kb
    mov ax,#0x1301
    int 0x10
! 打印"Cyls:" 
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#7
    mov bx,#0x0007
    mov bp,#msg_cyles
    mov ax,#0x1301
    int 0x10
! 打印柱面数   
    mov dx,[4]
    call    print_hex
! 打印"Heads:"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#8
    mov bx,#0x0007
    mov bp,#msg_heads
    mov ax,#0x1301
    int 0x10
! 打印磁头数
    mov dx,[6]
    call    print_hex
! 打印"Sectors:"
    mov ah,#0x03
    xor bh,bh
    int 0x10
    mov cx,#10
    mov bx,#0x0007
    mov bp,#msg_sectors
    mov ax,#0x1301
    int 0x10
    mov dx,[18]
    call    print_hex
inf_loop:
    jmp inf_loop
! 上面的call都转到这里
print_hex:
    mov    cx,#4                    ! dx(16位)可以显示4个十六进制数字
print_digit:
    rol    dx,#4                    ! 取 dx 的高4比特移到低4比特处
    mov    ax,#0xe0f                ! ah = 请求的功能值(显示单个字符),al = 半字节(4个比特)掩码
    and    al,dl                    ! 前4位会被置为0
    add    al,#0x30                 ! 给 al 数字加上十六进制 0x30
    cmp    al,#0x3a                 ! 比较看是否大于数字十
    jl     outp                     ! 是一个不大于十的数字则跳转
    add    al,#0x07                 ! 否则就是a~f,要多加7
outp:
    int    0x10                     ! 显示单个字符
    loop   print_digit              ! 重复4次
    ret                             
! 打印换行回车
print_nl:
    mov    ax,#0xe0d     ! CR
    int    0x10
    mov    al,#0xa     ! LF
    int    0x10
    ret
msg2:
    .byte 13,10
    .ascii "NOW we are in SETUP"
    .byte 13,10,13,10
msg_cursor:
    .byte 13,10
    .ascii "Cursor position:"
msg_memory:
    .byte 13,10
    .ascii "Memory Size:"
msg_cyles:
    .byte 13,10
    .ascii "Cyls:"
msg_heads:
    .byte 13,10
    .ascii "Heads:"
msg_sectors:
    .byte 13,10
    .ascii "Sectors:"
msg_kb:
    .ascii "KB"
.org 510
boot_flag:
    .word 0xAA55


经过漫长的调试,得到如下结果



Memory Size 是 0x3C00KB,算一算刚好是 15MB(扩展内存),加上 1MB 正好是 16MB,看看 Bochs 配置文件 bochs/bochsrc.bxrc:

这些都和上面打出的参数吻合,表示此次实验是成功的。


天道酬勤


实验二总共花费25小时,因为没有汇编基础,花费了大量时间在理解代码上,希望下面的实验可以越做越快吧。

目录
相关文章
|
1月前
|
算法
数据结构实验之操作系统打印机管理器问题
本实验旨在通过实现操作系统中的打印机管理器问题,掌握队列的基本操作如入队、出队等,利用队列的先进先出特性解决先申请先打印的问题。实验包括队列的初始化、入队、出队、打印队列内容等功能,并通过菜单式界面进行交互。实验结果显示基本功能可正常执行,但在连续操作时存在执行失败的情况,需进一步优化。
42 4
|
2月前
|
Linux C语言 iOS开发
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
46 0
|
5月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品体验与功能反馈摘要** 运维人员发现OS Copilot易上手,文档清晰,助其高效排查故障(8/10分)。愿意推荐并参与开源开发。亮点在于知识问答,能快速筛选答案。相较于竞品,优点是新手友好、文档清晰,但功能扩展性待增强。期望增加系统错误排查与解决方案,并集成ECS等,以优化系统安装流程。
阿里云操作系统智能助手OS Copilot实验测评报告
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是针对Linux的智能助手,助力学习、运维及编程。用户界面直观,自然语言交互方便新手。官方文档详尽,但初次配置略复杂,适合学生和开发者。在提高代码编写和调试效率、系统学习上得分高,功能亮点包括代码生成、问答和命令执行。用户期待更多操作系统支持、自动错误分析和系统排查功能。
189 3
|
5月前
|
弹性计算 人工智能 运维
阿里云操作系统智能助手OS Copilot实验测评报告
阿里云操作系统智能助手OS Copilot实验测评报告
115 2
|
5月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot的实验测评报告
OS Copilot 产品体验摘要 用户角色与场景:一位计算机学生使用辅助学习和解决问题,特别是通过代码解释功能加深理解。 易用性与文档:初者可能会觉得有些细节不明确。 帮助程度:用户给予极高评价,对学习帮助大,评分10分,快速定位和解决代码问题,提升学习效率。 推荐与参与:用户愿意推荐给他人。 功能体验:用户尝试了所有功能,对知识问答、辅助编程和命令执行特别感兴趣,尤其是命令执行帮助大。 对比其他产品:OS Copilot优点是便捷、准确。 期望功能:用户希望增加自动报错分析和系统错误排查。 联动体验:用户期待,以实现更全面的工具集。 总结:整体体验积极,用户看好其潜力,期待改进和未来联动。
|
5月前
|
弹性计算 运维 Python
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品测评摘要** - 学生使用,用于学习和编码,发现上手难度较高,指引文档不清晰,特别是Access ID设置和代码复制流程。 - 功能上,评分9分,辅助编程和知识问答功能显著提升了学习效率,减少了错误。 - 愿意推荐,并有兴趣参与开源开发以提升自我。 - 希望增强错误排查,提供具体错误原因和位置。 - 联动ACK智能助手可增强学习效果。 [链接]: https://developer.aliyun.com/topic/instructions-for-os-copilot
|
1月前
|
安全 Linux 数据安全/隐私保护
Vanilla OS:下一代安全 Linux 发行版
【10月更文挑战第30天】
59 0
Vanilla OS:下一代安全 Linux 发行版
|
1月前
|
NoSQL Linux PHP
如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤
本文介绍了如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤。接着,对比了两种常用的 PHP Redis 客户端扩展:PhpRedis 和 Predis,详细说明了它们的安装方法及优缺点。最后,提供了使用 PhpRedis 和 Predis 在 PHP 中连接 Redis 服务器及进行字符串、列表、集合和哈希等数据类型的基本操作示例。
59 4
|
1月前
|
人工智能 安全 Linux