过去,有许多讲Linux源代码的资料和书籍,但所讲解的代码都是要在Linux环境下编译的,这给只安装了Windows而又想一睹Linux启动代码的用户带来了极大的不便。监于此,本人将可在Windows编译环境下的编译运行的Linux启动源代码公之于众,以供大家学习、参考。
由于代码是从Linux源代码翻译过来的,且赵炯博士已经注释的十分详细,这里就不再多说了。代码为汇编语言,编译环境为TASM+TLINK。
1。bootsect.asm,这个文件是从bootsect.s翻译过来的,功能相同,我在文件末尾增加了用来调试的error例程。内容为:
code segment
;define the const here
SYSSIZE = 3000h
SETUPLEN = 4 ; nr of setup-sectors
BOOTSEG = 07c0h ; original address of boot-sector
INITSEG = 9000h ; we move boot here - out of the way
SETUPSEG = 9020h ; setup starts here
SYSSEG = 1000h ; system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ; where to stop loading
assume cs:code,ds:code,es:code
start:
mov ax,BOOTSEG
mov ds,ax
mov ax,INITSEG
mov es,ax
mov cx,256
sub si,si
sub di,di
rep movsw
;jump to 0x90000
mov bx,8ff0h
mov ds,bx
mov bx,00h
mov word ptr ds:[bx],offset go
mov word ptr ds:[bx]+2,9000h
mov bx,00h
jmp dword ptr [bx]
go LABEL FAR
mov ax,INITSEG
mov ds,ax
mov es,ax
; put stack at 0x9ff00.
mov ss,ax
mov sp,0FF00h ; arbitrary value >>512
; load the setup-sectors directly after the bootblock.
; Note that 'es' is already set up.
load_setup:
;copy sector 2,3,4,5 code to 0x90200,seg=0x9020
mov dx,0000h ; drive 0, head 0
mov cx,0002h ; sector 2, track 0
mov bx,0200h ; address = 512, in INITSEG
mov ax,0200h+SETUPLEN ; service 2, nr of sectors
int 13h ; read it
jnc ok_load_setup ; ok - continue
mov dx,0000h
mov ax,0000h ; reset the diskette
int 13h
jmp load_setup
ok_load_setup:
; Get disk drive parameters, specifically nr of sectors/track
mov dl,00h
mov ax,0800h ; AH=8 is get drive parameters
int 13h
mov ch,00h
mov sectors,cx
mov ax,INITSEG
mov es,ax
; Print some inane message
mov ah,03h ; read cursor pos
xor bh,bh
int 10h
mov cx,24
mov bx,0007h ; page 0, attribute 7 (normal)
mov bp,offset msg1
mov ax,1301h ; write string, move cursor
int 10h
; 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.
mov ax,root_dev
cmp ax,00h
jne root_defined
mov bx,sectors
mov ax,0208h ; /dev/ps0 - 1.2Mb
cmp bx,15
je root_defined
mov ax,021ch ; /dev/PS0 - 1.44Mb
cmp bx,18
je root_defined
undef_root: ;will loop for ever
jmp undef_root
root_defined:
mov root_dev,ax
; after that (everyting loaded), we jump to
; the setup-routine loaded directly after
; the bootblock:
;jump to 0x90200
mov bx,8ff0h
mov ds,bx
mov bx,00h
mov word ptr ds:[bx],0000h
mov word ptr ds:[bx]+2,9020h
mov bx,00h
jmp dword ptr [bx]
; 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 dw 1+SETUPLEN ; sectors read of current track
head dw 0 ; current head
track dw 0 ; current track
read_it:
mov ax,es
test ax,0fffh
die: jne die ; es must be at 64kB boundary
xor bx,bx ; bx is starting address within segment
mov ax,INITSEG
mov ds,ax
rp_read:
mov ax,es
cmp ax,ENDSEG ; have we loaded all yet?
jb ok1_read
ret
ok1_read:
mov ax,INITSEG
mov ds,ax
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,09h
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,09h
ok2_read:
call read_track
mov cx,ax
add ax,sread
cmp ax,sectors
jne ok3_read
mov ax,01h
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,09h
add bx,cx
jnc rp_read
mov ax,es
add ax,1000h
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,00h
and dx,0100h
mov ah,02h
int 13h
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt:
mov ax,00h
mov dx,00h
int 13h
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,03f2h
mov al,0h
out dx,al
pop dx
ret
;read fail and show error,我自己加的,可以在需要的地方调用以显示信息
error:
mov ax,0b800h
mov es,ax
xor di,di
mov ax,INITSEG
mov ds,ax
mov si,offset strError
mov cx,20
repShow:
lodsb
stosb
mov al,87h
stosb
dec cx
cmp cx,0
jne repShow
ret
;define the vars here
sectors dw 00h
strError db 'ERROR***********ERROR***********'
msg1 db 13,10,'Loading system ...',13,10,13,10
; ROOT_DEV: 0x000 - same type of floppy as boot.
; 0x301 - first partition on first drive etc
ROOT_DEV dw 0
;ROOT_DEV = 0306h
code ends
end start
2。setup.asm,是从setup.s翻译过来的。但这里为16位段的386指令,且我增加了可以输出字符的代码段和数据段。内容为:
P386
jump macro selector,offset
db 0eah ;
dw offset ;
dw selector ;
endm
code segment use16
;define the const
INITSEG = 9000h ; we move boot here - out of the way
SYSSEG = 1000h ; system loaded at 0x10000 (65536).
SETUPSEG = 9020h ; this is the current segment
assume cs:code,ds:code,es:code
start:
mov ax,INITSEG ; this is done in bootsect already, but...
mov ds,ax
mov ah,03h ; read cursor pos
xor bh,bh
int 10h ; save it in known place, con_init fetches
mov ds:[0],dx ; it from 0x90000.
; Get memory size (extended mem, kB)
mov ah,88h
int 15h
mov ds:[2],ax
; Get video-card data:
mov ah,0fh
int 10h
mov ds:[4],bx ; bh = display page
mov ds:[6],ax ; al = video mode, ah = window width
; check for EGA/VGA and some config parameters
mov ah,12h
mov bl,10h
int 10h
mov ds:[8],ax
mov ds:[10],bx
mov ds:[12],cx
; Get hd0 data
mov ax,0000h
mov ds,ax
mov si,0104h ;4*41h
mov ax,INITSEG
mov es,ax
mov di,0080h
mov cx,10h
rep movsb
; Get hd1 data
mov ax,0000h
mov ds,ax
mov si,0118 ;4*46h
mov ax,INITSEG
mov es,ax
mov di,0090h
mov cx,10h
rep movsb
; Check that there IS a hd1 :-)
mov ax,01500h
mov dl,81h
int 13h
jc no_disk1
cmp ah,03h
je is_disk1
no_disk1:
mov ax,INITSEG
mov es,ax
mov di,0090h
mov cx,10h
mov ax,00h
rep stosb
is_disk1:
; now we want to move to protected mode ...
cli ; no interrupts allowed ;
; first we move the system to it's rightful place
mov ax,0000h
cld ; 'direction'=0, movs moves forward
do_move:
mov es,ax ; destination segment
add ax,1000h
cmp ax,9000h
jz end_move
mov ds,ax ; source segment
xor di,di
xor si,si
mov cx,8000h
rep movsw
jmp do_move
; then we load the segment descriptors
end_move:
mov ax,SETUPSEG ; right, forgot this at first. didn't work :-)
mov ds,ax
lidt qword ptr idt_48 ; load idt with 0,0 ;can't run in via cpu ,so mark off
lgdt qword ptr gdt_48 ; load gdt with whatever appropriate
; that was painless, now we enable A20
call empty_8042
mov al,0D1h ; command write
out 64h,al
call empty_8042
mov al,0DFh ; A20 on
out 60h,al
call empty_8042
; well, that went ok, I hope. Now we have to reprogram the interrupts :-(
; we put them right after the intel-reserved hardware interrupts, at
; int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
; messed this up with the original PC, and they haven't been able to
; rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
; which is used for the internal hardware interrupts as well. We just
; have to reprogram the 8259's, and it isn't fun.
mov al,11h ; initialization sequence
out 20h,al ; send it to 8259A-1
dw 00ebh,00ebh ; jmp $+2, jmp $+2
out 0A0h,al ; and to 8259A-2
dw 00ebh,00ebh
mov al,20h ; start of hardware int's (0x20)
out 21h,al
dw 00ebh,00ebh
mov al,28h ; start of hardware int's 2 (0x28)
out 0A1h,al
dw 00ebh,00ebh
mov al,04h ; 8259-1 is master
out 21h,al
dw 00ebh,00ebh
mov al,02h ; 8259-2 is slave
out 0A1h,al
dw 00ebh,00ebh
mov al,01h ; 8086 mode for both
out 21h,al
dw 00ebh,00ebh
out 0A1h,al
dw 00ebh,00ebh
mov al,0FFh ; mask off all interrupts for now
out 21h,al
dw 00ebh,00ebh
out 0A1h,al
; well, that certainly wasn't fun :-(. Hopefully it works, and we don't
; need no steenking BIOS anyway (except for the initial loading :-).
; The BIOS-routine wants lots of unnecessary data, and it's less
; "interesting" anyway. This is how REAL programmers do it.
;
; Well, now's the time to actually move into protected mode. To make
; things as simple as possible, we do no register set-up or anything,
; we let the gnu-compiled 32-bit programs do that. We just jump to
; absolute address 0x00000, in 32-bit protected mode.
mov eax,00000001h
mov cr0,eax
mov ax,0001h ; protected mode (PE) bit
lmsw ax ; This is it;
;jmp offset 0 of segment 8 (cs)
;mov bx,0018h ;jump segment select
;mov ds,bx
;mov bx,00h
;mov word ptr ds:[bx],5000h ;because jump to 00h,then jump to 5000h in sec3 has error,so jump to 5000h dirctly here
;mov word ptr ds:[bx]+2,0008h
;mov bx,00h
;jmp dword ptr [ebx]
jump <0008h>,<0000h> ;now,sec3 use32,all is ok
; This routine checks that the keyboard command queue is empty
; No timeout is used - if this hangs there is something wrong with
; the machine, and we probably couldn't proceed anyway.
empty_8042:
dw 00ebh,00ebh
in al,64h ; 8042 status port
test al,02h ; is input buffer full?
jnz empty_8042 ; yes - loop
ret
;display,can run in protect mode
showMsg:
mov bx,0020h
mov es,bx
xor di,di
mov bx,0010h
mov ds,bx
mov si,offset strShow
mov cx,30
repeat:
lodsb
stosb
mov al,87h
stosb
dec cx
cmp cx,0
jne repeat
;define the vars
strShow db 'SECTOR2***********SECTOR2***********SECTOR2'
idt_48 dw 0,0,0
gdt dw 0,0,0,0 ; dummy
gdt1 dw 7FFFh,0000h,9A00h,00C0h ; granularity=4096, 386
gdt2 dw 7FFFh,0000h,9200h,00C0h ; 128MB
gdt3 dw 07FFh,0fff0h,9208h,00C0h ; for jmp use,base=8fff0h near the 90000h
gdt4 dw 07FFh,08000h,920Bh,00C0h ; for show Message use,base=b8000h,4MB size
; gdt limit=2048, 256 GDT entries
gdt_48 dw 800h,0200h+gdt,09h ; gdt base = 0X9xxxx
code ends
end start
3。setup.asm,是从setup.s翻译过来的。不过,这里有些改动,我把中断0-F分别用自己的函数实现了,并且加入了两个任务,他们通过TSS相互切换。这里的程序已经是32位的了,且声明支持386指令。内容为:
P386
jump macro selector,offset ;for 32 bit jmp
db 0eah ;
dw offset ;
dw 00h
dw selector ;
endm
call32 macro selector,offset ;for 32 bit call
db 09ah
dw offset
dw 00h
dw selector
endm
code segment use32
assume cs:code,ds:code,es:code
public showMsg
public strShow
pg_dir:
start:
mov ax,10h
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax ;setup ss,sp by nomad
mov esp,0ffffffh ;16MB upper
call setup_idt
call setup_gdt ; load gdt with whatever appropriate
mov ax,10h ; reload all the segment registers
mov ds,ax ; after changing gdt. CS was already
mov es,ax ; reloaded in 'setup_gdt'
mov fs,ax
mov gs,ax
xor eax,eax
A20:
inc eax ; check that A20 really IS enabled
mov ds:[000000h],eax ; loop forever if it isn't
cmp ds:[100000h],eax
je A20
;chach 80287
mov eax,cr0 ; check math chip
and eax,80000011h ; Save PG,PE,ET
; "orl $0x10020,%eax" here for 486 might be good
or eax,02h ; set MP
mov cr0,eax
call check_x87
jmp after_page_tables
;check the 80287/80387*******************
check_x87:
fninit
fstsw ax
cmp al,0
je x87 ;no coprocessor: have to set bits
mov eax,cr0
xor eax,06h ;reset MP, set EM
mov cr0,eax
ret
align 2
x87:
db 0DBh,0E4h ;fsetpm for 287, ignored by 387
ret
;setup the interrupt**********************
setup_idt:
lea edx,ignore_int
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
mov ecx,256
rp_sidt:
mov [edi],eax
mov 4[edi],edx
add edi,8
dec ecx
jne rp_sidt
;lidt qword ptr idt_48
;ret
;add 0-9 interrupt for test
add_int0:
lea edx,int_0
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0
mov [edi],eax
mov 4[edi],edx
add_int1:
lea edx,int_1
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*1
mov [edi],eax
mov 4[edi],edx
add_int2:
lea edx,int_2
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*2
mov [edi],eax
mov 4[edi],edx
add_int3:
lea edx,int_3
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*3
mov [edi],eax
mov 4[edi],edx
add_int4:
lea edx,int_4
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*4
mov [edi],eax
mov 4[edi],edx
add_int5:
lea edx,int_5
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*5
mov [edi],eax
mov 4[edi],edx
add_int6:
lea edx,int_6
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*6
mov [edi],eax
mov 4[edi],edx
add_int7:
lea edx,int_7
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*7
mov [edi],eax
mov 4[edi],edx
add_int8:
lea edx,int_8
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*8
mov [edi],eax
mov 4[edi],edx
add_int9:
lea edx,int_9
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*9
mov [edi],eax
mov 4[edi],edx
add_inta:
lea edx,int_a
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0ah
mov [edi],eax
mov 4[edi],edx
add_intb:
lea edx,int_b
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0bh
mov [edi],eax
mov 4[edi],edx
add_intc:
lea edx,int_c
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0ch
mov [edi],eax
mov 4[edi],edx
add_intd:
lea edx,int_d
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0dh
mov [edi],eax
mov 4[edi],edx
add_inte:
lea edx,int_e
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*0eh
mov [edi],eax
mov 4[edi],edx
add_int10:
lea edx,int_10
mov eax,00080000h
mov ax,dx ;selector = 0x0008 = cs
mov dx,8E00h ;interrupt gate - dpl=0, present
lea edi,idt
add edi,8*10h
mov [edi],eax
mov 4[edi],edx
lidt qword ptr idt_48
ret
;setup the GDT***************************
setup_gdt:
lgdt qword ptr gdt_48
ret
;define the page*************************
org 1000h
pg0:
org 2000h
pg1:
org 3000h
pg2:
org 4000h
pg3:
org 5000h
;tmp_floppy_area is used by the floppy-driver*************
;tmp_floppy_area db 1024*1 dup(0)
; interrupt for test
align 2
int_0:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,30h ;30h=0
call ignore_int
pop eax
int_1:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,31h ;31h=1
call ignore_int
pop eax
int_2:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,32h ;32h=2
call ignore_int
pop eax
int_3:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,33h ;33h=3
call ignore_int
pop eax
int_4:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,34h ;34h=4
call ignore_int
pop eax
int_5:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,35h ;35h=5
call ignore_int
pop eax
int_6:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,36h ;36h=6
call ignore_int
pop eax
int_7:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,37h ;37h=7
call ignore_int
pop eax
int_8:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,38h ;38h=8
call ignore_int
pop eax
int_9:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,39h ;39h=9
call ignore_int
pop eax
int_a:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,41h ;41h=A
call ignore_int
pop eax
int_b:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,42h ;42h=B
call ignore_int
pop eax
int_c:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,43h ;43h=C
call ignore_int
pop eax
int_d:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,44h ;44h=D
call ignore_int
pop eax
int_e:
push eax
mov eax,offset int_msg
mov byte ptr [eax]+7,45h ;45h=E
call ignore_int
pop eax
int_10:
push eax
mov eax,offset int_msg
mov word ptr [eax]+7,3130h ;3130h=10h
call ignore_int
pop eax
after_page_tables:
push 0 ; These are the parameters to main :-)
push 0
push 0
push offset L6 ; return address for main, if it decides to.
push offset main
jmp setup_paging
;call setup_paging
;jump <28h>,<0000h> ;jmp to main for 16 bit code
;jump <08h>,<7000h> ;jmp to main for 32 bit code
L6:
push offset strShow
call showMsg
push offset int_msg
call showMsg
jmp L6 ; main should never return here, but
; just in case, we know what happens.
; This is the default interrupt "handler" :-)************
int_msg db 'Unknown interrupt!',01h,01h
align 2
ignore_int:
push eax
push ecx
push edx
push ds
push es
push fs
mov eax,10h
mov ds,ax
mov es,ax
mov fs,ax
push offset int_msg
call showMsg
pop fs
pop es
pop ds
pop edx
pop ecx
pop eax
iret
;Setup_paging*************************
align 2
setup_paging:
mov cx,1024*5 ; 5 pages - pg_dir+4 page tables
xor eax,eax
xor bx,bx
addr:
mov dword ptr ds:[bx],eax
add bx,04h
cmp bx,5000h
jb addr
mov dword ptr [pg_dir],00001007h ; set present bit/user r/w
mov dword ptr [pg_dir]+4,00002007h ; --------- " " ---------
mov dword ptr [pg_dir]+8,00003007h ; --------- " " ---------
mov dword ptr [pg_dir]+12,00004007h ; --------- " " ---------
mov ebx,1000h ;begin at pg0,
mov eax,00000007h
setpage:
mov dword ptr ds:[ebx],eax
add eax,1000h
add ebx,04h
cmp ebx,5000h ;end at the end of pg4,1024*4 page is 4MB*4=16MB DRAM
jb setpage
xor eax,eax
mov cr3,eax
mov eax,cr0
or eax,80000000h
mov cr0,eax
ret
;showMsg. To show some message**********************
org 5550h ;nomad add for main use
showMsg proc near
;save regesters
push ebp
mov ebp,esp
push ebx
push eax
push es
push edi
push ds
push esi
;do show message
mov ax,0020h
mov es,ax
xor edi,edi
mov ax,0010h
mov ds,ax
mov esi,dword ptr ss:[ebp]+8 ;get string address for stack
repeat:
lodsb
mov bl,al
stosb
mov al,87h
stosb
cmp bl,01h
jne repeat
mov eax,8fffffffh ;to delay sometime
delay:
dec eax
jnz delay
;reserve regesters
pop esi
pop ds
pop edi
pop es
pop eax
pop ebx
pop ebp
pop eax ;stdcall
ret
showMsg endp
;define the vars==================================================
org 5600h ;nomad add for main use
strShow db '********Now is in the Protect mode,and PG is enable!**********',01h,01h
align 2
dw 0
idt_48 dw 256*8-1 ; idt contains 256 entries
dd idt
align 2
dw 0
gdt_48 dw 800h
dd gdt ; magic number, but it works for me :^)
;define the idt====================================
org 5800h ;nomad add for later use,idt is 256*8
align 8
idt db 256*8 dup(0) ; idt is uninitialized
;define the gdt====================================
org 6000h ;nomad add for later use,gdt is 256*8
gdt dw 0,0,0,0 ; NULL descriptor
gdt1 dq 00c09a0000000fffh ; 16Mb,code
gdt2 dw 0FFFh,00000h,9200h,00C0h ; 16MB,data, others same as sec2.asm
gdt3 dw 07FFh,0fff0h,9208h,00C0h ; for jmp use,base=8fff0h near the 90000h
gdt4 dw 0004h,08000h,0F20Bh,00C0h ; for show Message use,base=b8000h,16KB size,DPL=3
gdt5 dw 0FFFh,00000h,9200h,00C0h ; 16MB stack for system use
gdt6 dw 128,06C00h,0E900h,0000h ; for tss,system use
gdt7 dw 8*8,06800h,08200h,0000h ; for ldt,8 segment,task 0,DPL=3
gdt8 dw 128,06C80h,0E900h,0000h ; for tss, task 0
gdt9 dw 8*8,06840h,8200h,0000h ; for ldt,8 segment,task 1=task 0+8*8
gdta dw 128,06D00h,0E900h,0000h ; for tss, task 1=task 0+128
;define the ldt====================================
org 6800h ;nomad add for later use,ldt is 128*8=400h
ldt dw 0,0,0FA00h,0 ;dummy,DPL=3
code0 dw 0001h,07100h,0FA00h,00C0h ;code,dpl=3
data0 dw 0001h,07200h,0F200h,00C0h ;data,dpl=3
cGate dw 7080h,00008h,08C00h,0000h ;Gate,go to main,DPL=3
tGate dw 0000h,00030h,0E500h,0000h ;Gate,go to main,DPL=3
org 6840h ;task 1
ldt1 dw 0,0,0,0 ;dummy
code1 dw 0001h,07300h,0BA00h,00C0h ;code,DPL=1
data1 dw 0001h,07400h,0B200h,00C0h ;data,DPL=1
cGate1 dw 7000h,00008h,08C00h,0000h ;Gate,go to main
tGate1 dw 0000h,00030h,0E500h,0000h ;Gate,go to main,DPL=3
;define the TSS====================================
org 6C00h ;for tss 0 is used by system, 6C00h-7000h is 400h=128(80h)*8
tss dd 0 ;back
dd 0FFFFF0h ;esp0,16MB
dw 28h,0 ;ss0
dd 0F0H ;esp1
dw 14h,0 ;ss1
dd 0F0H ;esp2
dw 14h,0 ;ss2
dd 00h ;cr3
dd 00h ;eip
dd ? ;eflasgs
dd ? ;eax
dd ? ;ecx
dd ? ;edx
dd ? ;ebx
dd 0F0h ;esp
dd ? ;ebp
dd ? ;esi
dd ? ;edi
dw 14h,0 ;es
dw 0Ch,0 ;cs
dw 14h,0 ;ss
dw 14h,0 ;ds
dw 14h,0 ;fs
dw 14h,0 ;gs
dw 38h,0 ;ldt
dw 0,0 ;io
db 0ffh
org 6C80h ;for tss 1
dd 0 ;back
dd 0FFFFF0h ;esp0,16MB
dw 28h,0 ;ss0
dd ? ;esp1
dw ?,0 ;ss1
dd ? ;esp2
dw ?,0 ;ss2
dd 00h ;cr3
dd 00h ;eip
dd ? ;eflasgs
dd ? ;eax
dd ? ;ecx
dd ? ;edx
dd ? ;ebx
dd 0F0h ;esp
dd ? ;ebp
dd ? ;esi
dd ? ;edi
dw ?,0 ;es
dw 0Fh,0 ;cs,RING3
dw 17h,0 ;ss,RING3
dw ?,0 ;ds
dw ?,0 ;fs
dw ?,0 ;gs
dw 38h,0 ;ldt
dw 0,0 ;io
db 0ffh
org 6D00h ;for tss 2
dd 0 ;back
dd 0FFFFF0h ;esp0,16MB
dw 28h,0 ;ss0
dd ? ;esp1
dw ?,0 ;ss1
dd ? ;esp2
dw ?,0 ;ss2
dd 00h ;cr3
dd 00h ;eip
dd ? ;eflasgs
dd ? ;eax
dd ? ;ecx
dd ? ;edx
dd ? ;ebx
dd 0F0h ;esp
dd ? ;ebp
dd ? ;esi
dd ? ;edi
dw ?,0 ;es
dw 0Dh,0 ;cs,RPL=1
dw 15h,0 ;ss,RPL=1
dw ?,0 ;ds
dw ?,0 ;fs
dw ?,0 ;gs
dw 48h,0 ;ldt
dw 0,0 ;io
db 0ffh
org 6D80h ;for tss 3
org 6E00h ;for tss 4
org 6E80h ;for tss 5
org 6F00h ;for tss 6
org 6F80h ;for tss 7
;define the main===================================
org 7000h ;nomad add for main function point here
main:
;**use ldt,can easy jmp to task0 and task1*********************
;mov ax,0038h ;gdt7 for task0,ldt
;lldt ax
;jump 000Ch,0000h
;call32 000ch,0000h
;org 7080h ;task1
;mov ax,0048h ;gdt9 for task1
;lldt ax
;jump 000Ch,0000h
;**use retf of call from stack,can change from ring0 to ring3**
;mov ax,0038h ;gdt7 for task0,ldt
;lldt ax
;push 0017h ;ss,RPL=3
;push 00F0h ;esp
;push 000Fh ;cs,RPL=3
;push 0000h ;eip
;retf ;can't use ret
;**can chang task use tss,from ring0 to ring3******************
mov ax,0030h ;tss for system
ltr ax
redo:
jump 0040h,0000h
jump 0050h,0000h
jmp redo
;task 0************************************
org 7100h ;code
task0:
mov ax,0020h
mov es,ax
xor edi,edi
mov ax,0014h
mov ds,ax
xor esi,esi
repeat0:
lodsb
mov bl,al
stosb
mov al,87h
stosb
cmp bl,01h
jne repeat0
mov eax,8fffffffh ;to delay sometime
delay0:
dec eax
jnz delay0
;jump 0024h,0000h ;to ldt sel
jump 0030h,0000h ;jmp to main tss
jmp task0
org 7200h ;data and stack
strTask0 db 'There is the task 0 ! ',01h,01h
;task 1************************************
org 07300h ;code
task1:
mov ax,0020h
mov es,ax
xor edi,edi
mov ax,0014h
mov ds,ax
xor esi,esi
repeat1:
lodsb
mov bl,al
stosb
mov al,87h
stosb
cmp bl,01h
jne repeat1
mov eax,8fffffffh ;to delay sometime
delay1:
dec eax
jnz delay1
jump 0024h,0000h ;to ldt sel
jmp task1
org 07400h;data and stack
strTask1 db 'There is the task 1++++',01h,01h
code ends ;so the sec3's code is 7000h,equel 28 sectors,and main will begin from 7000h
end start
我在setup.asm中加入了两个任务,并用TSS切换他们之间的运行。于是可以在屏幕上交替输出“There is the task 1++++”和“There is the task 0 !”字符串