home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / os / linux / 8690 < prev    next >
Encoding:
Internet Message Format  |  1992-08-20  |  5.6 KB

  1. Path: sparky!uunet!mcsun!news.funet.fi!hydra!klaava!torvalds
  2. From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
  3. Newsgroups: comp.os.linux
  4. Subject: Re: A question about Kernel system call mechanism
  5. Keywords: linux, kernel, system call
  6. Message-ID: <1992Aug20.122051.24901@klaava.Helsinki.FI>
  7. Date: 20 Aug 92 12:20:51 GMT
  8. References: <1992Aug19.174117.21233@ramsey.cs.laurentian.ca>
  9. Organization: University of Helsinki
  10. Lines: 102
  11.  
  12. In article <1992Aug19.174117.21233@ramsey.cs.laurentian.ca> ron@ramsey.cs.laurentian.ca (Ron Prediger [Velociraptor]) writes:
  13. >I am relatively new to Linux and have been examining the kernel source.
  14. >
  15. >1) Does anyone know how linux passes parameters from the user process to the
  16. >kernel service routine ?  Below is what I think is happening and where I
  17. >am confused.
  18. >
  19. >It appears that system calls are handled using interrupt or trap gates
  20. >resident in the Interrupt descriptor table (IDT).  From reading the Intel
  21. >386 ref. manual I understand that a stack switch occurs automatically when
  22. >a less privileged process accesses a gate for a more privileged subroutine.
  23.  
  24. Correct so far...
  25.  
  26. >What I can't see is how the kernel service routine gets the system call
  27. >parameters (ie. addresses, etc) from the user process.  Is there code 
  28. >somewhere which copies these parameters from the original (level 3) stack to
  29. >the more privileged (level 0) stack ?  If linux had used call gates to
  30. >implement system calls, the parameters would automatically be copied to the
  31. >privileged routine's stack by the 386.  (This automatic
  32. >copy of parameters does not occur when referencing interrupt/trap gates.)
  33.  
  34. I didn't like system call gates: they are too complicated for my taste
  35. (besides, you have to know how many arguments to copy, or have a
  36. specific system call gate for each type of argument: maybe not a bad
  37. idea, but...).  Anyway, things are easier than you make them out to be:
  38. the arguments are simply passed in the normal registers. 
  39.  
  40. Passing arguments in the registers allows you 6 (32-bit) direct
  41. arguments (not counting %eax, which is used to tell which system call
  42. you want handled), and more if you simply set up a pointer to a block in
  43. user space.  And the beauty of it all is that they are automatically put
  44. on the stack in as arguments to the system calls when the registers are
  45. saved - see the file linux/kernel/sys_call.S, which saves all the
  46. necessary state information.  It's the simplest and fastest way I could
  47. find: linux doesn't even save the state in some special task-structure
  48. like other unices seem to do, but just leaves the regs on the stack,
  49. ready for popping when the process returns from the interrupt. 
  50.  
  51. >2) It appears that Linux is making use of segment registers (FS,GS) and the
  52. >LDT/GDT  to transfer the actual data (ie. from a read system call) between
  53. >user and kernel address spaces.  Is this observation correct ?
  54.  
  55. Actually, only %fs is used: it points to the user-space segment when in
  56. a system call.  Thus linux never needs to check any bounds when copying
  57. from/to user space: it's automatically handled by the hardware.  The
  58. get_fs_XXX() and put_fs_XXX() (XXX=byte, word, long) inline functions
  59. can be used to transfer bytes from/to user space, and memcpy_tofs() or
  60. memcpy_fromfs() can be used to move bigger blocks between kernel and
  61. user segments.
  62.  
  63. What happens at a system call is roughly:
  64.  
  65. user space:
  66.  - load the arguments into registers (%eax contains the system call
  67.    index, %ebx... contain the parameters)
  68.  - do an "int $0x80", moving to kernel mode:
  69.  
  70. kernel space:
  71.  - clear the direction-flag, as gcc assumes this
  72.  - save the system call number: a negative number means the interrupt
  73.    was caused by a hardware IRQ or trap.
  74.  - save all the segment registers
  75.  - save %eax (which happens to be the same number we saved earlier if
  76.    this is a normal system call)
  77.  - save the other registers: they automatically form the stack frame for
  78.    the system call.
  79.  - call the appropriate system call handler by indexing the appropriate
  80.    table with %eax.
  81.  
  82. The handler does it's stuff - it /can/ change the stack frame if it
  83. wants to, and thus return information in any registers it wants to, but
  84. that is really discouraged, and all system calls currently just return
  85. their result in %eax as part of their normal return.
  86.  
  87.  - check if there were any signals, and change the return stack (both in
  88.    kernel and user space) appropriately if so, invoking the signal
  89.    handler instead of returning directly. 
  90.  - pop all the saved registers, and do an iret, returning to user mode.
  91.  
  92. While the system call runs, the %ds and %es registers point to kernel
  93. data space, and %fs points to user space. But the system calls may
  94. change %fs for their own needs: for example symbolic links result in
  95. changing %fs to kernel space for a while as the name is parsed directly
  96. from the kernel buffers instead of from user space etc.
  97.  
  98. Note that normal faults/traps and IRQ's do essentially exactly the same,
  99. except for "fast" IRQ's, which just save a minimal amount of information
  100. and don't do the signal checking (used by things like the serial
  101. handlers).  Also, they naturally haven't got any "system call number",
  102. but have their own routine that is called after the stack is set up. 
  103.  
  104. As to the GDT: the GDT contains just two normal segment entries: GDT[1]
  105. is the kernel code segment descriptor, and GDT[2] is the kernel data
  106. descriptor. The rest of the global descriptor table is filled with TSS
  107. and LDT descriptors. The local descriptor tables normally contain just
  108. the user-space code/data descriptors in LDT[1] and LDT[2], but it's
  109. flexible enough to be extended if something wants to have more segments
  110. in user space (I think the xenix emulator uses this, although I haven't
  111. looked at the code yet).
  112.  
  113.         Linus
  114.