System calls in Windows Operating System
System calls in Windows Operating System
Does anybody know whether or not Windows uses Call Gates for external functions in DLLs?
When you invoke an external function in a DLL, say "SendMessage" in "User32.dll", your code (when assembled) will call a DWORD value (not a constant value, changes between module to module) and if you trace the code, you will see a FAR JMP to another variable DWORD value. I am guessing that the FAR JMP points to a Call Gate that is the gate to the "SendMessage" API in "User32.dll" that is mapped to the virtual address space of the current process. I am not sure so if someone could confirm this, I'd really appreciate it.
I also want to know whether it is good to set the CS' base address for processes to the physical address of the starting point of the process in the memory or not. So do you choose to set the CS's base address to the starting point of the process and then set the EIP to 0 or do you set the EIP to the process's base address and the CS to 0?
When you invoke an external function in a DLL, say "SendMessage" in "User32.dll", your code (when assembled) will call a DWORD value (not a constant value, changes between module to module) and if you trace the code, you will see a FAR JMP to another variable DWORD value. I am guessing that the FAR JMP points to a Call Gate that is the gate to the "SendMessage" API in "User32.dll" that is mapped to the virtual address space of the current process. I am not sure so if someone could confirm this, I'd really appreciate it.
I also want to know whether it is good to set the CS' base address for processes to the physical address of the starting point of the process in the memory or not. So do you choose to set the CS's base address to the starting point of the process and then set the EIP to 0 or do you set the EIP to the process's base address and the CS to 0?
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
Re: System calls in Windows Operating System
No, it doesn't. There is no privilege transition when calling a DLL, so it is just an indirect call through a jump table. That jump table contains the address of each function imported from the DLL. It is initialized when the DLL is loaded.XCHG wrote:Does anybody know whether or not Windows uses Call Gates for external functions in DLLs?
The NT kernel doesn't use call gates at all as far as I know, but Windows 9x/ME did. 9x/ME used call gates for system calls though, not for DLLs (for the same reason -- there is no need to switch privilege levels when calling a DLL).
IMO call gates don't really make sense if you're using a flat memory model (which most people do these days).
<edit>
I just noticed your post subject talks about system calls. Don't confuse system calls with functions exported from DLLs. Anything you call in User32.dll or even Kernel32.dll are just user-mode library functions. The real system calls are invoked via stubs in ntdll.dll. The stubs actually jump to processor-specific code that is mapped into each process' address space (to avoid conditional processor-detection logic on each system call). I believe XP and Vista use sysenter/sysexit or syscall/sysret for newer processors, and they probably still use the int instruction for older processors (if they even support processors that old).
</edit>
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
Re: System calls in Windows Operating System
Yep, I think so... ReactOS devs may have deeply studied Windows' Application Binary Interfaces, so they probably know...Colonel Kernel wrote:I believe XP and Vista use sysenter/sysexit or syscall/sysret for newer processors,
JJ
I just don't know how I am supposed to implement such system call mechanism so I am kind of lost. I guess that is all done with paging right? Are there any resources out there as basic instructions? Thank you both for your responses.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
I wouldn't say these system call mechanisms "use" paging -- more like they "integrate" with paging in the sense that they normally perform a privilege level switch (meaning that the code called by the system call can live in pages marked as "supervisor"). Syscall/sysret and friends are more complicated than just using "int", but are faster -- I would just use "int" for now and switch over to syscall etc. later when you want to optimize. If you have interrupts working, "int" should be no big deal. Just pick an interrupt number to use (Linux uses 0x80, for example) and write a handler for it.XCHG wrote:I just don't know how I am supposed to implement such system call mechanism so I am kind of lost. I guess that is all done with paging right? Are there any resources out there as basic instructions? Thank you both for your responses.
Here is the wiki page on system calls. It's a bit thin, but has links that might be useful:
http://www.osdev.org/wiki/System_Calls
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
Erm... About that page, page faults and system calls...Colonel Kernel wrote:Here is the wiki page on system calls. It's a bit thin, but has links that might be useful:
http://www.osdev.org/wiki/System_Calls
I thought of a method to free one GPR during system calls. Instead of calling a common interrupt that selects the correct function, the user mode program would call a predefined memory address is order to transfer control to the kernel. That page's address was on a non-present page, so the page fault exception handler selects the correct function (the faulty address). Of course it could simply be a memory read or write...
Now, I'm sure it's not very useful from a C's perspective, because are normally use stubs to call the system. However, if we declare the system call stubs as static inline functions (in the headers) perhaps register allocation can achive better performance. I don't know...
JJ
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
I suspect it wouldn't be as fast as syscall/sysret & friends, but the only way to be sure is to implement it and measure it.JJeronimo wrote:Now, I'm sure it's not very useful from a C's perspective, because are normally use stubs to call the system. However, if we declare the system call stubs as static inline functions (in the headers) perhaps register allocation can achive better performance. I don't know...
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
I so suspect too, but OTOH, page faults occur very often. An example is COW pages after forks and execs on UNIX... And they don't really speed down execution...Colonel Kernel wrote:I suspect it wouldn't be as fast as syscall/sysret & friends, but the only way to be sure is to implement it and measure it.JJeronimo wrote:Now, I'm sure it's not very useful from a C's perspective, because are normally use stubs to call the system. However, if we declare the system call stubs as static inline functions (in the headers) perhaps register allocation can achive better performance. I don't know...
And system calls are not to be used in every case. In reality, experienced programmers usually tell people to avoid overloading the processor with inter-privilege level calls...
JJ
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
On the grand scale of things, no, but if you look at what the processor actually does on a page fault, it's a much bigger hit than for a system call. A page fault is just like any other interrupt from the processor's point of view. It has to stop what it's doing, flush its pipeline, and push some of its state on the stack. Re-filling its pipeline with the handler code costs thousands of cycles in memory access (unless you're lucky enough that the handler code is still in the caches somewhere). I don't think the system call instructions involve any pipeline flushing (except probably for outstanding memory accesses), because they are designed specifically for speed.JJeronimo wrote:I so suspect too, but OTOH, page faults occur very often. An example is COW pages after forks and execs on UNIX... And they don't really speed down execution...
As for avoiding system calls, this might make sense for some architectures, but not for most microkernels where IPC is very commonplace... Unless you're talking about a microkernel with software-isolated processes where system calls are just regular function calls. I always manage to work that in somehow...
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
No... Singularity idea is very confusing to me... What's that? The kernel scans the program and prohibits it to execute if it does something wrong? We could call this anti-virus-based protection! I'm not very sure about it's effectivity...Colonel Kernel wrote:As for avoiding system calls, this might make sense for some architectures, but not for most microkernels where IPC is very commonplace... Unless you're talking about a microkernel with software-isolated processes where system calls are just regular function calls. I always manage to work that in somehow...
A solution could be making the kernel perform only high-importance tasks (like address-space switches or building page tables and so), and manage everything else in an "user-mode kernel layer" (including context switches and so... It would be possible, for example, to switch between threads of the same process without going to kernel mode). Then, the kernel only has one or two system calls that are only callable from this "layer" (it would examine the return address on the stack to determine this) and only if necessary for the system function.
Then, this layer could have a mechanism to detect weather the process altered the layer's data pages (for example, the accessed bit in the page table entry), and kill the process if so (and so restore the pages from a backup)... This test could be made by the linked-list/hash-table/etc manipulation functions to avoid testing the entire data space on each call...
Useful here would be if the processor supported some kind of "range-based" memory protection (if you understand what I'm talking about)...
Or another option would be making this pages read-only from user space and the layer would call them if it wanted to access them... Here, some kind "kernel instruction language" could be useful to reduce calling overhead (in the sense that each kernel call would execute a string of instructions in a special language, reducing to one the number of needed registers needed to call the kernel, but OTOH storing everything else in memory)...
JJ
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
Kernel Instruction Language System Call Mechanism
Pages Read-Only
Or in simpler terms just use a syscall instruction or interrupt.
Kernel Instruction Language
Oh. I think you mean directly jump into the kernel with out a context switch (changing address spaces). This is actually the standard way to perform this operation since a interrupt and a syscall instruction do not support changing the current address space unless you do it afterwards. If you do it afterwards there may be no point as you are most likely already inside the kernel code (read-only to user).Or another option would be making this pages read-only from user space and the layer would call them if it wanted to access them...
Or in simpler terms just use a syscall instruction or interrupt.
Kernel Instruction Language
It is most likely going to take more time to generate a sequence in this kernel instruction language rather than passing the arguments through the registers I would think?Here, some kind "kernel instruction language" could be useful to reduce calling overhead (in the sense that each kernel call would execute a string of instructions in a special language, reducing to one the number of needed registers needed to call the kernel, but OTOH storing everything else in memory)...
Last edited by Kevin McGuire on Mon May 14, 2007 3:15 pm, edited 1 time in total.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
What singularity does is that it takes a program, and then tries to build a proof that it does not do anything that could upset the OS. If it succeeds, the program can be run without any security measures, as it is guaranteed to behave.JJeronimo wrote:No... Singularity idea is very confusing to me... What's that? The kernel scans the program and prohibits it to execute if it does something wrong? We could call this anti-virus-based protection! I'm not very sure about it's effectivity...
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
Exactly. My point was that code that is "safe" can be run in the same address space and privilege level as the kernel, so a system call becomes just a simple function call.Combuster wrote:What singularity does is that it takes a program, and then tries to build a proof that it does not do anything that could upset the OS. If it succeeds, the program can be run without any security measures, as it is guaranteed to behave.JJeronimo wrote:No... Singularity idea is very confusing to me... What's that? The kernel scans the program and prohibits it to execute if it does something wrong? We could call this anti-virus-based protection! I'm not very sure about it's effectivity...
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
Re: Kernel Instruction Language System Call Mechanism
Here is a small mistake I made... I meant "from user space and the layer would call the kernel if it wanted to access them"Kevin McGuire wrote:Pages Read-OnlyOr another option would be making this pages read-only from user space and the layer would call them if it wanted to access them...
I think it's supported if the IDT entry is a task gate, but never mind...Oh. I think you mean directly jump into the kernel with out a context switch (changing address spaces). This is actually the standard way to perform this operation since a interrupt and a syscall instruction do not support changing the current address space unless you do it afterwards.
No! What I meant was a normal inter-ring call (using int or syscall) to transfer control to the supervisor-mode part of the kernel that would perform the modifications to the data structures used by the user-mode kernel portion.
No, because a "kernel script" could perform many operations on a single call.Kernel Instruction LanguageIt is most likely going to take more time to generate a sequence in this kernel instruction language rather than passing the arguments through the registers I would think?Here, some kind "kernel instruction language" could be useful to reduce calling overhead (in the sense that each kernel call would execute a string of instructions in a special language, reducing to one the number of needed registers needed to call the kernel, but OTOH storing everything else in memory)...
But access to the data structures could be done by directly reading from the read-only pages.
JJ
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
@JJeronimo:
If I understand you correctly, then I think what you're proposing resembles an Exokernel.
If I understand you correctly, then I think what you're proposing resembles an Exokernel.
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager