HIT_OS_LAB3 操作系统的引导

操作系统实验三

3.1. 实验目的

  • 熟悉实验环境;
  • 建立对操作系统引导过程的深入认识;
  • 掌握操作系统的基本开发过程;
  • 能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱。

3.2. 实验内容

3.2.1. 改写 bootsect.s 主要完成如下功能:

bootsect.s 可以在屏幕上输出提示信息
输出语句“BDSOS is booting…”
检查bootsect.s,以下代码用于打印信息

ljmp    $BOOTSEG, $_start  
_start:  
    mov $0x03,%ah  
    xor %bh,%bh  
    int $0x10  
	mov	$24, %cx
	mov	$0x0007, %bx		# page 0, attribute 7 (normal)
	#lea	msg1, %bp
	mov     $msg1, %bp
	mov	$0x1301, %ax		# write string, move cursor
	int	$0x10
    msg1:
	.byte 13,10
	.ascii "Loading system ..."
	.byte 13,10,13,10 
.org 510  
boot_flag:  
    .word   0xAA55  

因此,对bootsect.s的内容进行修改,使其输出所需的信息,然后删除其余代码,最终,bootsect.s的完整内容如下:

.code16  
.global _start   
.equ SETUPLEN, 4		# nr of setup-sectors  
.equ BOOTSEG, 0x07c0		# original address of boot-sector  
.equ INITSEG, 0x9000		# we move boot here - out of the way  
.equ SETUPSEG, 0x9020		# setup starts here  
.equ ROOT_DEV, 0x301  
ljmp    $BOOTSEG, $_start  
_start:  
 mov $0x03,%ah  
 xor %bh,%bh  
 int $0x10  
 mov $31,%cx  
 mov $0x0007,%bx  
 mov $msg1,%bp  
 mov $0x07c0,%ax  
 mov %ax,%es  
 mov $0x1301,%ax  
 int $0x10  
msg1:  
 .byte 13,10  
 .ascii "BDSOS is booting..."  
 .byte 13,10,13,10  
.org 510  
boot_flag:  
 .word   0xAA55 

最后,编译文件并执行,结果如下图,显示bootsect.s的修改是正确的,成功输出语句“BDSOS is booting…”
HIT_OS_LAB3 操作系统的引导_第1张图片

3.2.2. 改写 setup.s 主要完成如下功能:

首先,确保setup.s能够向屏幕输出信息,这个功能已经在前一个问题中在bootsect.s中完成,因此,将相应代码复制到setup.s中,然后删除多余代码,完整的setup.s代码如下:

       .code16
       .equ SETUPSEG, 0x9020
       .global _start
       ljmp $SETUPSEG, $_start	
       _start:
           mov $0x03,%ah
           xor %bh,%bh
           int $0x10
           mov $25,%cx
           mov $0x0007,%bx
           mov $msg2,%bp
           mov $0x07c0,%ax
           mov %cs,%ax
           mov %ax,%es
           mov $0x1301,%ax
           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的内容,找到以下代码实现了这个功能:

        load_setup:
        	mov	$0x0000, %dx		# drive 0, head 0
        	mov	$0x0002, %cx		# sector 2, track 0
        	mov	$0x0200, %bx		# address = 512, in INITSEG
        	.equ    AX, 0x0200+SETUPLEN
        	mov     $AX, %ax		# service 2, nr of sectors
        	int	$0x13			# read it
        	jnc	ok_load_setup		# ok - continue
        	mov	$0x0000, %dx
        	mov	$0x0000, %ax		# reset the diskette
        	int	$0x13
        	jmp	load_setup
        ok_load_setup:
    	    ljmp	$SETUPSEG, $0

因此,对bootsect.s的代码进行修改,首先加载setup.s,然后显示语句“BDSOS is booting…”,最后跳转至setup.s。完成这些功能并删除多余代码后,bootsect.s的完整代码如下:

   	.code16
       	.equ SETUPLEN, 2		# nr of setup-sectors
       	.equ BOOTSEG, 0x07c0		# original address of boot-sector
       	.equ INITSEG, 0x9000		# we move boot here - out of the way
       	.equ SETUPSEG, 0x9020		# setup starts here
       	.equ ROOT_DEV, 0x301
       	ljmp    $BOOTSEG, $_start
       _start:
       	mov	$BOOTSEG, %ax
       	mov	%ax, %ds
       	mov	$INITSEG, %ax
       	mov	%ax, %es
       	mov	$256, %cx
       	sub	%si, %si
       	sub	%di, %di
       	rep	
       	movsw

       load_setup:
       	mov	$0x0000, %dx		# drive 0, head 0
       	mov	$0x0002, %cx		# sector 2, track 0
       	mov	$0x0200, %bx		# address = 512, in INITSEG
       	.equ    AX, 0x0200+SETUPLEN
       	mov     $AX, %ax		# service 2, nr of sectors
       	int	$0x13			# read it
       	jnc	ok_load_setup		# ok - continue
       	mov	$0x0000, %dx
       	mov	$0x0000, %ax		# reset the diskette
       	int	$0x13
       	jmp	load_setup

       ok_load_setup:
       	mov	$0x03, %ah		# read cursor pos
       	xor	%bh, %bh
       	int	$0x10
       	mov	$31, %cx
       	mov	$0x0007, %bx		# page 0, attribute 7 (normal)
       	mov     $msg1, %bp
       	mov	$0x1301, %ax		# write string, move cursor
       	int	$0x10
       	ljmp	$SETUPSEG, $0

       msg1:
       	.byte 13,10
       	.ascii "BDSOS is booting..."
       	.byte 13,10,13,10
       	.org 508
       root_dev:
       	.word ROOT_DEV
       boot_flag:
       	.word 0xAA55

