HUST-OS课设

本文最后更新于:2022年2月10日 下午

HUST-操作系统课程设计

任务一

image-20220128174233995

主要参考

《Orange’S:一个操作系统的实现》电子版,老师给的是旧版,内容差太多了,离谱。

环境配置:Ubuntu+NASM+Bochs+freedos

VMware安装Ubuntu虚拟机:

官网下载即可。

安装NASM:

1
apt install nasm

Bochs环境安装与测试:

跟之前的实验差不多。

  • 1.安装Bochs:

    • 方法一:不推荐,安装的bochs没有功能选项的显示

      1
      sudo apt-get install vgabios bochs bochs-x bximage
    • 方法二:官网下载压缩包,下载链接:Bochs x86 ,接下来的过程可能会出各种各样的问题,有些问题在下面的遇到问题中有描述

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      //解压
      tar xvf bochs-2.7.tar.gz

      //进入解压目录
      cd bochs-2.7

      //执行,下面的命令需要gcc环境,若没有,则apt安装,建议用下面的详细版
      ./configure --enable-debugger --enable-disasm

      //详细版的,出现的问题少一些
      ./configure --with-x11 --with-wx --enable-debugger --enable-disasm --enable-all-optimizations --enable-readline --enable-long-phy-address --enable-ltdl-install --enable-idle-hack --enable-plugins --enable-a20-pin --enable-x86-64 --enable-smp --enable-cpu-level=6 --enable-large-ramfile --enable-repeat-speedups --enable-fast-function-calls --enable-handlers-chaining --enable-trace-linking --enable-configurable-msrs --enable-show-ips --enable-debugger-gui --enable-iodebug --enable-logging --enable-assert-checks --enable-fpu --enable-vmx=2 --enable-svm --enable-3dnow --enable-alignment-check --enable-monitor-mwait --enable-avx --enable-evex --enable-x86-debugger --enable-pci --enable-usb --enable-voodoo

      //缺少什么包就去安装
      make

      sudo make install
      //执行,检测是否安装成功
      bochs

      image-20220128230636528

  • 2.创建boot.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	org	07c00h			; 告诉编译器程序加载到7c00处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 16 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h 号中断
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
  • 3.使用nasm编译asm文件
1
nasm boot.asm -o boot.bin
  • 4.执行命令bximage,生成一个虚拟软盘

    image-20220128214250650

  • 5.将bin文件写入img中

1
dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
  • 6.编写bochs的配置文件bochsrc,文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images 需要根据自己本机的路径设置
romimage: file=/usr/os/bochs-2.7/bios/BIOS-bochs-latest
vgaromimage: file=/usr/os/bochs-2.7/bios/VGABIOS-lgpl-latest

# what disk images will be used
floppya: 1_44=a.img, status=inserted

# choose the boot disk.
boot: floppy

# where do we send log messages?
log: bochsout.txt

# disable the mouse
mouse: enabled=0
#书中所给的keyboard配置删掉
  • 7.执行bochs -f bochsrc,将弹出黑色窗口,之后输入6,选择功能6,再输入c,此时执行引导程序,结果如下:

    image-20220128231345001

Bochs中配置freedos:

freedos主要用于提供保护模式下的程序的运行环境,用于运行COM文件。参考链接:Fan Lu’s Blog (fanlumaster.github.io)

  • 1.下载freedos压缩包,直接执行命令wget http://bochs.sourceforge.net/guestos/freedos-img.tar.gz,下载完成后解压即可。

  • 2.进入解压的freedos目录,可以看到存在几个img文件,将其中的a.img改名为freedos.img,并复制到你的工作目录下(就是你写asm的目录)

    image-20220128233224263

  • 3.使用bximage新建一个软盘,名字叫pm.img

  • 4.编写bochsrc配置文件,文件内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    megs:128
    #模拟器的内存

    #下面这两个路径需要自己去看一下对应路径下是否真的有这两个文件,防止路径出错
    romimage:file=/usr/os/bochs-2.7/bios/BIOS-bochs-latest
    #这个是BIOS-bochs-latest的路径,可能不一样
    vgaromimage:file=/usr/os/bochs-2.7/bios/VGABIOS-lgpl-latest
    #注意,这是a
    floppya:1_44=freedos.img,status=inserted
    #注意,这是b。。有人会愚蠢的分不清。。
    floppyb:1_44=pm.img,status=inserted
    #这个是启动软盘,在当前目录下,如果不在当前目录,需要指明路径

    boot:a
    #表示从软盘启动

    log:bochsout.txt
    #日志输出文件

    mouse: enabled=0
    #disable the mouse

  • 5.启动bochs,命令还是bochs -f bochsrc,依然是选择功能6,弹出黑色窗口,然后输入c,这时候我们可以发现,他运行了freedos.img的引导程序,黑色窗口中进入了A:\>的命令行,注意此时,我们的pm.img是空的,没有向其中写入程序,接着在A:\>的命令行中执行命令format.exe b:,来格式化B盘。

