天天看点

操作系统的引导

对这次的实验,我已经无力吐槽了,只恨当初没有好好学习计算机组成原理,对BIOS与汇编语言几乎没有什么概念。

但不管怎么说,实验成功完成了,秉着作业开源的原则,现贴出代码如下。

操作系统的引导

一.首先是bootsect.s文件。完整代码如下:

!
! 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

! 这里是需要修改的代码

	mov	ah,#0x03		! read cursor pos
	xor	bh,bh
	int	0x10
	
	mov	cx,#179       !179是需要显示的字符数目,可以比实际要显示的字符数目大,但不要过大,因为只有512KB,当设置为180多时就会出现错误
	mov	bx,#0x008e     !我在这里设置了字符信息的前景色与背景色,显示效果为闪烁的橙黄色
	mov	bp,#msg1
	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

!/*
! * 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     				!2
	.ascii "***     *** *** *** ***"!23
	.byte 13,10						!2
	.ascii " *       *   *    * *  "!23
	.byte 13,10					    !2
	.ascii " *       *   *    * *  "!23
	.byte 13,10					    !2
	.ascii " *       *****     *   "!23
	.byte 13,10					    !2
	.ascii " *       *   *    * *  "!23
	.byte 13,10					    !2
	.ascii " *       *   *    * *  "!23
	.byte 13,10					    !2
	.ascii "******  *** *** *** ***"!23
	.byte 13,10,13,10               !4

.org 508
root_dev:
	.word ROOT_DEV
boot_flag:
	.word 0xAA55

.text
endtext:
.data
enddata:
.bss
endbss:
           

二.然后是setup.s文件,完整代码如下:

!
!	setup.s		(C) 1991 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! both setup.s and system has been loaded by the bootblock.
!
! This code asks the bios for memory/disk/other parameters, and
! puts them in a "safe" place: 0x90000-0x901FF, ie where the
! boot-block used to be. It is then up to the protected mode
! system to read them from there before the area is overwritten
! for buffer-blocks.
!

! NOTE! These had better be the same as in bootsect.s!

INITSEG  = 0x9000	! we move boot here - out of the way
SYSSEG   = 0x1000	! system loaded at 0x10000 (65536).
SETUPSEG = 0x9020	! this is the current segment

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

entry start
start:

    mov	ax,#SETUPSEG
    mov	es,ax
    mov	ah,#0x03   ! read cursor pos
    xor	bh,bh
    int	0x10

    mov	cx,#25
    mov	bx,#0x0007
    mov	bp,#MSG1
    mov	ax,#0x1301
    int	0x10
! ok, the read went well so we get current cursor position and save it for
! posterity.

	mov	ax,#INITSEG	! this is done in bootsect already, but...
	mov	ds,ax
	mov	ah,#0x03	! read cursor pos
	xor	bh,bh
	int	0x10		! save it in known place, con_init fetches
	mov	[0],dx		! it from 0x90000.
! Get memory size (extended mem, kB)

	mov	ah,#0x88
	int	0x15
	mov	[2],ax

! Get video-card data:

	mov	ah,#0x0f
	int	0x10
	mov	[4],bx		! bh = display page
	mov	[6],ax		! al = video mode, ah = window width

! check for EGA/VGA and some config parameters

	mov	ah,#0x12
	mov	bl,#0x10
	int	0x10
	mov	[8],ax
	mov	[10],bx
	mov	[12],cx

! Get hd0 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x41]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0080
	mov	cx,#0x10
	rep
	movsb

! Get hd1 data

	mov	ax,#0x0000
	mov	ds,ax
	lds	si,[4*0x46]
	mov	ax,#INITSEG
	mov	es,ax
	mov	di,#0x0090
	mov	cx,#0x10
	rep
	movsb








    MOV       AX,#SETUPSEG
    MOV       DS,AX
    MOV       ES,AX
	      mov	ah,#0x03		! read cursor pos
	      xor       bh,bh
	      int       0x10
	
              MOV       CX,#25
              mov       bx,#0x0007      ! page 0, attribute 7 (normal)
              MOV       bp,#MSG2
              MOV       ax,#0X1301		! WRITE STRING, MOVE CURSOR
              INT       0x10
			
              MOV       AX,#INITSEG
              mov       ds,ax   !set the data seg address, even it has been set.
			 	  
              mov       cx,#4
              mov       dx,[0]
     print_digit1:             !print the data
              rol       dx,#4
              mov       ax,#0xe0f
              and       al,dl
              add       al,#0x30
              cmp       al,#0x3a
              jl        outp1
              add       al, #0x07
       outp1:
              int       0x10
              loop      print_digit1
			  
              ! MOV       AX,#SETUPSEG
              ! MOV       DS,AX
              ! MOV       ES,AX

!print size of the extended memory:

              mov	ah,#0x03	! read cursor pos
	      xor       bh,bh
	      int       0x10
		   
              MOV       CX,#37
              mov	bx,#0x0007      ! page 0, attribute 7 (normal)
              MOV       BP,#MSG3
              MOV       AX,#0X1301		! WRITE STRING, MOVE CURSOR
			  
              INT       0X10
	      MOV       AX,#INITSEG
              MOV       DS,AX   !SET THE DATA SEG ADDRESS, EVEN IT HAS BEEN SET.
			 	  
              MOV       CX,#4
              MOV       DX,[2]
            PRINT_DIGIT2:
              ROL       DX,#4
              MOV       AX,#0XE0F
              AND       AL,DL
              ADD       AL,#0X30
              CMP       AL,#0X3A
              JL        OUTP2
              ADD       AL, #0X07
       OUTP2:
              INT       0X10
              LOOP      PRINT_DIGIT2

              mov	ah,#0x03	! read cursor pos
	      xor       bh,bh
	      int       0x10
		   
              MOV       CX,#7
              mov	bx,#0x0007      ! page 0, attribute 7 (normal)
              MOV       BP,#MSG4
              MOV       AX,#0X1301		! WRITE STRING, MOVE CURSOR
			  
              INT       0X10
	      MOV       AX,#INITSEG
              MOV       DS,AX   !SET THE DATA SEG ADDRESS, EVEN IT HAS BEEN SET.
			 	  
              MOV       CX,#4
              MOV       DX,[0x0080]
            PRINT_DIGIT3:
              ROL       DX,#4
              MOV       AX,#0XE0F
              AND       AL,DL
              ADD       AL,#0X30
              CMP       AL,#0X3A
              JL        OUTP3
              ADD       AL, #0X07
       OUTP3:
              INT       0X10
              LOOP      PRINT_DIGIT3

              mov	ah,#0x03	! read cursor pos
	      xor       bh,bh
	      int       0x10
		   
              MOV       CX,#8
              mov	bx,#0x0007      ! page 0, attribute 7 (normal)
              MOV       BP,#MSG5
              MOV       AX,#0X1301		! WRITE STRING, MOVE CURSOR
			  
              INT       0X10
	      MOV       AX,#INITSEG
              MOV       DS,AX   !SET THE DATA SEG ADDRESS, EVEN IT HAS BEEN SET.
			 	  
              MOV       CX,#4
              MOV       DX,[0x0082]
            PRINT_DIGIT4:
              ROL       DX,#4
              MOV       AX,#0XE0F
              AND       AL,DL
              ADD       AL,#0X30
              CMP       AL,#0X3A
              JL        OUTP4
              ADD       AL, #0X07
       OUTP4:
              INT       0X10
              LOOP      PRINT_DIGIT4

              mov	ah,#0x03	! read cursor pos
	      xor       bh,bh
	      int       0x10
		   
              MOV       CX,#10
              mov	bx,#0x0007      ! page 0, attribute 7 (normal)
              MOV       BP,#MSG6
              MOV       AX,#0X1301		! WRITE STRING, MOVE CURSOR
			  
              INT       0X10
	      MOV       AX,#INITSEG
              MOV       DS,AX   !SET THE DATA SEG ADDRESS, EVEN IT HAS BEEN SET.
			 	  
              MOV       CX,#4
              MOV       DX,[0x008E]
            PRINT_DIGIT5:
              ROL       DX,#4
              MOV       AX,#0XE0F
              AND       AL,DL
              ADD       AL,#0X30
              CMP       AL,#0X3A
              JL        OUTP5
              ADD       AL, #0X07
       OUTP5:
              INT       0X10
              LOOP      PRINT_DIGIT5
			  
			  
       	
			  
  
print_nl:    
			  mov       ax,#0xe0d
			  int       0x10
			  mov       al,#0xa
			  int       0x10

	   

MSG1:
    .byte 13,10
	.ascii "We are in setup now"
	.byte 13,10,13,10	
MSG2:
	.byte 13,10
	.ascii "the cursor position is:"
MSG3:
    .byte 13,10
    .ascii "the size of the extended memory is:"
MSG4:
    .byte 13,10
    .ascii "Cyls:"
MSG5:
    .byte 13,10
    .ascii "Heads:"
MSG6:
    .byte 13,10
    .ascii "Sectors:"
.text
endtext:
.data
enddata:
.bss
endbss:           

三.最后是build,c文件:

/*
 *  linux/tools/build.c
 *
 *  (C) 1991  Linus Torvalds
 */

