Question about system calls
Posted: Wed Jul 03, 2019 9:46 am
I have just finished writing system calls in my operating system, but unsure of if I have done it correctly. I've googled many things, but cannot find any definitive answers.
My first question is: do system calls always have to generate software interrupts? I am using interrupt 0x80 as Linux does. I have coded a system call handler, part in C and part in Assembly, that takes a system call number from the eax (32 bit OS) register (which is stored in a struct which is populated from the register values pushed onto the stack when an interrupt occurs), and then uses that as an index into a system call table. It then sets up the stack to pass all the values to the functions. This works perfectly. Initially, I was testing this using inline assembly, but once I got that sorted, I moved on to actually writing the system calls. So, for example, I got a system call "sys_open", which just calls "vfs_open", and returns the FILE structure associated with that file. In user mode programs, a user would typically use "fopen", so in my case, I just made "fopen" call "sys_open" (which subsequently calls "vfs_open"). In this way, there is some sort of protection, as the kernel can still check for certain errors/bugs/whatever. But I am unsure if this is the correct way of doing this. Is it OK that I just have functions calling other functions, instead of just generating interrupts, or is there a better way that I am supposed to be doing this? If I do have to use interrupts for all system calls, do part(s) of the system call have to be coded in assembly, or can it all be done in C?
In this approach I have taken, there is no switching to kernel mode, which leads onto my next question: do I really need to switch to kernel mode? And if so, how? Or is it possible just to setup up things in the kernel initially, and then switch to and stay in user mode the entire time (I feel like this is similar to one of the kernel designs)? If I do have to switch to kernel mode each time, I haven't found anything explaining how that would be done (I have managed to switch to user mode successfully, although generating an interrupt in user mode does cause a double fault, and subsequently, a crash. Any ideas why?). I understand that user mode is restricted from doing certain things that only the kernel can do. I read that this includes IO port access, but I still seem to be able to read from ports in user mode (unless I need to still set the IOPL?).
I currently have no virtual memory manager, but would like to implement this in the future. I know that memory management is the job of the kernel, and so wouldn't this require switching to kernel mode, for example mapping in and out different page?
I thought about just hiding some functions from the user, or rather, do some sort of checking inside functions, such as system calls, to check whether the process has sufficient privileges etc, but I'm not sure if this is a thorough enough, or the most correct way, of preventing privileged operations from being run in user mode instead of kernel mode.
The code can be found at https://github.com/aaron2212/XOS. It is under the branch "system-calls"
My first question is: do system calls always have to generate software interrupts? I am using interrupt 0x80 as Linux does. I have coded a system call handler, part in C and part in Assembly, that takes a system call number from the eax (32 bit OS) register (which is stored in a struct which is populated from the register values pushed onto the stack when an interrupt occurs), and then uses that as an index into a system call table. It then sets up the stack to pass all the values to the functions. This works perfectly. Initially, I was testing this using inline assembly, but once I got that sorted, I moved on to actually writing the system calls. So, for example, I got a system call "sys_open", which just calls "vfs_open", and returns the FILE structure associated with that file. In user mode programs, a user would typically use "fopen", so in my case, I just made "fopen" call "sys_open" (which subsequently calls "vfs_open"). In this way, there is some sort of protection, as the kernel can still check for certain errors/bugs/whatever. But I am unsure if this is the correct way of doing this. Is it OK that I just have functions calling other functions, instead of just generating interrupts, or is there a better way that I am supposed to be doing this? If I do have to use interrupts for all system calls, do part(s) of the system call have to be coded in assembly, or can it all be done in C?
In this approach I have taken, there is no switching to kernel mode, which leads onto my next question: do I really need to switch to kernel mode? And if so, how? Or is it possible just to setup up things in the kernel initially, and then switch to and stay in user mode the entire time (I feel like this is similar to one of the kernel designs)? If I do have to switch to kernel mode each time, I haven't found anything explaining how that would be done (I have managed to switch to user mode successfully, although generating an interrupt in user mode does cause a double fault, and subsequently, a crash. Any ideas why?). I understand that user mode is restricted from doing certain things that only the kernel can do. I read that this includes IO port access, but I still seem to be able to read from ports in user mode (unless I need to still set the IOPL?).
I currently have no virtual memory manager, but would like to implement this in the future. I know that memory management is the job of the kernel, and so wouldn't this require switching to kernel mode, for example mapping in and out different page?
I thought about just hiding some functions from the user, or rather, do some sort of checking inside functions, such as system calls, to check whether the process has sufficient privileges etc, but I'm not sure if this is a thorough enough, or the most correct way, of preventing privileged operations from being run in user mode instead of kernel mode.
The code can be found at https://github.com/aaron2212/XOS. It is under the branch "system-calls"