Внутреннее устройство ядра Linux 2.4

       

Как реализуются системные вызовы в архитектуре i386?


В Linux существует два механизма реализации системных вызовов:

  • вентили lcall7/lcall27;
  • программное прерывание int 0x80.
  • Чисто Линуксовые программы используют int 0x80, в то время как программы из других UNIX систем (Solaris, UnixWare 7 и пр.) используют механизм lcall7. Название lcall7 может ввести в заблуждение, поскольку это понятие включает в себя еще и lcall27 (например для Solaris/x86), но тем не менее, функция-обработчик называется lcall7_func.

    Во время начальной загрузки системы вызывается функция arch/i386/kernel/traps.c:trap_init(), которая настраивает IDT (Interrupt Descriptor Table) так, чтобы вектор 0x80 (of type 15, dpl 3) указывал на точку входа system_call из arch/i386/kernel/entry.S.

    Когда пользовательское приложение делает системный вызов, аргументы помещаются в регистры и приложение выполняет инструкцию int 0x80. В результате приложение переводится в привелигированный режим ядра и выполняется переход по адресу system_call в entry.S. Далее:

  • Сохраняются регистры.
  • В регистры %ds и %es заносится KERNEL_DS, так что теперь они ссылаются на адресное пространство ядра.
  • Если значение %eax больше чем NR_syscalls

    (на сегодняшний день 256), то возвращается код ошибки ENOSYS.

  • Если задача исполняется под трассировщиком (tsk->ptrace & PF_TRACESYS), то выполняется специальная обработка. Сделано это для поддержки программ типа strace (аналог SVR4 truss(1)) и отладчиков.
  • Вызывается sys_call_table+4*(syscall_number из %eax). Эта таблица инициализируется в том же файле (arch/i386/kernel/entry.S) и содержит указатели на отдельные обработчики системных вызовов, имена которых, в Linux, начинаются с префикса sys_, например sys_open, sys_exit, и т.п.. Эти функции снимают со стека свои входные параметры, которые помещаются туда макросом SAVE_ALL.
  • Вход в 'system call return path'. Это - отдельная метка, потому что этот код используется не только int 0x80 но и lcall7, lcall27. Это связано с обработкой тасклетов (tasklets) (включая bottom halves), проверяется необходимость вызова планировщика (tsk->need_resched != 0) и имеются ли ожидающие сигналы.
  • Linux поддерживает до 6-ти входных аргументов в системных вызовах. Они передаются через регистры %ebx, %ecx, %edx, %esi, %edi (и %ebp для временного хранения, см. _syscall6() в asm-i386/unistd.h). Номер системного вызова передается в регистре %eax.



    Содержание раздела