最后,编译文件并执行,结果如下图,bootsect.s和setup.s的修改是正确的,成功显示语句“Now we are in SETUP”
HIT_OS_LAB3 操作系统的引导_第2张图片

setup.s 可以获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存储在内存的特定地址,并在屏幕上输出。
在保持setup.s原有功能不变的同时,使其能够读取硬件参数。首先,在原setup.s文件中,有以下代码可以读取各项硬件信息:

        mov	$INITSEG, %ax	# get Cursor Poser
	    mov	%ax, %ds
	    mov	$0x03, %ah	
	    xor	%bh, %bh
	    int	$0x10		
	    mov	%dx, %ds:0      # get Memory Size
    	mov	$0x88, %ah 
	    int	$0x15
	    mov	%ax, %ds:2
	    mov	$0x0000, %ax        # get hd0 data
	    mov	%ax, %ds
	    lds	%ds:4*0x41, %si
	    mov	$INITSEG, %ax
	    mov	%ax, %es
	    mov	$0x0004, %di
	    mov	$0x10, %cx
	    rep
	    movsb

但是,读取出的数以无符号整数形式存在,需要对这些数进行处理,以十六进制形式显示。可以通过以下函数完成这个操作:

       print_hex:
           mov    $4,%cx
       print_digit:
           rol    $4,%dx
           mov    $0xe0f,%ax  
           and    %dl,%al  
           add    $0x30,%al
           cmp    $0x3a,%al
           jl     outp  
           add    $0x07,%al  
       outp:
           int    $0x10
           loop   print_digit
           ret
       print_nl:
           mov    $0xe0d,%ax
           int    $0x10
           mov    $0xa,%al
           int    $0x10
           ret

然后,结合以上两点信息,使setup.s在显示"Now we are in SETUP"之后,进一步打印"Memory Size:"、内存大小、“KB”、"Cursor Poser:"等信息,以满足要求。完整的setup.s代码如下:

       .code16
       .equ SETUPSEG, 0x9020	# this is the current segment
       .equ INITSEG, 0x9000	# we move boot here - out of the way
       .global _start
       ljmp $SETUPSEG, $_start	
       _start:
           mov $0x03,%ah       # print "Now we are in SETUP"
           xor %bh,%bh
           int $0x10
           mov $25,%cx
           mov $0x0007,%bx
           mov $msg2,%bp       
           mov $0x07c0,%ax
           mov %cs,%ax
           mov %ax,%es
           mov $0x1301,%ax
           int $0x10
       	mov	$INITSEG, %ax	# get Cursor Poser
       	mov	%ax, %ds
       	mov	$0x03, %ah	
       	xor	%bh, %bh
       	int	$0x10		
       	mov	%dx, %ds:0
       	mov	$0x88, %ah      # get memory size
       	int	$0x15
       	mov	%ax, %ds:2
           mov $0x03,%ah       # print "Memory Size:"
           xor %bh,%bh
           int $0x10
           mov $12,%cx
           mov $0x0007,%bx
           mov $msg3,%bp
           mov $0x1301,%ax
           int $0x10
       	mov	%ds:2 , %dx     # print memory size
           call print_hex
           mov $0x03,%ah       # print "KB"
           xor %bh,%bh
           int $0x10
           mov $2,%cx
           mov $0x0007,%bx
           mov $msg4,%bp
           mov $0x1301,%ax
           int $0x10
           call print_nl 
           mov $0x03,%ah       # print "Memory Size:"
           xor %bh,%bh
           int $0x10
           mov $12,%cx
           mov $0x0007,%bx
           mov $msg8,%bp
           mov $0x1301,%ax
           int $0x10
       	mov	%ds:0 , %dx     # print memory size
           call print_hex
           call print_nl
           mov $0x03,%ah       # print "Cylinders:"
           xor %bh,%bh
           int $0x10
           mov $10,%cx
           mov $0x0007,%bx
           mov $msg5,%bp
           mov $0x1301,%ax
           int $0x10
       	mov	$0x0000, %ax        # get hd0 data
       	mov	%ax, %ds
       	lds	%ds:4*0x41, %si
       	mov	$INITSEG, %ax
       	mov	%ax, %es
       	mov	$0x0004, %di
       	mov	$0x10, %cx
       	rep
       	movsb
       	mov	$INITSEG, %ax       # print Cylinders
       	mov	%ax, %ds
       	mov	%ds:4 , %dx     
           call print_hex
           call print_nl
           mov $0x03,%ah       # print "Headers:"
           xor %bh,%bh
           int $0x10
           mov $8,%cx
           mov $0x0007,%bx
           mov $msg6,%bp       
           mov $0x07c0,%ax
           mov %cs,%ax
           mov %ax,%es
           mov $0x1301,%ax
           int $0x10
       	mov	$INITSEG, %ax       # print Headers
       	mov	%ax, %ds
       	mov	%ds:6 , %dx     
           call print_hex
           call print_nl
           mov $0x03,%ah       # print "Sectors Per Track:"
           xor %bh,%bh
           int $0x10
           mov $18,%cx
           mov $0x0007,%bx
           mov $msg7,%bp
           mov $0x1301,%ax
           int $0x10
       	mov	$INITSEG, %ax       # print Sectors Per Track
       	mov	%ax, %ds
       	mov	%ds:18 , %dx     
           call print_hex
           call print_nl
       inf_loop:
           jmp inf_loop
       print_hex:
           mov    $4,%cx
       print_digit:
           rol    $4,%dx
           mov    $0xe0f,%ax  
           and    %dl,%al  
           add    $0x30,%al
           cmp    $0x3a,%al
           jl     outp  
           add    $0x07,%al  
       outp:
           int    $0x10
           loop   print_digit
           ret
       print_nl:
           mov    $0xe0d,%ax   
           int    $0x10
           mov    $0xa,%al    
           int    $0x10
           ret
       msg2:
           .byte   13,10
           .ascii "Now we are in SETUP"
           .byte   13,10,13,10
       msg3:
           .ascii "Memory Size:"
       msg4:
           .ascii "KB"
       msg5:
           .ascii "Cylinders:"
       msg6:
           .ascii "Headers:"
       msg7:
           .ascii "Sectors Per Track:"
       msg8:
           .ascii "Cursor Pose:"
       .org 510
       boot_flag:
           .word   0xAA55

