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

在上一篇的基础之上,写一个多进程程序:程序切换原理:在定时中断的时候将当前进程的现场保存在当前进程的堆栈中(中断时并自动压入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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值