对这次的实验,我已经无力吐槽了,只恨当初没有好好学习计算机组成原理,对BIOS与汇编语言几乎没有什么概念。
但不管怎么说,实验成功完成了,秉着作业开源的原则,现贴出代码如下。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmLygjM48VO3kDN4AzM1MTMvw1Nx8CXxEjMxAjMvw1ckF2bsBXdvwFdl5mLuR2cj5Set1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
一.首先是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);
}