53.html
来自「linux 0.11中文版 有注释」· HTML 代码 · 共 220 行
HTML
220 行
<html>
<head>
<title>kernel/asm.s</title>
<meta name='robots' content='noindex,nofollow'>
<meta name='generator' content='GLOBAL-5.4.1'>
</head>
<body text='#191970' bgcolor='#f5f5dc' vlink='gray'>
<a name='TOP'><h2><a href='../mains.html'>root</a>/<a href='../files/104.html'>kernel</a>/asm.s</h2>
<i><font color='green'>/* [<][>][^][v][top]<a href='#BOTTOM'>[bottom]</a><a href='../mains.html'>[index]</a><a href='../help.html'>[help]</a> */</font></i>
<hr>
<pre>
<a name='L1'><i><font color='green'>/*</font></i>
<a name='L2'><i><font color='green'>* linux/kernel/asm.s</font></i>
<a name='L3'><i><font color='green'>*</font></i>
<a name='L4'><i><font color='green'>* (C) 1991 Linus Torvalds</font></i>
<a name='L5'><i><font color='green'>*/</font></i>
<a name='L6'>
<a name='L7'><i><font color='green'>/*</font></i>
<a name='L8'><i><font color='green'>* asm.s contains the low-level code for most hardware faults.</font></i>
<a name='L9'><i><font color='green'>* page_exception is handled by the mm, so that isn't here. This</font></i>
<a name='L10'><i><font color='green'>* file also handles (hopefully) fpu-exceptions due to TS-bit, as</font></i>
<a name='L11'><i><font color='green'>* the fpu must be properly saved/resored. This hasn't been tested.</font></i>
<a name='L12'><i><font color='green'>eax = -1</font></i>
<a name='L13'><i><font color='green'>系统中断调用(eax=调用号)</font></i>
<a name='L14'><i><font color='green'>ebx,ecx,edx 中放有调用参数</font></i>
<a name='L15'><i><font color='green'>调用号超范围?</font></i>
<a name='L16'><i><font color='green'>中断返回</font></i>
<a name='L17'><i><font color='green'>寄存器入栈</font></i>
<a name='L18'><i><font color='green'>ds,es 指向内核代码段</font></i>
<a name='L19'><i><font color='green'>fs 指向局部数据段(用户数据)</font></i>
<a name='L20'><i><font color='green'>调用对应的C 处理函数</font></i>
<a name='L21'><i><font color='green'>任务状态?</font></i>
<a name='L22'><i><font color='green'>调用schedule() 时间片=0?</font></i>
<a name='L23'><i><font color='green'>初始任务?</font></i>
<a name='L24'><i><font color='green'>弹出入栈的寄存器</font></i>
<a name='L25'><i><font color='green'>超级用户程序?</font></i>
<a name='L26'><i><font color='green'>用户堆栈?</font></i>
<a name='L27'><i><font color='green'>根据进程信号位图取进程的最</font></i>
<a name='L28'><i><font color='green'>小信号量,调用do signal()</font></i>
<a name='L29'><i><font color='green'>*/</font></i>
<a name='L30'>5.3 asm.s 程序
<a name='L31'>
<a name='L32'><i><font color='green'>/*</font></i>
<a name='L33'><i><font color='green'>* asm.s 程序中包括大部分的硬件故障(或出错)处理的底层次代码。页异常是由内存管理程序</font></i>
<a name='L34'><i><font color='green'>* mm 处理的,所以不在这里。此程序还处理(希望是这样)由于TS-位而造成的fpu 异常,</font></i>
<a name='L35'><i><font color='green'>* 因为fpu 必须正确地进行保存/恢复处理,这些还没有测试过。</font></i>
<a name='L36'><i><font color='green'>*/</font></i>
<a name='L37'>
<a name='L38'><i><font color='green'># 本代码文件主要涉及对Intel 保留的中断int0--int16 的处理(int17-int31 留作今后使用)。</font></i>
<a name='L39'><i><font color='green'># 以下是一些全局函数名的声明,其原形在traps.c 中说明。</font></i>
<a name='L40'>.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
<a name='L41'>.globl _double_fault,_coprocessor_segment_overrun
<a name='L42'>.globl _invalid_TSS,_segment_not_present,_stack_segment
<a name='L43'>.globl _general_protection,_coprocessor_error,_irq13,_reserved
<a name='L44'>
<a name='L45'><i><font color='green'># int0 -- (下面这段代码的含义参见图4.1(a))。</font></i>
<a name='L46'><i><font color='green'># 下面是被零除出错(divide_error)处理代码。标号'_divide_error'实际上是C 语言函</font></i>
<a name='L47'><i><font color='green'># 数divide_error()编译后所生成模块中对应的名称。'_do_divide_error'函数在traps.c 中。</font></i>
<a name='L48'>_divide_error:
<a name='L49'>pushl $_do_divide_error # 首先把将要调用的函数地址入栈。这段程序的出错号为0。
<a name='L50'>no_error_code: # 这里是无出错号处理的入口处,见下面第55 行等。
<a name='L51'>xchgl %eax,(%esp) # _do_divide_error 的地址 ?? eax,eax 被交换入栈。
<a name='L52'>pushl %ebx
<a name='L53'>pushl %ecx
<a name='L54'>pushl %edx
<a name='L55'>pushl %edi
<a name='L56'>pushl %esi
<a name='L57'>pushl %ebp
<a name='L58'>push %ds # !!16 位的段寄存器入栈后也要占用4 个字节。
<a name='L59'>push %es
<a name='L60'>push %fs
<a name='L61'>pushl $0 # "error code" # 将出错码入栈。
<a name='L62'>lea 44(%esp),%edx # 取原调用返回地址处堆栈指针位置,并压入堆栈。
<a name='L63'>pushl %edx
<a name='L64'>movl $0x10,%edx # 内核代码数据段选择符。
<a name='L65'>mov %dx,%ds
<a name='L66'>mov %dx,%es
<a name='L67'>mov %dx,%fs
<a name='L68'>call *%eax # 调用C 函数do_divide_error()。
<a name='L69'>addl $8,%esp # 让堆栈指针重新指向寄存器fs 入栈处。
<a name='L70'>pop %fs
<a name='L71'>pop %es
<a name='L72'>pop %ds
<a name='L73'>popl %ebp
<a name='L74'>popl %esi
<a name='L75'>popl %edi
<a name='L76'>popl %edx
<a name='L77'>popl %ecx
<a name='L78'>popl %ebx
<a name='L79'>popl %eax # 弹出原来eax 中的内容。
<a name='L80'>iret
<a name='L81'>
<a name='L82'><i><font color='green'># int1 -- debug 调试中断入口点。处理过程同上。</font></i>
<a name='L83'>_debug:
<a name='L84'>5.3 asm.s 程序
<a name='L85'>pushl $_do_int3 # _do_debug C 函数指针入栈。以下同。
<a name='L86'>jmp no_error_code
<a name='L87'>
<a name='L88'><i><font color='green'># int2 -- 非屏蔽中断调用入口点。</font></i>
<a name='L89'>_nmi:
<a name='L90'>pushl $_do_nmi
<a name='L91'>jmp no_error_code
<a name='L92'>
<a name='L93'><i><font color='green'># int3 -- 同_debug。</font></i>
<a name='L94'>_int3:
<a name='L95'>pushl $_do_int3
<a name='L96'>jmp no_error_code
<a name='L97'>
<a name='L98'><i><font color='green'># int4 -- 溢出出错处理中断入口点。</font></i>
<a name='L99'>_overflow:
<a name='L100'>pushl $_do_overflow
<a name='L101'>jmp no_error_code
<a name='L102'>
<a name='L103'><i><font color='green'># int5 -- 边界检查出错中断入口点。</font></i>
<a name='L104'>_bounds:
<a name='L105'>pushl $_do_bounds
<a name='L106'>jmp no_error_code
<a name='L107'>
<a name='L108'><i><font color='green'># int6 -- 无效操作指令出错中断入口点。</font></i>
<a name='L109'>_invalid_op:
<a name='L110'>pushl $_do_invalid_op
<a name='L111'>jmp no_error_code
<a name='L112'>
<a name='L113'><i><font color='green'># int9 -- 协处理器段超出出错中断入口点。</font></i>
<a name='L114'>_coprocessor_segment_overrun:
<a name='L115'>pushl $_do_coprocessor_segment_overrun
<a name='L116'>jmp no_error_code
<a name='L117'>
<a name='L118'><i><font color='green'># int15 – 保留。</font></i>
<a name='L119'>_reserved:
<a name='L120'>pushl $_do_reserved
<a name='L121'>jmp no_error_code
<a name='L122'>
<a name='L123'><i><font color='green'># int45 -- ( = 0x20 + 13 ) 数学协处理器(Coprocessor)发出的中断。</font></i>
<a name='L124'><i><font color='green'># 当协处理器执行完一个操作时就会发出IRQ13 中断信号,以通知CPU 操作完成。</font></i>
<a name='L125'>_irq13:
<a name='L126'>pushl %eax
<a name='L127'>xorb %al,%al # 80387 在执行计算时,CPU 会等待其操作的完成。
<a name='L128'>outb %al,$0xF0 # 通过写0xF0 端口,本中断将消除CPU 的BUSY 延续信号,并重新
<a name='L129'><i><font color='green'># 激活80387 的处理器扩展请求引脚PEREQ。该操作主要是为了确保</font></i>
<a name='L130'><i><font color='green'># 在继续执行80387 的任何指令之前,响应本中断。</font></i>
<a name='L131'>movb $0x20,%al
<a name='L132'>outb %al,$0x20 # 向8259 主中断控制芯片发送EOI(中断结束)信号。
<a name='L133'>jmp 1f # 这两个跳转指令起延时作用。
<a name='L134'>1: jmp 1f
<a name='L135'>1: outb %al,$0xA0 # 再向8259 从中断控制芯片发送EOI(中断结束)信号。
<a name='L136'>popl %eax
<a name='L137'>jmp _coprocessor_error # _coprocessor_error 原来在本文件中,现在已经放到
<a name='L138'>5.3 asm.s 程序
<a name='L139'><i><font color='green'># (kernel/system_call.s, 131)</font></i>
<a name='L140'>
<a name='L141'><i><font color='green'># 以下中断在调用时会在中断返回地址之后将出错号压入堆栈,因此返回时也需要将出错号弹出。</font></i>
<a name='L142'><i><font color='green'># int8 -- 双出错故障。(下面这段代码的含义参见图4.1(b))。</font></i>
<a name='L143'>_double_fault:
<a name='L144'>pushl $_do_double_fault # C 函数地址入栈。
<a name='L145'>error_code:
<a name='L146'>xchgl %eax,4(%esp) # error code <-> %eax,eax 原来的值被保存在堆栈上。
<a name='L147'>xchgl %ebx,(%esp) # &function <-> %ebx,ebx 原来的值被保存在堆栈上。
<a name='L148'>pushl %ecx
<a name='L149'>pushl %edx
<a name='L150'>pushl %edi
<a name='L151'>pushl %esi
<a name='L152'>pushl %ebp
<a name='L153'>push %ds
<a name='L154'>push %es
<a name='L155'>push %fs
<a name='L156'>pushl %eax # error code # 出错号入栈。
<a name='L157'>lea 44(%esp),%eax # offset # 程序返回地址处堆栈指针位置值入栈。
<a name='L158'>pushl %eax
<a name='L159'>movl $0x10,%eax # 置内核数据段选择符。
<a name='L160'>mov %ax,%ds
<a name='L161'>mov %ax,%es
<a name='L162'>mov %ax,%fs
<a name='L163'>call *%ebx # 调用相应的C 函数,其参数已入栈。
<a name='L164'>addl $8,%esp # 堆栈指针重新指向栈中放置fs 内容的位置。
<a name='L165'>pop %fs
<a name='L166'>pop %es
<a name='L167'>pop %ds
<a name='L168'>popl %ebp
<a name='L169'>popl %esi
<a name='L170'>popl %edi
<a name='L171'>popl %edx
<a name='L172'>popl %ecx
<a name='L173'>popl %ebx
<a name='L174'>popl %eax
<a name='L175'>iret
<a name='L176'>
<a name='L177'><i><font color='green'># int10 -- 无效的任务状态段(TSS)。</font></i>
<a name='L178'>_invalid_TSS:
<a name='L179'>pushl $_do_invalid_TSS
<a name='L180'>jmp error_code
<a name='L181'>
<a name='L182'><i><font color='green'># int11 -- 段不存在。</font></i>
<a name='L183'>_segment_not_present:
<a name='L184'>pushl $_do_segment_not_present
<a name='L185'>jmp error_code
<a name='L186'>
<a name='L187'><i><font color='green'># int12 -- 堆栈段错误。</font></i>
<a name='L188'>_stack_segment:
<a name='L189'>pushl $_do_stack_segment
<a name='L190'>jmp error_code
<a name='L191'>
<a name='L192'>5.3 asm.s 程序
<a name='L193'><i><font color='green'># int13 -- 一般保护性出错。</font></i>
<a name='L194'>_general_protection:
<a name='L195'>pushl $_do_general_protection
<a name='L196'>jmp error_code
<a name='L197'>
<a name='L198'><i><font color='green'># int7 -- 设备不存在(_device_not_available)在(kernel/system_call.s,148)</font></i>
<a name='L199'><i><font color='green'># int14 -- 页错误(_page_fault)在(mm/page.s,14)</font></i>
<a name='L200'><i><font color='green'># int16 -- 协处理器错误(_coprocessor_error)在(kernel/system_call.s,131)</font></i>
<a name='L201'><i><font color='green'># 时钟中断int 0x20 (_timer_interrupt)在(kernel/system_call.s,176)</font></i>
<a name='L202'><i><font color='green'># 系统调用int 0x80 (_system_call)在(kernel/system_call.s,80)</font></i>
</pre>
<hr>
<a name='BOTTOM'>
<i><font color='green'>/* [<][>][^][v]<a href='#TOP'>[top]</a>[bottom]<a href='../mains.html'>[index]</a><a href='../help.html'>[help]</a> */</font></i>
</body>
</html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?