linux-0.11-操作系统引导
Published on 2024-03-06 11:38 in 分类: 操作系统 with yjw-ada
分类: 操作系统

linux-0.11-操作系统引导

    bootsect.s逐字分析

    _start 部分

    1. 设置数据段(DS)和额外段(ES)寄存器:

      mov	ax, #BOOTSEG
      mov	ds, ax
      mov	ax, #INITSEG
      mov	es, ax
      

      这部分代码将BOOTSEG(0x07c0)值加载到DS寄存器,设置数据段指向引导扇区的原始地址。然后,它将INITSEG(0x9000)值加载到ES寄存器,设置额外段指向内存中的一个新位置,用于临时存储数据。

    2. 复制引导扇区:

      mov	cx, #256
      sub	si, si
      sub	di, di
      rep movsw
      

      这里,代码使用rep movsw指令复制引导扇区的内容。CX寄存器设置为256,表示要复制的字(word)数(512字节/2=256字)。SI(源索引)和DI(目的索引)寄存器被清零,指示复制操作的开始位置。rep movsw会重复执行movsw指令,将数据从DS:SI复制到ES:DI,直到CX减到0。

    3. 跳转到新位置执行代码:

      jmpi	go, INITSEG
      

      使用远跳转(jmpi)到INITSEG段中的go标签开始执行新的代码段。这个指令实际上是将控制权转移给在INITSEG中更高地址空间的代码,为进一步的操作系统加载做准备。

    go 部分

    1. 设置段寄存器:

      go:	mov	ax, cs
      mov	ds, ax
      mov	es, ax
      

      go标签处,首先将当前代码段(CS)的值加载到AX寄存器,然后将这个值赋给数据段(DS)和额外段(ES),确保数据和额外段指向当前执行的代码段。

    2. 设置堆栈段(SS)和堆栈指针(SP):

      mov	ss, ax
      mov	sp, #0xFF00
      

      这里将堆栈段(SS)设置为当前的代码段,并将堆栈指针(SP)设置为0xFF00。这个设置为程序提供了一个堆栈空间,用于存储临时数据和处理函数调用。

    _start部分,程序准备了数据复制的环境并将引导扇区的内容移动到了一个安全的内存位置(INITSEG)。这样做是为了避免后续操作覆盖引导扇区的内容。然后,通过jmpi跳转到go部分,go部分接着对环境进行进一步设置,尤其是为程序的运行配置堆栈环境。这些步骤为加载和执行操作系统的剩余部分做好了准备。

    `
    !
    ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
    ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
    ! versions of linux
    !
    SYSSIZE = 0x3000
    !
    !	bootsect.s		(C) 1991 Linus Torvalds
    !
    ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
    ! iself out of the way to address 0x90000, and jumps there.
    !
    ! It then loads 'setup' directly after itself (0x90200), and the system
    ! at 0x10000, using BIOS interrupts. 
    !
    ! NOTE! currently system is at most 8*65536 bytes long. This should be no
    ! problem, even in the future. I want to keep it simple. This 512 kB
    ! kernel size should be enough, especially as this doesn't contain the
    ! buffer cache as in minix
    !
    ! The loader has been made as simple as possible, and continuos
    ! read errors will result in a unbreakable loop. Reboot by hand. It
    ! loads pretty fast by getting whole sectors at a time whenever possible.
    
    .globl begtext, begdata, begbss, endtext, enddata, endbss
    .text
    begtext:
    .data
    begdata:
    .bss
    begbss:
    .text
    
    SETUPLEN = 4				! nr of setup-sectors
    BOOTSEG  = 0x07c0			! original address of boot-sector
    INITSEG  = 0x9000			! we move boot here - out of the way
    SETUPSEG = 0x9020			! setup starts here
    SYSSEG   = 0x1000			! system loaded at 0x10000 (65536).
    ENDSEG   = SYSSEG + SYSSIZE		! where to stop loading
    
    ! ROOT_DEV:	0x000 - same type of floppy as boot.
    !		0x301 - first partition on first drive etc
    ROOT_DEV = 0x306
    
    entry _start
    _start:
    	mov	ax,#BOOTSEG
    	mov	ds,ax
    	mov	ax,#INITSEG
    	mov	es,ax
    	mov	cx,#256
    	sub	si,si
    	sub	di,di
    	rep
    	movw
    	jmpi	go,INITSEG
    go:	mov	ax,cs
    	mov	ds,ax
    	mov	es,ax
    ! put stack at 0x9ff00.
    	mov	ss,ax
    	mov	sp,#0xFF00		! arbitrary value >>512
    
    ! load the setup-sectors directly after the bootblock.
    ! Note that 'es' is already set up.
    
    load_setup:
    	mov	dx,#0x0000		! drive 0, head 0
    	mov	cx,#0x0002		! sector 2, track 0
    	mov	bx,#0x0200		! address = 512, in INITSEG
    	mov	ax,#0x0200+SETUPLEN	! service 2, nr of sectors
    	int	0x13			! read it
    	jnc	ok_load_setup		! ok - continue
    	mov	dx,#0x0000
    	mov	ax,#0x0000		! reset the diskette
    	int	0x13
    	j	load_setup
    
    ok_load_setup:
    
    ! Get disk drive parameters, specifically nr of sectors/track
    
    	mov	dl,#0x00
    	mov	ax,#0x0800		! AH=8 is get drive parameters
    	int	0x13
    	mov	ch,#0x00
    	seg cs
    	mov	sectors,cx
    	mov	ax,#INITSEG
    	mov	es,ax
    
    ! Print some inane message
    	
    	call read_cursor
    	mov	cx,#2
    	mov	bx,#0x0007		! page 0, attribute 7 (normal, white color)
    	mov	bp,#msg1
    	mov	ax,#0x1301		! write string, move cursor
    	int	0x10
    
    	call read_cursor
    	mov cx, #6
    	mov bx, #0x0009		! page 0, attribute 9(bright blue color)
    	mov bp, #msg1+2
    	mov ax, #0x1301		! write string, move cursor
    	int 0x10
    	
    	call read_cursor
    	mov cx, #18
    	mov bx, #0x0007		! page 0, attribute 7(normal, white color)
    	mov bp, #msg1+8
    	mov ax, #0x1301		! write string, move cursor
    	int 0x10
    
    ! ok, we've written the message, now
    ! we want to load the system (at 0x10000)
    
    	mov	ax,#SYSSEG
    	mov	es,ax		! segment of 0x010000
    	call	read_it
    	call	kill_motor
    
    ! After that we check which root-device to use. If the device is
    ! defined (!= 0), nothing is done and the given device is used.
    ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
    ! on the number of sectors that the BIOS reports currently.
    
    	seg cs
    	mov	ax,root_dev
    	cmp	ax,#0
    	jne	root_defined
    	seg cs
    	mov	bx,sectors
    	mov	ax,#0x0208		! /dev/ps0 - 1.2Mb
    	cmp	bx,#15
    	je	root_defined
    	mov	ax,#0x021c		! /dev/PS0 - 1.44Mb
    	cmp	bx,#18
    	je	root_defined
    undef_root:
    	jmp undef_root
    root_defined:
    	seg cs
    	mov	root_dev,ax
    
    ! after that (everyting loaded), we jump to
    ! the setup-routine loaded directly after
    ! the bootblock:
    
    	jmpi	0,SETUPSEG
    
    ! This routine loads the system at address 0x10000, making sure
    ! no 64kB boundaries are crossed. We try to load it as fast as
    ! possible, loading whole tracks whenever we can.
    !
    ! in:	es - starting address segment (normally 0x1000)
    !
    sread:	.word 1+SETUPLEN	! sectors read of current track
    head:	.word 0			! current head
    track:	.word 0			! current track
    
    read_it:
    	mov ax,es
    	test ax,#0x0fff
    die:	jne die			! es must be at 64kB boundary
    	xor bx,bx		! bx is starting address within segment
    rp_read:
    	mov ax,es
    	cmp ax,#ENDSEG		! have we loaded all yet?
    	jb ok1_read
    	ret
    ok1_read:
    	seg cs
    	mov ax,sectors
    	sub ax,sread
    	mov cx,ax
    	shl cx,#9
    	add cx,bx
    	jnc ok2_read
    	je ok2_read
    	xor ax,ax
    	sub ax,bx
    	shr ax,#9
    ok2_read:
    	call read_track
    	mov cx,ax
    	add ax,sread
    	seg cs
    	cmp ax,sectors
    	jne ok3_read
    	mov ax,#1
    	sub ax,head
    	jne ok4_read
    	inc track
    ok4_read:
    	mov head,ax
    	xor ax,ax
    ok3_read:
    	mov sread,ax
    	shl cx,#9
    	add bx,cx
    	jnc rp_read
    	mov ax,es
    	add ax,#0x1000
    	mov es,ax
    	xor bx,bx
    	jmp rp_read
    
    read_track:
    	push ax
    	push bx
    	push cx
    	push dx
    	mov dx,track
    	mov cx,sread
    	inc cx
    	mov ch,dl
    	mov dx,head
    	mov dh,dl
    	mov dl,#0
    	and dx,#0x0100
    	mov ah,#2
    	int 0x13
    	jc bad_rt
    	pop dx
    	pop cx
    	pop bx
    	pop ax
    	ret
    bad_rt:	mov ax,#0
    	mov dx,#0
    	int 0x13
    	pop dx
    	pop cx
    	pop bx
    	pop ax
    	jmp read_track
    
    read_cursor:
    	push ax
    	push bx
    	mov	ah,#0x03		! read cursor pos
    	xor	bh,bh
    	int	0x10
    	pop bx
    	pop ax
    	ret
    
    !/*
    ! * This procedure turns off the floppy drive motor, so
    ! * that we enter the kernel in a known state, and
    ! * don't have to worry about it later.
    ! */
    kill_motor:
    	push dx
    	mov dx,#0x3f2
    	mov al,#0
    	outb
    	pop dx
    	ret
    
    sectors:
    	.word 0
    
    msg1:
    	.byte 13,10
    	.ascii "Qiunix is loading..."
    	.byte 13,10,13,10
    
    .org 508
    root_dev:
    	.word ROOT_DEV
    boot_flag:
    	.word 0xAA55
    
    .text
    endtext:
    .data
    enddata:
    .bss
    endbss:`
    
    
    posted @   yjw-ada  阅读(42)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
    · C#/.NET/.NET Core优秀项目和框架2025年2月简报
    · Manus爆火,是硬核还是营销?
    · 终于写完轮子一部分:tcp代理 了,记录一下
    · 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
    点击右上角即可分享
    微信分享提示