OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 5:42 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: How to handle signals
PostPosted: Fri Jun 29, 2018 9:27 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1604
Hi all,

I'm currently designing (seems like I never get as far as implementing the designs, though) the system call interface of my OS. For reasons I'm thinking call gates. I have an abundance of those, so each system call can be its own call gate. In fact, I should probably reserve a bunch of system call numbers and have all the unimplemented ones return -ENOSYS, since writing a single function that does that is easier than trying to emulate it from the GPF handler. Unless there is just a brilliant way to figure out both the failed opcode and the next instruction boundary of x86 code.

So I thought I'd have the call gates all point to assembly stubs that just continue to the C handler and do a far return, e.g.

Code:
asm_write:
    call sys_write
    lret


Then sys_write() can use the same calling convention as normal code. And since I am on 64 bits, all the arguments are in registers, anyway. So far, so good.

But then I wondered: What if a call can block? Yeah, I can suspend the task in kernel mode. In fact, that is what normally happens. But then a signal might arrive for the task. In fact, signals can only arrive while the task is blocked. If it kill()s itself, I have to manually put a break there, and if another core kills a currently running task, that's what IPIs are for.

So, yes, what happens if a signal arrives and, horror of horrors, is handled? In that case I would like to alter the user stack: Align their rsp to a 16-byte boundary, lower it by 128, put a restore image there (which has to contain the old RSP, RIP, and the volatile registers. The nonvolatile ones are saved by the compiler), and the address of the restorer, then replace the system call's (or interrupt's) return RSP with the new value and the RIP with the handler.

Problem is, all of this requires access to return RIP and return RSP. Writable access, in fact. No matter how I slice it, these are necessary data. On a side note, even though these specific steps are arch-specific, something like this would have to be done on all archs, should I ever go portable.

I could of course make my stubs a bit longer, save all the volatile regs and call the system call with pointers to the reg and return structures (I'd decouple them, since I have both call gates and interrupts, with different return frames). But that would make every syscall arch-specific. Not a nice thought. Also, I'd have to read my arguments out of this structure and hope I'm doing the correct type casts. Sounds error prone.

I could save the regs and create the pointers, but only give them to the syscall function as two additional arguments. That would require knowledge of how many arguments there are in each call, but is theoretically possible. Though at least for some syscalls, that would put me over the edge of 6 arguments, so
I'd have to spill to the stack.

Other ideas?

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: How to handle signals
PostPosted: Fri Jun 29, 2018 9:44 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4594
Location: Chichester, UK
I'd use SYSCALL rather than call gates.


Top
 Profile  
 
 Post subject: Re: How to handle signals
PostPosted: Fri Jun 29, 2018 12:19 pm 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
If a signal happens in a syscall, (assuming a traditional OS design where syscalls are executed on per-task kernel stacks) that syscall needs to deal with the signal. Specifically, the blocking needs to be interrupted, the syscall needs to decide if it is able to cancel its operation or not and if it wants to cancel, it needs to return to the outermost kernel frame that has access to user IP and SP.

_________________
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].


Top
 Profile  
 
 Post subject: Re: How to handle signals
PostPosted: Fri Jun 29, 2018 12:52 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1604
OK. So, in my case, the outermost kernel frame is the assembly stub. So that one has to contain code to check for signals... Hey, that's actually workable.

Code:
asm_write:
    call sys_write
    cmpq $-EINTR, %rax
    jz handle_syscall_signal
    lret


And then handle_syscall_signal can save the registers and call the necessary functions to handle the signal. That is also flexible enough to allow for a similar function for interrupt handlers.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: How to handle signals
PostPosted: Fri Jun 29, 2018 1:57 pm 
Offline
Member
Member

Joined: Thu May 17, 2007 1:27 pm
Posts: 999
Yes, that would work. You can also pass the stack pointer from the assembly stack to C if you want to write that code in C.

_________________
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 176 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group