image-20220128232306646

  • 6.接下来尝试在pm.img中写入程序,并且该程序可从实模式转到保护模式,在保护模式下,打印一个字符,pmtest1.asm代码如下(参考书源代码),具体代码实现含义在书中有解释,可仔细阅读,pm.inc为直接复制光盘中的源代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    ; ==========================================
    ; pmtest1.asm
    ; 编译方法:nasm pmtest1.asm -o pmtest1.com
    ; ==========================================

    %include "pm.inc" ; 常量, 宏, 以及一些说明

    org 0100h
    jmp LABEL_BEGIN

    [SECTION .gdt]
    ; GDT
    ; 段基址, 段界限 , 属性
    LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
    LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段, 32
    LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
    ; GDT 结束

    GdtLen equ $ - LABEL_GDT ; GDT长度
    GdtPtr dw GdtLen - 1 ; GDT界限
    dd 0 ; GDT基地址

    ; GDT 选择子
    SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
    SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
    ; END of [SECTION .gdt]

    [SECTION .s16]
    [BITS 16]
    LABEL_BEGIN:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0100h

    ; 初始化 32 位代码段描述符
    xor eax, eax
    mov ax, cs
    shl eax, 4
    add eax, LABEL_SEG_CODE32
    mov word [LABEL_DESC_CODE32 + 2], ax
    shr eax, 16
    mov byte [LABEL_DESC_CODE32 + 4], al
    mov byte [LABEL_DESC_CODE32 + 7], ah

    ; 为加载 GDTR 作准备
    xor eax, eax
    mov ax, ds
    shl eax, 4
    add eax, LABEL_GDT ; eax <- gdt 基地址
    mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址

    ; 加载 GDTR
    lgdt [GdtPtr]

    ; 关中断
    cli

    ; 打开地址线A20
    in al, 92h
    or al, 00000010b
    out 92h, al

    ; 准备切换到保护模式
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    ; 真正进入保护模式
    jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
    ; END of [SECTION .s16]


    [SECTION .s32]; 32 位代码段. 由实模式跳入.
    [BITS 32]

    LABEL_SEG_CODE32:
    mov ax, SelectorVideo
    mov gs, ax ; 视频段选择子(目的)

    mov edi, (80 * 10 + 0) * 2 ; 屏幕第 10 行, 第 0 列。
    mov ah, 0Ch ; 0000: 黑底 1100: 红字
    mov al, 'z'
    mov [gs:edi], ax

    ; 到此停止
    jmp $

    SegCode32Len equ $ - LABEL_SEG_CODE32
    ; END of [SECTION .s32]

  • 7.使用命令nasm pmtest1.asm -o pmtest1.com,将asm文件编译成com程序。

  • 8.将pmtest1.com文件复制到pm.img上,若是首次复制,则需先创建一个目录:

    1
    sudo mkdir /mnt/floppy

    随后执行以下命令:

    1
    2
    3
    sudo mount -o loop pm.img /mnt/floppy
    sudo cp pmtest1.com /mnt/floppy/
    sudo umount /mnt/floppy
  • 再次启动bochs,并进入到freedos中,在A:\>命令行中执行B:\pmtest1.com,此时pmtest1.com,程序便运行起来了,完成了GDT表的初始化,实模式转换到保护模式,在保护模式下输出字符z,执行结果如下:

image-20220128232637635

至此,基本环境算是打起来了,中间遇到了太多的问题,花了一整天的时间😭😭

遇到的问题