/*
 * This file builds a disk-image from three different files:
 *
 * - bootsect: max 510 bytes of 8086 machine code, loads the rest
 * - setup: max 4 sectors of 8086 machine code, sets up system parm
 * - system: 80386 code for actual system
 *
 * It does some checking that all files are of the correct type, and
 * just writes the result to stdout, removing headers and padding to
 * the right amount. It also writes some system data to stderr.
 */

/*
 * Changes by tytso to allow root device specification
 */

#include <stdio.h>	/* fprintf */
#include <string.h>
#include <stdlib.h>	/* contains exit */
#include <sys/types.h>	/* unistd.h needs this */
#include <sys/stat.h>
#include <linux/fs.h>
#include <unistd.h>	/* contains read/write */
#include <fcntl.h>

/*
 * Changes by falcon<[email protected]> to define MAJOR and MINOR for they
 * are not defined in current linux header file linux/fs.h,I copy it from
 * include/linux/fs.h directly.
 */

#ifndef MAJOR
	#define MAJOR(a) (((unsigned)(a))>>8)
#endif
#ifndef MINOR
	#define MINOR(a) ((a)&0xff)
#endif

#define MINIX_HEADER 32
#define GCC_HEADER 1024

#define SYS_SIZE 0x3000

/*
 * Changes by falcon<[email protected]> to let this kernel Image file boot
 * with a root image file on the first hardware device /dev/hd1, hence, you
 * should prepare a root image file, and configure the bochs with
 * the following lines(please set the ... as suitable info):
 * 	...
 *      floppya: 1_44="Image", status=inserted
 *      ata0-master: type=disk, path="/path/to/rootimage.img", mode=flat ...
 *      ...
 */

