您的位置:首页 > 运维架构 > Linux

操作系统实现----多进程(无特权级转移)

2013-12-18 19:47 309 查看
在上一篇的基础之上,写一个多进程程序:程序切换原理:在定时中断的时候将当前进程的现场保存在当前进程的堆栈中(中断时并自动压入eflag,cs,eip,因为没有特权级的转变,所以也没有堆栈的切换),然后将栈设为目标进程的堆栈,并弹出该进程现场,中断最后的iret指令会将程序接着目标进程的eip运行。

kernel.s因为将所有的段偏移设为0,所以编程时地址的处理非常容易。

boot.s

%define KERNEL_SEG 0x1000 ;内核开始运行的段位置
%define KERNEL_LEN 20 ;内核扇区所占数目

org 0x7c00

mov ax,cs
mov ds,ax
mov es,ax

mov ax,msg
mov bp,ax
mov ax,0x1301
mov bx,0x000c
mov cx,msgLen
mov dx,0x0000
int 10h;

load:
mov ax,KERNEL_SEG
mov es,ax
mov ah,02
mov al,KERNEL_LEN
xor bx,bx
mov ch,0
mov cl,2
mov dh,0
mov dl,0
int 13h

movKernel:
mov ax,KERNEL_SEG
mov ds,ax
xor ax,ax
mov es,ax
xor si,si
xor di,di
mov cx,KERNEL_LEN * 512
cli
copy:
mov al,[ds:si]
mov [es:di],al
inc si
inc di
loop copy

jmp 0:0

msg: db "Loading kernel"
msgLen equ $-msg

times 510-($-$$) db 0
dw 0xaa55

kernel.s:

%define STACK_LEN 1024		;内核栈空间、进程栈空间大小

jmp start
;gdt
gdt:	db 0,0,0,0,0,0,0,0
gdt_cs:	db 0xff,0x7,0,0,0,0x9a,0xc0,0
gdt_ds:	db 0xff,0x7,0,0,0,0x92,0xc0,0
gdt_gs:	db 0x02,0,0,0x80,0x0b,0x92,0xc0,0

gdtLen equ $-gdt

selector_cs equ gdt_cs - gdt
selector_ds equ gdt_ds - gdt
selector_gs equ gdt_gs - gdt

gdtPtr:
dw	gdtLen - 1
dd	gdt

idt:
%rep 8
dw 	intHandler	;offset
dw	selector_cs	;selector
dw	0x8e00		;property
dw	0			;offset
%endrep
dw 	timeInt		;offset
dw	selector_cs	;selector
dw	0x8e00		;property
dw	0			;offset
%rep 256-9
dw 	intHandler	;offset
dw	selector_cs	;selector
dw	0x8e00		;property
dw	0			;offset
%endrep

idtLen	equ $ - idt

idtPtr:
dw	idtLen - 1
dd	idt

start:
mov ax,cs
mov ds,ax
mov es,ax

lgdt [gdtPtr]

cli

lidt [idtPtr]

in al,0x92
or al,00000010b
out 0x92,al

mov eax,cr0
or eax,1
mov cr0,eax

jmp selector_cs:start_32

[bits 32]
start_32:
mov ax,selector_ds
mov ds,ax			;数据段初始化
mov ss,ax			;堆栈段初始化
mov esp,stack_top	;堆栈栈底

mov ah,0x0c
mov al,'P'
call dis_str
int 0x80
int 0x80

mov al,0x36		;控制字:通道0工作方式3、计数初值采用二进制
out 0x43,al
mov ax,11930	;频率为100hz
out 0x40,al		;低位
mov al,ah
out 0x40,al		;高位

sti

;初始化两个进程,主要是进程对应的堆栈区,事先要压入现场信息
;初始化进程1的堆栈
mov ax,selector_ds
mov ss,ax			;堆栈段初始化
mov esp,stack_top_1	;堆栈栈底

pushf
push dword selector_cs		;push cs
push dword task_1			;push eip

push ds
push es
push fs
push gs
pushad
mov [stack_1],esp		;保存进程1现在的栈指针

;初始化进程0的堆栈
mov ax,selector_ds
mov ss,ax			;堆栈段初始化
mov esp,stack_top_0	;堆栈栈底

mov [stack_0],esp	;进程0的堆栈指针

pushf
push dword selector_cs		;push cs
push dword task_0			;push eip

iret		;启动进程0

jmp $		;等待时钟中断去切换执行两个任务
;
dis_str:
push ebx
mov bx,selector_gs
mov gs,bx
mov bx,selector_ds
mov ds,bx
mov ebx,[cursor_i]
shl ebx,1
mov [gs:ebx],ax
shr ebx,1
inc ebx
cmp ebx,80*25
jne .1
mov ebx,0
.1:	mov [cursor_i],ebx
pop ebx
ret

intHandler:
iret
mov ah,0x0c
mov al,'I'
call dis_str
mov al,'n'
call dis_str
mov al,'t'
call dis_str
;	mov al,0x20			;发送EOI 	;为什么这些中断不需要写这句话?
;	out 0x20,al			;中断处理结束,要是没有这一句的话,只能响应中断一次
iret

timeInt:
push ds
push es
push fs
push gs
pushad
;由于已经保存了现场,这些寄存器可以使用了
;切换到内核空间
mov	ax,selector_ds
mov ds,ax
mov al,[process_now]
cmp al,0

jne	j1
;如果是进程0
mov [stack_0],esp	;保存进程0的堆栈指针
mov al,1
mov [process_now],al
mov ax,selector_ds
mov ss,ax			;切换到进程1的堆栈
mov esp,[stack_1]	;
jmp j2
j1:
;如果是进程1
mov [stack_1],esp
mov al,0
mov [process_now],al
mov ax,selector_ds
mov ss,ax			;
mov esp,[stack_0]	;切换到进程0的堆栈,
j2:	mov al,0x20			;发送EOI
out 0x20,al			;中断处理结束,要是没有这一句的话,只能响应中断一次

;将目标进程的现场回复
popad	;popad 将通用寄存器弹出(除了esp)
pop gs
pop fs
pop es
pop ds

iret

task_0:
loo:
mov ah,0x0c
mov al,'A'
call dis_str
mov ecx,0xfffff		;delay
loop $
jmp loo
task_1:
loo2:
mov ah,0x0b
mov al,'B'
call dis_str
mov ecx,0xfffff		;delay
loop $
jmp loo2

data_label:
cursor_i dd 80		;显示屏幕位置
process_now	db	0	;当前运行进程
stack_0	dd	0		;0进程的栈指针
stack_1	dd	0		;1进程的栈指针

times STACK_LEN db 0
stack_top:		;内核栈底
times STACK_LEN db 0
stack_top_0:	;进程0使用的堆栈
times STACK_LEN db 0
stack_top_1:	;进程1使用的堆栈

times (512*20 - ($-$$)) db 0

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