最后,编译文件并执行,结果如下图。
HIT_OS_LAB3 操作系统的引导_第3张图片

  • 成功显示信息“Memory Size:3C00KB”。表明3C00KB即为15MB,又有15MB+1MB=16MB。查看bochs配置文件bochs/bochsrc.bxrc,发现有"megs: 16",则配置的bochs为16MB内存,所以这项信息正确。
  • 成功显示信息“Cursor Poser:1800”,光标位置为1800,也是正确的。
  • 成功显示信息“Cylinders:00cc”、“Headers:0010”、“Sectors Per Track:0026”。查看bochs配置文件bochs/bochsrc.bxrc,发现有“ata0-master: type=disk, path=“$OSLAB_PATH/hdc-0.11.img”, mode=flat, cylinders=204, heads=16, spt=38”,设定的cylinders=204=0x00CC,heads=16=0x0010,spt(Sectors Per Track)=38=0x0026,与所显示的信息相符,因此这几项信息也是正确的。

3.3. 实验报告

有时,继承传统意味着别手蹩脚。 x86 计算机为了向下兼容,导致启动过程比较复杂。 请找出 x86 计算机启动过程中,被硬件强制,软件必须遵守的两个“多此一举”的步骤(多找几个也无妨),说说它们为什么多此一举,并设计更简洁的替代方案。

实模式和保护模式切换:

  • 初始时,x86处理器以实模式运行,这是旧版处理器的工作模式。为了支持现代操作系统,处理器在启动后需要切换到保护模式。这一切换包括加载新的段描述符、设置新的全局描述符表(GDT)和禁用一些过时的实模式特性。
  • 实模式是为老软件和硬件设计的,而保护模式提供更强大和安全的特性。然而,切换过程增加了启动的复杂性,而在现代系统中,实模式的许多特性是多余的。
  • 直接从启动时开始在保护模式下运行,省略实模式和保护模式的切换,以简化启动过程。

BIOS中断调用:

  • 在启动过程中,操作系统通常需要与硬件交互。在x86中,传统方式是通过调用BIOS中断请求服务,例如,读取键盘输入、显示字符等。这导致了对中断向量表的依赖,增加了复杂性。
  • 随着计算机硬件和操作系统的发展,直接调用硬件驱动程序或使用更现代的接口方式可以更高效地进行硬件交互。
  • 直接使用现代的硬件抽象层和驱动程序模型,避免对BIOS中断的依赖。通过在内核中嵌入适当的驱动程序,而不是依赖BIOS中断调用,可以更为简洁地实现相同的功能。

你可能感兴趣的:(OS实验,c#,开发语言)