#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 1

/* max nr of sectors of setup: don't change unless you also change
 * bootsect etc */
#define SETUP_SECTS 4

#define STRINGIFY(x) #x

void die(char * str)
{
	fprintf(stderr,"%s\n",str);
	exit(1);
}

void usage(void)
{
	die("Usage: build bootsect setup system [rootdev] [> image]");
}

int main(int argc, char ** argv)
{
	int i,c,id;
	char buf[1024];
	char major_root, minor_root;
	struct stat sb;

	if ((argc != 4) && (argc != 5))
		usage();
	if (argc == 5) {
		if (strcmp(argv[4], "FLOPPY")) {
			if (stat(argv[4], &sb)) {
				perror(argv[4]);
				die("Couldn't stat root device.");
			}
			major_root = MAJOR(sb.st_rdev);
			minor_root = MINOR(sb.st_rdev);
		} else {
			major_root = 0;
			minor_root = 0;
		}
	} else {
		major_root = DEFAULT_MAJOR_ROOT;
		minor_root = DEFAULT_MINOR_ROOT;
	}
	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
	if ((major_root != 2) && (major_root != 3) &&
	    (major_root != 0)) {
		fprintf(stderr, "Illegal root device (major = %d)\n",
			major_root);
		die("Bad root device --- major #");
	}
	for (i=0;i<sizeof buf; i++) buf[i]=0;
	if ((id=open(argv[1],O_RDONLY,0))<0)
		die("Unable to open 'boot'");
	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
		die("Unable to read header of 'boot'");
	if (((long *) buf)[0]!=0x04100301)
		die("Non-Minix header of 'boot'");
	if (((long *) buf)[1]!=MINIX_HEADER)
		die("Non-Minix header of 'boot'");
	if (((long *) buf)[3]!=0)
		die("Illegal data segment in 'boot'");
	if (((long *) buf)[4]!=0)
		die("Illegal bss in 'boot'");
	if (((long *) buf)[5] != 0)
		die("Non-Minix header of 'boot'");
	if (((long *) buf)[7] != 0)
		die("Illegal symbol table in 'boot'");
	i=read(id,buf,sizeof buf);
	fprintf(stderr,"Boot sector %d bytes.\n",i);
	if (i != 512)
		die("Boot block must be exactly 512 bytes");
	if ((*(unsigned short *)(buf+510)) != 0xAA55)
		die("Boot block hasn't got boot flag (0xAA55)");
	buf[508] = (char) minor_root;
	buf[509] = (char) major_root;	
	i=write(1,buf,512);
	if (i!=512)
		die("Write call failed");
	close (id);
	
	if ((id=open(argv[2],O_RDONLY,0))<0)
		die("Unable to open 'setup'");
	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
		die("Unable to read header of 'setup'");
	if (((long *) buf)[0]!=0x04100301)
		die("Non-Minix header of 'setup'");
	if (((long *) buf)[1]!=MINIX_HEADER)
		die("Non-Minix header of 'setup'");
	if (((long *) buf)[3]!=0)
		die("Illegal data segment in 'setup'");
	if (((long *) buf)[4]!=0)
		die("Illegal bss in 'setup'");
	if (((long *) buf)[5] != 0)
		die("Non-Minix header of 'setup'");
	if (((long *) buf)[7] != 0)
		die("Illegal symbol table in 'setup'");
	for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
		if (write(1,buf,c)!=c)
			die("Write call failed");
	close (id);
	if (i > SETUP_SECTS*512)
		die("Setup exceeds " STRINGIFY(SETUP_SECTS)
			" sectors - rewrite build/boot/setup");
	fprintf(stderr,"Setup is %d bytes.\n",i);
	for (c=0 ; c<sizeof(buf) ; c++)
		buf[c] = '\0';
	while (i<SETUP_SECTS*512) {
		c = SETUP_SECTS*512-i;
		if (c > sizeof(buf))
			c = sizeof(buf);
		if (write(1,buf,c) != c)
			die("Write call failed");
		i += c;
	}

	if ((id=open(argv[3],O_RDONLY,0))>=0){          //argv[3]为system模块,本实验中并没有用到这个模块,所以这里需要修改
		if (read(id,buf,GCC_HEADER) != GCC_HEADER)
			die("Unable to read header of 'system'");
		if (((long *) buf)[5] != 0)
			die("Non-GCC header of 'system'");
		for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
			if (write(1,buf,c)!=c)
				die("Write call failed");
		close(id);
		fprintf(stderr,"System is %d bytes.\n",i);
		if (i > SYS_SIZE*16)
			die("System is too big");
	}
	return(0);
}




           

继续阅读