⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 77.html

📁 linux 0.11中文版 有注释
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<html>
<head>
<title>kernel/system_call.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>/system_call.s</h2>
<i><font color='green'>/* [&lt;][&gt;][^][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/system_call.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'>* system_call.s contains the system-call low-level handling routines.</font></i>
<a name='L9'><i><font color='green'>* This also contains the timer-interrupt handler, as some of the code is</font></i>
<a name='L10'><i><font color='green'>* the same. The hd- and flopppy-interrupts are also here.</font></i>
<a name='L11'><i><font color='green'>*</font></i>
<a name='L12'><i><font color='green'>* NOTE: This code handles signal-recognition, which happens every time</font></i>
<a name='L13'><i><font color='green'>* after a timer-interrupt and after each system call. Ordinary interrupts</font></i>
<a name='L14'><i><font color='green'>* don't handle signal-recognition, as that would clutter them up totally</font></i>
<a name='L15'><i><font color='green'>* unnecessarily.</font></i>
<a name='L16'><i><font color='green'>*</font></i>
<a name='L17'><i><font color='green'>* Stack layout in 'ret_from_system_call':</font></i>
<a name='L18'><i><font color='green'>*</font></i>
<a name='L19'><i><font color='green'>* 0(%esp) - %eax</font></i>
<a name='L20'><i><font color='green'>* 4(%esp) - %ebx</font></i>
<a name='L21'><i><font color='green'>* 8(%esp) - %ecx</font></i>
<a name='L22'><i><font color='green'>* C(%esp) - %edx</font></i>
<a name='L23'><i><font color='green'>* 10(%esp) - %fs</font></i>
<a name='L24'><i><font color='green'>* 14(%esp) - %es</font></i>
<a name='L25'><i><font color='green'>* 18(%esp) - %ds</font></i>
<a name='L26'><i><font color='green'>* 1C(%esp) - %eip</font></i>
<a name='L27'><i><font color='green'>* 20(%esp) - %cs</font></i>
<a name='L28'><i><font color='green'>* 24(%esp) - %eflags</font></i>
<a name='L29'><i><font color='green'>* 28(%esp) - %oldesp</font></i>
<a name='L30'><i><font color='green'>* 2C(%esp) - %oldss</font></i>
<a name='L31'><i><font color='green'>*/</font></i>
<a name='L32'><i><font color='green'>/*</font></i>
<a name='L33'><i><font color='green'>* system_call.s 文件包含系统调用(system-call)底层处理子程序。由于有些代码比较类似,所以</font></i>
<a name='L34'><i><font color='green'>* 同时也包括时钟中断处理(timer-interrupt)句柄。硬盘和软盘的中断处理程序也在这里。</font></i>
<a name='L35'><i><font color='green'>*</font></i>
<a name='L36'><i><font color='green'>* 注意:这段代码处理信号(signal)识别,在每次时钟中断和系统调用之后都会进行识别。一般</font></i>
<a name='L37'><i><font color='green'>* 中断信号并不处理信号识别,因为会给系统造成混乱。</font></i>
<a name='L38'><i><font color='green'>*</font></i>
<a name='L39'><i><font color='green'>* 从系统调用返回('ret_from_system_call')时堆栈的内容见上面19-30 行。</font></i>
<a name='L40'><i><font color='green'>*/</font></i>
<a name='L41'>
<a name='L42'>SIG_CHLD = 17 # 定义SIG_CHLD 信号(子进程停止或结束)。
<a name='L43'>
<a name='L44'>EAX = 0x00 # 堆栈中各个寄存器的偏移位置。
<a name='L45'>EBX = 0x04
<a name='L46'>ECX = 0x08
<a name='L47'>EDX = 0x0C
<a name='L48'>FS = 0x10
<a name='L49'>5.5 system_call.s 程序
<a name='L50'>ES = 0x14
<a name='L51'>DS = 0x18
<a name='L52'>EIP = 0x1C
<a name='L53'>CS = 0x20
<a name='L54'>EFLAGS = 0x24
<a name='L55'>OLDESP = 0x28 # 当有特权级变化时。
<a name='L56'>OLDSS = 0x2C
<a name='L57'>
<a name='L58'><i><font color='green'># 以下这些是任务结构(task_struct)中变量的偏移值,参见include/linux/sched.h,77 行开始。</font></i>
<a name='L59'>state = 0 # these are offsets into the task-struct. # 进程状态码
<a name='L60'>counter = 4 # 任务运行时间计数(递减)(滴答数),运行时间片。
<a name='L61'>priority = 8 <i><font color='green'>// 运行优先数。任务开始运行时counter=priority,越大则运行时间越长。</font></i>
<a name='L62'>signal = 12 <i><font color='green'>// 是信号位图,每个比特位代表一种信号,信号值=位偏移值+1。</font></i>
<a name='L63'>sigaction = 16 # MUST be 16 (=len of sigaction) <i><font color='green'>// sigaction 结构长度必须是16 字节。</font></i>
<a name='L64'><i><font color='green'>// 信号执行属性结构数组的偏移值,对应信号将要执行的操作和标志信息。</font></i>
<a name='L65'>blocked = (33*16) <i><font color='green'>// 受阻塞信号位图的偏移量。</font></i>
<a name='L66'>
<a name='L67'><i><font color='green'># 以下定义在sigaction 结构中的偏移量,参见include/signal.h,第48 行开始。</font></i>
<a name='L68'><i><font color='green'># offsets within sigaction</font></i>
<a name='L69'>sa_handler = 0 <i><font color='green'>// 信号处理过程的句柄(描述符)。</font></i>
<a name='L70'>sa_mask = 4 <i><font color='green'>// 信号量屏蔽码</font></i>
<a name='L71'>sa_flags = 8 <i><font color='green'>// 信号集。</font></i>
<a name='L72'>sa_restorer = 12 <i><font color='green'>// 返回恢复执行的地址位置。</font></i>
<a name='L73'>
<a name='L74'>nr_system_calls = 72 # Linux 0.11 版内核中的系统调用总数。
<a name='L75'>
<a name='L76'><i><font color='green'>/*</font></i>
<a name='L77'><i><font color='green'>* Ok, I get parallel printer interrupts while using the floppy for some</font></i>
<a name='L78'><i><font color='green'>* strange reason. Urgel. Now I just ignore them.</font></i>
<a name='L79'><i><font color='green'>*/</font></i>
<a name='L80'><i><font color='green'>/*</font></i>
<a name='L81'><i><font color='green'>* 好了,在使用软驱时我收到了并行打印机中断,很奇怪。呵,现在不管它。</font></i>
<a name='L82'><i><font color='green'>*/</font></i>
<a name='L83'><i><font color='green'># 定义入口点。</font></i>
<a name='L84'>.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
<a name='L85'>.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
<a name='L86'>.globl _device_not_available, _coprocessor_error
<a name='L87'>
<a name='L88'><i><font color='green'># 错误的系统调用号。</font></i>
<a name='L89'>.align 2 # 内存4 字节对齐。
<a name='L90'>bad_sys_call:
<a name='L91'>movl $-1,%eax # eax 中置-1,退出中断。
<a name='L92'>iret
<a name='L93'><i><font color='green'># 重新执行调度程序入口。调度程序schedule 在(kernel/sched.c,104)。</font></i>
<a name='L94'>.align 2
<a name='L95'>reschedule:
<a name='L96'>pushl $ret_from_sys_call # 将ret_from_sys_call 的地址入栈(101 行)。
<a name='L97'>jmp _schedule
<a name='L98'><font color='darkred'>#</font>### int 0x80 --linux 系统调用入口点(调用中断int 0x80,eax 中是调用号)。
<a name='L99'>.align 2
<a name='L100'>_system_call:
<a name='L101'>cmpl $nr_system_calls-1,%eax # 调用号如果超出范围的话就在eax 中置-1 并退出。
<a name='L102'>ja bad_sys_call
<a name='L103'>5.5 system_call.s 程序
<a name='L104'>push %ds # 保存原段寄存器值。
<a name='L105'>push %es
<a name='L106'>push %fs
<a name='L107'>pushl %edx # ebx,ecx,edx 中放着系统调用相应的C 语言函数的调用参数。
<a name='L108'>pushl %ecx # push %ebx,%ecx,%edx as parameters
<a name='L109'>pushl %ebx # to the system call
<a name='L110'>movl $0x10,%edx # set up ds,es to kernel space
<a name='L111'>mov %dx,%ds # ds,es 指向内核数据段(全局描述符表中数据段描述符)。
<a name='L112'>mov %dx,%es
<a name='L113'>movl $0x17,%edx # fs points to local data space
<a name='L114'>mov %dx,%fs # fs 指向局部数据段(局部描述符表中数据段描述符)。
<a name='L115'><i><font color='green'># 下面这句操作数的含义是:调用地址 = _sys_call_table + %eax * 4。参见列表后的说明。</font></i>
<a name='L116'><i><font color='green'># 对应的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定义了一个包括72 个</font></i>
<a name='L117'><i><font color='green'># 系统调用C 处理函数的地址数组表。</font></i>
<a name='L118'>call _sys_call_table(,%eax,4)
<a name='L119'>pushl %eax # 把系统调用号入栈。
<a name='L120'>movl _current,%eax # 取当前任务(进程)数据结构地址??eax。
<a name='L121'><i><font color='green'># 下面97-100 行查看当前任务的运行状态。如果不在就绪状态(state 不等于0)就去执行调度程序。</font></i>
<a name='L122'><i><font color='green'># 如果该任务在就绪状态但counter[??]值等于0,则也去执行调度程序。</font></i>
<a name='L123'>cmpl $0,state(%eax) # state
<a name='L124'>jne reschedule
<a name='L125'>cmpl $0,counter(%eax) # counter
<a name='L126'>je reschedule
<a name='L127'><i><font color='green'># 以下这段代码执行从系统调用C 函数返回后,对信号量进行识别处理。</font></i>
<a name='L128'>ret_from_sys_call:
<a name='L129'><i><font color='green'># 首先判别当前任务是否是初始任务task0,如果是则不必对其进行信号量方面的处理,直接返回。</font></i>
<a name='L130'><font color='darkred'>#</font> 103 行上的_task 对应C 程序中的task[]数组,直接引用task 相当于引用task[0]。
<a name='L131'>movl _current,%eax # task[0] cannot have signals
<a name='L132'>cmpl _task,%eax
<a name='L133'>je 3f # 向前(forward)跳转到标号3。
<a name='L134'><i><font color='green'># 通过对原调用程序代码选择符的检查来判断调用程序是否是超级用户。如果是超级用户就直接</font></i>
<a name='L135'><i><font color='green'># 退出中断,否则需进行信号量的处理。这里比较选择符是否为普通用户代码段的选择符0x000f</font></i>
<a name='L136'><font color='darkred'>#</font> (RPL=3,局部表,第1 个段(代码段)),如果不是则跳转退出中断程序。
<a name='L137'>cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
<a name='L138'>jne 3f
<a name='L139'><i><font color='green'># 如果原堆栈段选择符不为0x17(也即原堆栈不在用户数据段中),则也退出。</font></i>
<a name='L140'>cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
<a name='L141'>jne 3f
<a name='L142'><i><font color='green'># 下面这段代码(109-120)的用途是首先取当前任务结构中的信号位图(32 位,每位代表1 种信号),</font></i>
<a name='L143'><i><font color='green'># 然后用任务结构中的信号阻塞(屏蔽)码,阻塞不允许的信号位,取得数值最小的信号值,再把</font></i>
<a name='L144'><i><font color='green'># 原信号位图中该信号对应的位复位(置0),最后将该信号值作为参数之一调用do_signal()。</font></i>
<a name='L145'><i><font color='green'># do_signal()在(kernel/signal.c,82)中,其参数包括13 个入栈的信息。</font></i>
<a name='L146'>movl signal(%eax),%ebx # 取信号位图??ebx,每1 位代表1 种信号,共32 个信号。
<a name='L147'>movl blocked(%eax),%ecx # 取阻塞(屏蔽)信号位图??ecx。
<a name='L148'>notl %ecx # 每位取反。
<a name='L149'>andl %ebx,%ecx # 获得许可的信号位图。
<a name='L150'>bsfl %ecx,%ecx # 从低位(位0)开始扫描位图,看是否有1 的位,
<a name='L151'><i><font color='green'># 若有,则ecx 保留该位的偏移值(即第几位0-31)。</font></i>
<a name='L152'>je 3f # 如果没有信号则向前跳转退出。
<a name='L153'>btrl %ecx,%ebx # 复位该信号(ebx 含有原signal 位图)。
<a name='L154'>movl %ebx,signal(%eax) # 重新保存signal 位图信息??current-&gt;signal。
<a name='L155'>incl %ecx # 将信号调整为从1 开始的数(1-32)。
<a name='L156'>pushl %ecx # 信号值入栈作为调用do_signal 的参数之一。
<a name='L157'>5.5 system_call.s 程序
<a name='L158'>call _do_signal # 调用C 函数信号处理程序(kernel/signal.c,82)
<a name='L159'>popl %eax # 弹出信号值。
<a name='L160'>3: popl %eax
<a name='L161'>popl %ebx
<a name='L162'>popl %ecx
<a name='L163'>popl %edx
<a name='L164'>pop %fs
<a name='L165'>pop %es
<a name='L166'>pop %ds
<a name='L167'>iret
<a name='L168'>
<a name='L169'><font color='darkred'>#</font>### int16 -- 下面这段代码处理协处理器发出的出错信号。跳转执行C 函数math_error()
<a name='L170'><font color='darkred'>#</font> (kernel/math/math_emulate.c,82),返回后将跳转到ret_from_sys_call 处继续执行。
<a name='L171'>.align 2
<a name='L172'>_coprocessor_error:
<a name='L173'>push %ds
<a name='L174'>push %es
<a name='L175'>push %fs
<a name='L176'>pushl %edx
<a name='L177'>pushl %ecx
<a name='L178'>pushl %ebx
<a name='L179'>pushl %eax
<a name='L180'>movl $0x10,%eax # ds,es 置为指向内核数据段。
<a name='L181'>mov %ax,%ds
<a name='L182'>mov %ax,%es

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -