Date: Fri, 27 Aug 2004 04:16:12 -0700 From: Terry Lambert <tlambert2@mindspring.com> To: Mmaist <mmaist@email.it> Cc: freebsd-hackers@freebsd.org Subject: Re: syscalls implementation Message-ID: <412F17FC.E856A234@mindspring.com> References: <fb356c20f5bbebc5f8888312d44f11b5@213.203.147.246>
next in thread | previous in thread | raw e-mail | index | archive | help
Mmaist wrote: > Hi! > I was wondering were syscalls implementation is in the FreeBSD source tree. > I would like to know, especially, where > > int kldload(const char*); > > is located. sys/kern/kern_linker.c contains > > int > kldload(struct thread *, struct kldload_args *) > > and I need to watch at what called between them. This is probably the wrong list. You probably want -questions. Here's the simplest answer you will probably understand, given that the question you are really asking is about understanding how system calls work, and where baby system calls come from. 8-). The system calls are in code that's generated from the file /usr/src/sys/kern/syscalls.master by /usr/src/sys/kern/maksyscalls.sh, which is an awk script encapsulated in a shell script. In user space, the system calls are stubs in a library that traps into the vector code generated from syscalls.master in the kernel. This code is located in /usr/src/lib/libc. In the case os system calls that are unwrapped (like kldload(2)), the calls are generated assembly code that comes from running a script against the same syscalls.master file describd earlier; see src/lib/libc/sys/Makefile.inc for the exact place in the source tree that these stubs are being generated from. The way a system call happens is that the arguments are pushed on the stack (or put into registers, depending), and then a trap is issued by attempting to execute a supervisor-only instruction in user code. This effectively generates a fault which is then serviced by a fault handler in the kernel which recognizes the particular trap as "special", and treats it as a system call. Now when the special trap code in the kernel itself is activated, it packages up the arguments in a structure of a known size (known to the code in init_sysent.c, generated from syscalls.master). For the Intel version of the trap code, see /usr/src/sys/i386/i386/trap.c and the related assembly code there. The current thread and the packaged argument pointer are passed to the system call. Techinically, it makes a lot of things difficult that the current thread is passed into the system call as part of its context, rather than obtained when needed, and cached locally, if necessary, but since it's handy at the time, it's passed in. On non-register-poor architectures, the current thread is usually made available in a register, so the cost in obtaining it later is actually lss than a memory dereference of a computed stack offset, as it is/was (depends on the version, architecture, etc.) in FreeBSD because it's being passed in. On of the major things this makes difficult is accurate proxy credential representation at various points in the kernel (see the NFS server source code for examples of the contorted logic this makes necessary). The packages argument structures are defined in the (also generated from the syscalls.master) file /usr/src/sys/sys/sysproto.h. For the kldload system call, this looks like: struct kldload_args { char file_l_[PADL_(const char *)]; const char * file; char file_r_[PADR_(const char *)]; }; This argument structure is actually a dscriptor. A descriptor is used to ensure packing and alignment, so that the user stack save area can be coerced directly to the structure type, and dereferenced in the function. The descriptor contains the information necessary to line the structure contents up with the user stack area and/or register spill area, where the arguments were stored in user space before the trap. Mostly, you can just look at the middle element to know what the argument is, for each line of arguments. In this case, it's a "const char * file". This matches what it was in user space when you made the call. So the function you are seeing in the kernel: int kldload(struct thread *, struct kldload_args *); *is* the system call you saw in user space: int kldload(const char*); with the trap added thread pointer and pointer to the packed up save area containing the same char * value you passed in user space. Note that since the user and kernel space are not necessarily in core at the same time (maybe the pointer you pointed to was in a page that was swapped out), so you have to use copyin/uiomove in the function in the kernel to copy the path in before it can be used in the kernel address space. Probably you should not be hacking in this area until you understand the code operation a little better, since unless you know what you are doing, most changes you could possibly make will leave you with a dead system. -- Terry
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?412F17FC.E856A234>