参考:bochs配置安装 ,只记录了这几个,中间问题太多不想写了。

  • Message: dlopen failed for module ‘x’: file not found

    image-20220128202825748

​ 原因:没有安装bochs-x

​ 解决方法:apt-get install bochs-x

  • ./configure --enable-debugger --enable-disasm执行出错

    image-20220128222707346

​ 原因:缺少相应的包

​ 解决方法:sudo apt-get install build-essential

  • make出错

    image-20220128223202133

​ 解决方法:下面三句几乎将所有需要的都安装了

1
2
3
sudo apt-get install build-essential
sudo apt-get install xorg-dev
sudo apt-get install libgtk2.0-dev
  • make install出错

image-20220128230032093

​ 解决方法:vim .bochsrc,删除第955行

GDT

在IA32下,CPU有两种工作模式,实模式和保护模式,当启动计算后,刚开始是实模式,随后经过某种机制,进入到保护模式。

Intel8086是16位的CPU,有16位的寄存器,16位的数据总线以及20位的地址总线,所以有1MB的寻址能力,在寻址时,分别用两个16位寄存器保存段基址和段偏移,物理地址=段基址*16+段偏移,以此来达到1MB的寻址空间。

从80386开始,Intel的CPU的地址线变为32位,寻址空间变为4GB,但是依然使用的是16位寄存器,显然使用段基址加段偏移的方法,是无法达到4GB的寻址空间的。此时我们改变了段的含义,在保护模式下,段基地址依然使用16位寄存器来保存,只不过这里的段基地址并不对应具体段在内存中的基地址,而是作为一个索引,指向了某个数据结构中的一个表项(数据项),这个表项的内容详细定义了这个端的起始地址,界限,属性等内容,这个数据结构就叫做GDT(Global Descriptor Table,全局描述表,其实就是我们所说的段表),GDT中的每一个表项叫做一个Descriptor(描述符),存储量某个段的信息,一个描述符就对应一个段,可以使数据段,代码段等等。

所以,GDT的作用就是用来提供段式存储机制,这种机制是通过段寄存器(他存储的地址指向段表中某个段的描述符)和GDT中的描述符共同提供的。

每个描述的内部结构:

image-20220129173123365

比如看下面的代码就是GDT的内容,里面有3个描述符,表示3个段(第一个描述符是空描述符,实际只存储了两个段,CODE段和VIDEO段,每个描述符里记录了这个段的段基址,段界限和属性)

1
2
3
4
5
6
7
8
9
10
11
12
13
[SECTION .gdt]
;Descriptor是一个数据结构,在pm.inc中定义了,大小是8字节
; GDT,是一个数组,包括三个Descriptor,每一个描述符定义一个段
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址为0B8000H
; GDT 结束
;GdtLen表示GDT的长度,通过下面的减法计算出来
GdtLen equ $ - LABEL_GDT ; GDT长度
;Gdtptr也是一个数据结构,可以看出大小是6字节,后4字节dd,是GDT的基址
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址

现在我们知道了,每个段的基地址等信息保存在GDT表中,那么我们怎么知道我们当前段的描述符在GDT表中的位置呢,这时候,就用到了一个叫做选择子数据结构,来告诉我们段描述符在GDT表中的位置,如下:

1
2
3
; GDT 选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

这两个变量就分别保存了code段和video段在GDT表中的偏移,根据这两个选择子,就可以找到段在GDT中的描述符。(具体到底怎么用,我很懵逼)。

总之,我们得到逻辑地址后,首先将段地址作为索引,找到该段在GDT表中的描述符,然后得知该段在内存中的真实的段基地址,然后再根据偏移地址,就可以找到物理地址了

image-20220129175526290

chapter3/b/pmtest2.asm尝试

代码复制粘贴就行了😆😆😆

image-20220129200612154

bochsrc中的路径需要改成自己的,Makefile中遇到了问题:

image-20220129200758402

解决方法:参考sudo mount -o loop pm.img /mnt/floppy/mount 错误解决办法

之后make,然后进入bochs和freedos,运行B:\pm.img,成功~:

image-20220129201004351


本文作者: ziyikee
本文链接: https://ziyikee.fun/2022/01/28/HUST-OS%E8%AF%BE%E8%AE%BE/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!