Hi,
I'm writing a new OS kernel atop of L4Fiasco.OC. I'm having some difficulties to let my OS support user-level processes that uses floating-point instruction.
So far, My OS closely follows L4Linux, it creates a new task for each user-level process, and marks as all threads of the task as alien thread to capture all page faults and exceptions.
My OS works fines with page fault and syscalls. However, I'm confused with what I should do with floating-point exception (exception #7), which is issued to my kernel at the first time it tries to perform floating-point arithmetic.
I tried to return to the user-level process with an empty message ( l4_msgtag_t tag = l4_msgtag(0, 0, 0, 0) ), or an empty message with L4_MSGTAG_TRANSFER_FPU (l4_msgtag_t tag = l4_msgtag(0, 0, 0, L4_MSGTAG_TRANSFER_FPU) ), but I had no luck.
The user-level process immediately calls "int $0x3" and stops.
I read through L4Linux's code and it seems it's doing similar thing, except that it did initialize the FPU state before asking L4 to transfer the FPU state to user-level process.
Am I missing something? What's the recommend way of doing it? Your comments are highly appreciated.
~Haohui
Hi,
To provide a more concrete idea for the discussion. Here is my code skeleton:
static void server_loop(void)
{
while (1) {
.... handle_exception(&src, &tag);
if (l4_msgtag_flags(tag) & L4_MSGTAG_TRANSFER_FPU) l4_utcb_inherit_fpu_u(u, 1);
tag = l4_ipc_reply_and_wait(u, tag, &src, L4_IPC_SEND_TIMEOUT_0);
l4_utcb_inherit_fpu_u(u, 0); .... }
}
static int handle_exception(l4_cap_idx_t *src_id, l4_msgtag_t *tag) { l4_exc_regs_t exc; memcpy(&exc, l4_utcb_exc(), sizeof(exc));
if (exc.trapno == 0x7) { printf("FPU exception\n"); *tag = l4_msgtag(0, 0, 0, L4_MSGTAG_TRANSFER_FPU); return 0; } ... }
Your comments are appreciated.
~Haohui
On Sun, Apr 8, 2012 at 5:22 PM, Mai, Haohui haohui.mai@gmail.com wrote:
Hi,
I'm writing a new OS kernel atop of L4Fiasco.OC. I'm having some difficulties to let my OS support user-level processes that uses floating-point instruction.
So far, My OS closely follows L4Linux, it creates a new task for each user-level process, and marks as all threads of the task as alien thread to capture all page faults and exceptions.
My OS works fines with page fault and syscalls. However, I'm confused with what I should do with floating-point exception (exception #7), which is issued to my kernel at the first time it tries to perform floating-point arithmetic.
I tried to return to the user-level process with an empty message ( l4_msgtag_t tag = l4_msgtag(0, 0, 0, 0) ), or an empty message with L4_MSGTAG_TRANSFER_FPU (l4_msgtag_t tag = l4_msgtag(0, 0, 0, L4_MSGTAG_TRANSFER_FPU) ), but I had no luck.
The user-level process immediately calls "int $0x3" and stops.
I read through L4Linux's code and it seems it's doing similar thing, except that it did initialize the FPU state before asking L4 to transfer the FPU state to user-level process.
Am I missing something? What's the recommend way of doing it? Your comments are highly appreciated.
~Haohui
On Sun Apr 08, 2012 at 17:22:21 -0500, Mai, Haohui wrote:
I'm writing a new OS kernel atop of L4Fiasco.OC. I'm having some difficulties to let my OS support user-level processes that uses floating-point instruction.
So far, My OS closely follows L4Linux, it creates a new task for each user-level process, and marks as all threads of the task as alien thread to capture all page faults and exceptions.
My OS works fines with page fault and syscalls. However, I'm confused with what I should do with floating-point exception (exception #7), which is issued to my kernel at the first time it tries to perform floating-point arithmetic.
I tried to return to the user-level process with an empty message ( l4_msgtag_t tag = l4_msgtag(0, 0, 0, 0) ), or an empty message with L4_MSGTAG_TRANSFER_FPU (l4_msgtag_t tag = l4_msgtag(0, 0, 0, L4_MSGTAG_TRANSFER_FPU) ), but I had no luck.
The user-level process immediately calls "int $0x3" and stops.
I read through L4Linux's code and it seems it's doing similar thing, except that it did initialize the FPU state before asking L4 to transfer the FPU state to user-level process.
I do not see anything (obvious) wrong. Can you pinpoint where the int3 is?
Adam
Hi,
I forgot to mention that my OS is running simultaneously with L4Linux.
In this case, it seems that Thread::transfer_fpu() becomes a no-op -- since the vcpu task for L4Linux has the FPU, but is the owner of FPU, and my OS doesn't. Therefore my OS cannot grant my user-level task the FPU since it doesn't have it.
However, my OS can grant the FPU to my user-level task, once I insert an floating-point instruction right before trying to grant my user-level process the FPU. In this case my OS magically becomes the owner of the FPU, and everything works smoothly.
What I really don't understand is that how this "magic" works. First, both L4Linux and my OS are started independently by ned:
(1) If FPU ownership can only be transferred via exception #7 and IPC, I don't understand why my OS can grab the FPU transparently, simply by executing an floating-point instruction.
(2) If there's some transparent way that an process can get an FPU, then I don't understand why my user-level process can't grab the FPU transparently. Maybe this is because that my OS is a non-alien task but my user-level task is an alien?
I really appreciate if you can explain it a little bit --- I'm really appreciated if you can share your idea of what would be the correct way of implementing it.
~Haohui
On Tue, Apr 10, 2012 at 5:07 PM, Adam Lackorzynski < adam@os.inf.tu-dresden.de> wrote:
On Sun Apr 08, 2012 at 17:22:21 -0500, Mai, Haohui wrote:
I'm writing a new OS kernel atop of L4Fiasco.OC. I'm having some difficulties to let my OS support user-level processes that uses floating-point instruction.
So far, My OS closely follows L4Linux, it creates a new task for each user-level process, and marks as all threads of the task as alien thread
to
capture all page faults and exceptions.
My OS works fines with page fault and syscalls. However, I'm confused
with
what I should do with floating-point exception (exception #7), which is issued to my kernel at the first time it tries to perform floating-point arithmetic.
I tried to return to the user-level process with an empty message ( l4_msgtag_t tag = l4_msgtag(0, 0, 0, 0) ), or an empty message with L4_MSGTAG_TRANSFER_FPU (l4_msgtag_t tag = l4_msgtag(0, 0, 0, L4_MSGTAG_TRANSFER_FPU) ), but I had no luck.
The user-level process immediately calls "int $0x3" and stops.
I read through L4Linux's code and it seems it's doing similar thing,
except
that it did initialize the FPU state before asking L4 to transfer the FPU state to user-level process.
I do not see anything (obvious) wrong. Can you pinpoint where the int3 is?
Adam
Adam adam@os.inf.tu-dresden.de Lackorzynski http://os.inf.tu-dresden.de/~adam/
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
Hi,
On Thu Apr 12, 2012 at 01:34:09 -0500, Mai, Haohui wrote:
I forgot to mention that my OS is running simultaneously with L4Linux.
In this case, it seems that Thread::transfer_fpu() becomes a no-op -- since the vcpu task for L4Linux has the FPU, but is the owner of FPU, and my OS doesn't. Therefore my OS cannot grant my user-level task the FPU since it doesn't have it.
However, my OS can grant the FPU to my user-level task, once I insert an floating-point instruction right before trying to grant my user-level process the FPU. In this case my OS magically becomes the owner of the FPU, and everything works smoothly.
What I really don't understand is that how this "magic" works. First, both L4Linux and my OS are started independently by ned:
(1) If FPU ownership can only be transferred via exception #7 and IPC, I don't understand why my OS can grab the FPU transparently, simply by executing an floating-point instruction.
First of all, the FPU is managed by the kernel transparently for threads, i.e. each thread gets its own FPU context, and this context is switched transparently between threads when they are scheduled. Now the special case is the exception handling, where it is possible to specify that the FPU shall be transfered back and forth. Looking at your example this possibility is indeed used. This makes it possible that the exception handler (aka kernel) can manage the FPU of other threads, i.e. it has to switch the context etc.
(2) If there's some transparent way that an process can get an FPU, then I don't understand why my user-level process can't grab the FPU transparently. Maybe this is because that my OS is a non-alien task but my user-level task is an alien?
Yes, exactly, this is due to the alien state of the user thread, in which case the exception is reflected to the handler. There, you put in the right FPU context and then let the thread continue with that.
Adam
Adam,
Thanks for your clarification.
One thing that I'm not still quite clear is that how to manage FPU context in my settings.
The main challenge here is that to keep track the "current" pointer (similar to the current pointer in L4Linux) -- otherwise it's difficult to save the FPU context.
My OS only handles page faults and syscalls, and delegates scheduling processes to L4 completely.
Handling page faults and syscalls is easy in the sense that the IPC messages have complete information.
However, It's not immediately clear to me that how to keep track of "current" pointer and to save / restore FPU context.
Do you have any comments on this one? I appreciate your help.
~Haohui
On Fri, Apr 13, 2012 at 4:05 AM, Adam Lackorzynski < adam@os.inf.tu-dresden.de> wrote:
Hi,
On Thu Apr 12, 2012 at 01:34:09 -0500, Mai, Haohui wrote:
I forgot to mention that my OS is running simultaneously with L4Linux.
In this case, it seems that Thread::transfer_fpu() becomes a no-op -- since the vcpu task for L4Linux has the FPU, but is the owner of FPU, and my OS doesn't. Therefore my OS cannot grant my user-level task the FPU since it doesn't have it.
However, my OS can grant the FPU to my user-level task, once I insert an floating-point instruction right before trying to grant my user-level process the FPU. In this case my OS magically becomes the owner of the
FPU,
and everything works smoothly.
What I really don't understand is that how this "magic" works. First,
both
L4Linux and my OS are started independently by ned:
(1) If FPU ownership can only be transferred via exception #7 and IPC, I don't understand why my OS can grab the FPU transparently, simply by executing an floating-point instruction.
First of all, the FPU is managed by the kernel transparently for threads, i.e. each thread gets its own FPU context, and this context is switched transparently between threads when they are scheduled. Now the special case is the exception handling, where it is possible to specify that the FPU shall be transfered back and forth. Looking at your example this possibility is indeed used. This makes it possible that the exception handler (aka kernel) can manage the FPU of other threads, i.e. it has to switch the context etc.
(2) If there's some transparent way that an process can get an FPU, then
I
don't understand why my user-level process can't grab the FPU transparently. Maybe this is because that my OS is a non-alien task but
my
user-level task is an alien?
Yes, exactly, this is due to the alien state of the user thread, in which case the exception is reflected to the handler. There, you put in the right FPU context and then let the thread continue with that.
Adam
Adam adam@os.inf.tu-dresden.de Lackorzynski http://os.inf.tu-dresden.de/~adam/
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
On Fri Apr 13, 2012 at 13:33:54 -0500, Mai, Haohui wrote:
Adam,
Thanks for your clarification.
One thing that I'm not still quite clear is that how to manage FPU context in my settings.
The main challenge here is that to keep track the "current" pointer (similar to the current pointer in L4Linux) -- otherwise it's difficult to save the FPU context.
My OS only handles page faults and syscalls, and delegates scheduling processes to L4 completely.
Handling page faults and syscalls is easy in the sense that the IPC messages have complete information.
However, It's not immediately clear to me that how to keep track of "current" pointer and to save / restore FPU context.
Do you have any comments on this one? I appreciate your help.
Ok, then the question actually is why your user processes are running as aliens at all. Receiving page-faults and other exceptions does not depend on being an alien. This also works without it. Then the kernel would just handle the FPU transparently for the threads and your handler thread does not need to care about that.
Adam
Hi,
I think alien is still essential since I plan to run Linux binary directly on top of my OS, thus I don't really want them to call L4 API directly.
If alien thread is required, what would be the best way of doing it?
~Haohui
On Mon, Apr 16, 2012 at 5:25 PM, Adam Lackorzynski < adam@os.inf.tu-dresden.de> wrote:
On Fri Apr 13, 2012 at 13:33:54 -0500, Mai, Haohui wrote:
Adam,
Thanks for your clarification.
One thing that I'm not still quite clear is that how to manage FPU
context
in my settings.
The main challenge here is that to keep track the "current" pointer (similar to the current pointer in L4Linux) -- otherwise it's difficult
to
save the FPU context.
My OS only handles page faults and syscalls, and delegates scheduling processes to L4 completely.
Handling page faults and syscalls is easy in the sense that the IPC messages have complete information.
However, It's not immediately clear to me that how to keep track of "current" pointer and to save / restore FPU context.
Do you have any comments on this one? I appreciate your help.
Ok, then the question actually is why your user processes are running as aliens at all. Receiving page-faults and other exceptions does not depend on being an alien. This also works without it. Then the kernel would just handle the FPU transparently for the threads and your handler thread does not need to care about that.
Adam
Adam adam@os.inf.tu-dresden.de Lackorzynski http://os.inf.tu-dresden.de/~adam/
l4-hackers mailing list l4-hackers@os.inf.tu-dresden.de http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
Hi,
On Mon Apr 16, 2012 at 17:34:05 -0500, Mai, Haohui wrote:
I think alien is still essential since I plan to run Linux binary directly on top of my OS, thus I don't really want them to call L4 API directly.
If alien thread is required, what would be the best way of doing it?
I haven't checked closely now but if you just touch the FPU in the handler thread and then transmit it, it should work so that any is getting an FPU state. And you probably do not want to have it back then. On the other side, in your execution model, I think you don't even need to forbit doing any L4 call, I should just work.
Adam
l4-hackers@os.inf.tu-dresden.de