zoukankan      html  css  js  c++  java
  • 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断。

    要做的工作有两项:设置8259A和建立IDT。

    /*======================================================================*
                                init_8259A
     *======================================================================*/
    PUBLIC void init_8259A()
    {
    	/* Master 8259, ICW1. */
    	out_byte(INT_M_CTL,	0x11);
    	/* Slave  8259, ICW1. */
    	out_byte(INT_S_CTL,	0x11);
    	/* Master 8259, ICW2. 设置 '主8259' 的中断入口地址为 0x20. */
    	out_byte(INT_M_CTLMASK,	INT_VECTOR_IRQ0);
    	/* Slave  8259, ICW2. 设置 '从8259' 的中断入口地址为 0x28 */
    	out_byte(INT_S_CTLMASK,	INT_VECTOR_IRQ8);
    	/* Master 8259, ICW3. IR2 对应 '从8259'. */
    	out_byte(INT_M_CTLMASK,	0x4);
    	/* Slave  8259, ICW3. 对应 '主8259' 的 IR2. */
    	out_byte(INT_S_CTLMASK,	0x2);
    	/* Master 8259, ICW4. */
    	out_byte(INT_M_CTLMASK,	0x1);
    	/* Slave  8259, ICW4. */
    	out_byte(INT_S_CTLMASK,	0x1);
    	/* Master 8259, OCW1.  */
    	out_byte(INT_M_CTLMASK,	0xFF);
    	/* Slave  8259, OCW1.  */
    	out_byte(INT_S_CTLMASK,	0xFF);
    }
    

    out_byte的函数体位于kliba.asm中

    global	out_byte
    global	in_byte
    
    ; ========================================================================
    ;                  void out_byte(u16 port, u8 value);
    ; ========================================================================
    out_byte:
    	mov	edx, [esp + 4]		; port
    	mov	al, [esp + 4 + 4]	; value
    	out	dx, al
    	nop	; 一点延迟
    	nop
    	ret
    
    ; ========================================================================
    ;                  u8 in_byte(u16 port);
    ; ========================================================================
    in_byte:
    	mov	edx, [esp + 4]		; port
    	xor	eax, eax
    	in	al, dx
    	nop	; 一点延迟
    	nop
    	ret
    

    现在,该是把这些中断和异常的处理程序统统添加上的时候了。

    global	divide_error
    global	single_step_exception
    global	nmi
    global	breakpoint_exception
    global	overflow
    global	bounds_check
    ...
    
    	lidt	[idt_ptr]
    
    ...
    ; 中断和异常 -- 异常
    divide_error:
    	push	0xFFFFFFFF	; no err code
    	push	0		; vector_no	= 0
    	jmp	exception
    single_step_exception:
    	push	0xFFFFFFFF	; no err code
    	push	1		; vector_no	= 1
    	jmp	exception
    nmi:
    	push	0xFFFFFFFF	; no err code
    	push	2		; vector_no	= 2
    	jmp	exception
    breakpoint_exception:
    	push	0xFFFFFFFF	; no err code
    	push	3		; vector_no	= 3
    	jmp	exception
    overflow:
    	push	0xFFFFFFFF	; no err code
    	push	4		; vector_no	= 4
    	jmp	exception
    ...
    exception:
    	call	exception_handler
    	add	esp, 4*2	; 让栈顶指向 EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS
    	hlt
    

    异常发生时堆栈的变化情况是,中断或异常发生时eflags、cs、eip已经被压栈,如果有错误码的话,错误码也已经被压栈。

    所以我们对异常处理的总体思想是,如果有错误码,则直接把向量号压栈,然后执行一个函数exception_handler;如果没有错误码,则先在栈中压入一个0xFFFFFFFF,再把向量号压栈并随后执行exception_handler。

    函数exception_hanlder()的原型是这样的:

    void exception_handler(int vec_no,int err_code,int eip,int cs,int eflags);
    

    由于C调用约定是调用者恢复堆栈,所以不用担心exception_handler会破坏堆栈中的eip、cs以及eflags。

    现在我们已经有了异常处理函数,该是设置IDT的时候了。设置IDT的代码放进函数init_prot()中,它也位于protect.c中。protect.c通篇几乎只调用一个函数,就是init_idt_desc(),它用来初始化一个门描述符。其中用到的函数指针类型是这样定义的:

    typedef	void	(*int_handler)	();
    

    在init_prot()中,所有描述符都被初始化成中断门。DA_386IGate表示中断门。

    Intel为我们准备了一个指令叫做ud2,能够产生一个#UD异常。

    编译:

    make image

    运行结果如下:

    一个码农的日常 

    源码

  • 相关阅读:
    AIMS 2013中的性能报告工具不能运行的解决办法
    读懂AIMS 2013中的性能分析报告
    在线研讨会网络视频讲座 方案设计利器Autodesk Infrastructure Modeler 2013
    Using New Profiling API to Analyze Performance of AIMS 2013
    Map 3D 2013 新功能和新API WebCast视频下载
    为Autodesk Infrastructure Map Server(AIMS) Mobile Viewer创建自定义控件
    ADN新开了云计算Cloud和移动计算Mobile相关技术的博客
    JavaScript修改css样式style
    文本编辑神器awk
    jquery 开发总结1
  • 原文地址:https://www.cnblogs.com/joey-hua/p/5418380.html
Copyright © 2011-2022 走看看