1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

interrupt handling rewrite

(including uart0 integration, rt-extension removal)
This commit is contained in:
Ludwig Ortmann 2013-05-14 18:31:47 +02:00
parent 2d29a26b64
commit c6553f6492
9 changed files with 232 additions and 130 deletions

View File

@ -1,5 +1,8 @@
ASMSRC = $(wildcard *.s) ASMSRC = $(wildcard *.s)
ASSMSRC = $(wildcard *.S)
ASMOBJ = $(ASMSRC:%.s=$(BINDIR)%.o) ASMOBJ = $(ASMSRC:%.s=$(BINDIR)%.o)
ASMOBJ += $(ASSMSRC:%.S=$(BINDIR)%.o)
SRC = $(wildcard *.c) SRC = $(wildcard *.c)
OBJ = $(SRC:%.c=$(BINDIR)%.o) OBJ = $(SRC:%.c=$(BINDIR)%.o)
DEP = $(SRC:%.c=$(BINDIR)%.d) DEP = $(SRC:%.c=$(BINDIR)%.d)
@ -7,8 +10,8 @@ DEP = $(SRC:%.c=$(BINDIR)%.d)
include $(RIOTCPU)/Makefile.base include $(RIOTCPU)/Makefile.base
include $(RIOTBOARD)/Makefile.base include $(RIOTBOARD)/Makefile.base
$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) $(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) $(ASSMOBJ)
$(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ) $(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ) $(ASSMOBJ)
# pull in dependency info for *existing* .o files # pull in dependency info for *existing* .o files
-include $(OBJ:.o=.d) -include $(OBJ:.o=.d)
@ -22,7 +25,10 @@ $(BINDIR)%.o: %.c
$(BINDIR)%.o: %.s $(BINDIR)%.o: %.s
@$(AS) $(ASFLAGS) $*.s -o $(BINDIR)$*.o @$(AS) $(ASFLAGS) $*.s -o $(BINDIR)$*.o
$(BINDIR)%.o: %.S
@gcc -c -m32 $*.S -o $(BINDIR)$*.o
# remove compilation products # remove compilation products
clean:: clean::
rm -f $(BINDIR)$(MODULE).a $(OBJ) $(DEP) $(ASMOBJ) rm -f $(BINDIR)$(MODULE).a $(OBJ) $(DEP) $(ASMOBJ) $(ASSMOBJ)

View File

@ -17,7 +17,9 @@
#include <tcb.h> #include <tcb.h>
/** Minimum stack size */ /** Minimum stack size */
#ifndef MINIMUM_STACK_SIZE
#define MINIMUM_STACK_SIZE (sizeof(tcb_t)) #define MINIMUM_STACK_SIZE (sizeof(tcb_t))
#endif
/** /**
* @brief Creates a new thread. * @brief Creates a new thread.

View File

@ -34,6 +34,8 @@
#include "debug.h" #include "debug.h"
#define HWTIMERMINOFFSET 1000
static unsigned long native_hwtimer_now; static unsigned long native_hwtimer_now;
static int native_hwtimer_irq[ARCH_MAXTIMERS]; static int native_hwtimer_irq[ARCH_MAXTIMERS];
@ -172,6 +174,10 @@ void hwtimer_arch_unset(short timer)
void hwtimer_arch_set(unsigned long offset, short timer) void hwtimer_arch_set(unsigned long offset, short timer)
{ {
DEBUG("hwtimer_arch_set(%li, %i)\n", offset, timer); DEBUG("hwtimer_arch_set(%li, %i)\n", offset, timer);
if (offset < HWTIMERMINOFFSET) {
offset = HWTIMERMINOFFSET;
DEBUG("hwtimer_arch_set: offset < MIN, set to: %i\n", offset);
}
native_hwtimer_irq[timer] = 1; native_hwtimer_irq[timer] = 1;
native_hwtimer_isset[timer] = 1; native_hwtimer_isset[timer] = 1;

View File

@ -18,9 +18,10 @@
/* TODO: choose more sensibly? */ /* TODO: choose more sensibly? */
#define KERNEL_CONF_STACKSIZE_DEFAULT (16384) #define KERNEL_CONF_STACKSIZE_DEFAULT (16384)
#define KERNEL_CONF_STACKSIZE_IDLE (4096) #define KERNEL_CONF_STACKSIZE_IDLE (16384)
#define NATIVE_ISR_STACKSIZE (16384) #define NATIVE_ISR_STACKSIZE (16384)
#define TRANSCEIVER_STACK_SIZE (16384) #define TRANSCEIVER_STACK_SIZE (16384)
#define MINIMUM_STACK_SIZE (1024)
/* for cc110x_ng */ /* for cc110x_ng */
#define RX_BUF_SIZE (10) #define RX_BUF_SIZE (10)

View File

@ -46,6 +46,11 @@ int unregister_interrupt(int sig);
/* this should be defined elsewhere */ /* this should be defined elsewhere */
void thread_yield(void); void thread_yield(void);
extern volatile ucontext_t *interrupted_contexts[MAXTHREADS]; extern void _native_sig_leave_tramp(void);
extern ucontext_t *_native_cur_ctx, *_native_isr_ctx;
extern unsigned int _native_saved_eip;
extern int _native_in_isr;
extern int _native_in_syscall;
extern int _native_sigpend;
/** @} */ /** @} */
#endif //_CPU_H #endif //_CPU_H

View File

@ -1,9 +1,6 @@
/** /**
* Native CPU irq.h implementation * Native CPU irq.h implementation
* *
* uses POSIX real-time extension signals to create interrupts
* TODO: needs to be rewritten for better portability
*
* Copyright (C) 2013 Ludwig Ortmann * Copyright (C) 2013 Ludwig Ortmann
* *
* This file subject to the terms and conditions of the GNU General Public * This file subject to the terms and conditions of the GNU General Public
@ -15,29 +12,41 @@
* @file * @file
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> * @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de>
*/ */
#include <signal.h>
#include <err.h> #include <err.h>
#include <string.h>
#include <unistd.h>
#include <irq.h> // __USE_GNU for gregs[REG_EIP] access
#define __USE_GNU
#include <signal.h>
#undef __USE_GNU
#include "irq.h"
#include "cpu.h" #include "cpu.h"
#include "debug.h" #include "debug.h"
static int native_interrupts_enabled; static int native_interrupts_enabled;
static int native_in_irs;
static int last_sig; int _native_sigpend;
static ucontext_t native_context; int _native_in_isr;
int _native_in_syscall;
static ucontext_t native_isr_context;
static sigset_t native_sig_set; static sigset_t native_sig_set;
static char __isr_stack[SIGSTKSZ]; static char __isr_stack[SIGSTKSZ];
extern volatile tcb_t *active_thread; extern volatile tcb_t *active_thread;
unsigned int _native_saved_eip;
ucontext_t *_native_cur_ctx, *_native_isr_ctx;
int _native_in_isr;
static int pipefd[2];
struct int_handler_t { struct int_handler_t {
void (*func)(void); void (*func)(void);
}; };
static struct int_handler_t native_irq_handlers[255]; static struct int_handler_t native_irq_handlers[255];
char sigalt_stk[SIGSTKSZ];
volatile ucontext_t *interrupted_contexts[MAXTHREADS];
void print_thread_sigmask(ucontext_t *cp) void print_thread_sigmask(ucontext_t *cp)
{ {
@ -113,6 +122,7 @@ unsigned disableIRQ(void)
unsigned int prev_state; unsigned int prev_state;
sigset_t mask; sigset_t mask;
_native_in_syscall = 1;
DEBUG("disableIRQ()\n"); DEBUG("disableIRQ()\n");
if (sigfillset(&mask) == -1) { if (sigfillset(&mask) == -1) {
@ -132,6 +142,16 @@ unsigned disableIRQ(void)
} }
prev_state = native_interrupts_enabled; prev_state = native_interrupts_enabled;
native_interrupts_enabled = 0; native_interrupts_enabled = 0;
if (_native_sigpend > 0) {
DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n");
_native_in_syscall = 0;
printf("calling swapcontext()\n");
swapcontext(_native_cur_ctx, _native_isr_ctx);
}
else {
_native_in_syscall = 0;
}
DEBUG("disableIRQ(): return\n");
return prev_state; return prev_state;
} }
@ -143,6 +163,7 @@ unsigned enableIRQ(void)
{ {
unsigned int prev_state; unsigned int prev_state;
_native_in_syscall = 1;
DEBUG("enableIRQ()\n"); DEBUG("enableIRQ()\n");
if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) { if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) {
@ -153,6 +174,16 @@ unsigned enableIRQ(void)
//print_sigmasks(); //print_sigmasks();
//native_print_signals(); //native_print_signals();
if (_native_sigpend > 0) {
DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n");
_native_in_syscall = 0;
printf("calling swapcontext()\n");
swapcontext(_native_cur_ctx, _native_isr_ctx);
}
else {
_native_in_syscall = 0;
}
DEBUG("enableIRQ(): return\n");
return prev_state; return prev_state;
} }
@ -172,8 +203,8 @@ void restoreIRQ(unsigned state)
int inISR(void) int inISR(void)
{ {
DEBUG("inISR()\n"); DEBUG("inISR(): %i\n", _native_in_isr);
return native_in_irs; return _native_in_isr;
} }
@ -187,104 +218,86 @@ void eINT(void)
enableIRQ(); enableIRQ();
} }
int _native_popsig(void)
{
int nread, nleft, i;
int sig;
nleft = sizeof(int);
i = 0;
while ((nleft>0) && ((nread = read(pipefd[0], &sig + i, nleft)) != -1)) {
i += nread;
nleft -= nread;
}
if (nread == -1) {
err(1, "_native_popsig(): read()");
}
return sig;
}
/** /**
* call signal handler, * call signal handlers,
* restore user context * restore user context
*/ */
void native_irq_handler() void native_irq_handler()
{ {
if (last_sig == -1) { int sig;
errx(1, "XXX: internal error");
DEBUG("\n\n\t\tnative_irq_handler\n\n");
while (_native_sigpend > 0) {
sig = _native_popsig();
_native_sigpend--;
if (native_irq_handlers[sig].func != NULL) {
DEBUG("calling interrupt handler for %i\n", sig);
native_irq_handlers[sig].func();
}
else if (sig == SIGUSR1) {
DEBUG("ignoring SIGUSR1\n");
}
else {
printf("XXX: no handler for signal %i\n", sig);
errx(1, "XXX: this should not have happened!\n");
}
} }
if (native_irq_handlers[last_sig].func != NULL) { DEBUG("native_irq_handler(): return");
DEBUG("calling interrupt handler for %i\n", last_sig); _native_in_isr = 0;
native_irq_handlers[last_sig].func();
}
else if (last_sig == SIGUSR1) {
DEBUG("ignoring SIGUSR1\n");
}
else {
printf("XXX: no handler for signal %i\n", last_sig);
errx(1, "XXX: this should not have happened!\n");
}
last_sig = -1;
native_in_irs = 0;
cpu_switch_context_exit(); cpu_switch_context_exit();
} }
/** /**
* load isr context, save signal * save signal, return to _native_sig_leave_tramp if possible
*/ */
void native_isr_entry(int sig, siginfo_t *info, void *context) void native_isr_entry(int sig, siginfo_t *info, void *context)
{ {
/* DEBUG("\n\n\t\tnative_isr_entry\n\n");
* This is how it goes: if (native_interrupts_enabled == 0) {
* We create a new context "R" for the RIOT interrupt service errx(1, "interrupts are off, but I caught a signal.");
* routine. }
* We save the current (signalhandler) context "S" to the active
* threads context.
* We then jump into the R context.
* Later, when jumping back into "S", we start out in the signal
* handler context only to immediately return into the context we
* originally left. This step is done by the kernel for us.
*
* So the thing to wrap your head around is that the active thread
* remains within in the signal handler context (which is pushed
* onto the active threads own stack by swapcontext) until the
* thread is activated again, at which point the kernel handles
* the context switch back onto the interrupted context for us.
* */
/* save the signal */ /* save the signal */
last_sig = sig; if (write(pipefd[1], &sig, sizeof(int)) == -1) {
err(1, "native_isr_entry(): write()");
}
_native_sigpend++;
/* indicate irs status */ /* indicate irs status */
native_in_irs = 1;
if (getcontext(&native_context) == -1) { makecontext(&native_isr_context, native_irq_handler, 0);
err(1, "native_isr_entry(): getcontext()"); _native_cur_ctx = (ucontext_t*)active_thread->sp;
}
native_context.uc_stack.ss_sp = __isr_stack; if (_native_in_syscall == 0) {
native_context.uc_stack.ss_size = SIGSTKSZ; _native_in_isr = 1;
native_context.uc_stack.ss_flags = 0; DEBUG("\n\n\t\treturn to _native_sig_leave_tramp\n\n");
_native_saved_eip = ((ucontext_t*)context)->uc_mcontext.gregs[REG_EIP];
/* XXX: disable interrupts ((ucontext_t*)context)->uc_mcontext.gregs[REG_EIP] = (unsigned int)&_native_sig_leave_tramp;
* -> sigfillset(&(native_context.uc_sigmask)); // TODO: change sigmask?
* else: */
//sigemptyset(&(native_context.uc_sigmask));
if (sigfillset(&(native_context.uc_sigmask)) == -1) {
err(1, "native_isr_entry(): sigfillset()");
}
makecontext(&native_context, native_irq_handler, 0);
#ifdef NATIVEUSESWAPCONTEXT
/**
* XXX:
* This seems to be the cause of undefined behavior. Try saving
* the context passed to this function and using setcontext to
* leave the handler.
* Also it is probably wise to makecontext the isr context
* elsewehere.
* */
if ((swapcontext((ucontext_t*)active_thread->sp, &native_context)) == -1) {
err(1, "swapcontext failed");
} }
else { else {
DEBUG("returning to interrupted thread\n"); DEBUG("\n\n\t\treturn to syscall\n\n");
} }
native_in_irs = 0;
enableIRQ();
#else
interrupted_contexts[thread_getpid()] = context;
/**
* signal masks are broken
*/
//active_thread->sp = context;
setcontext(&native_context);
DEBUG("\n\n\tnever reached\n\n\n");
#endif
} }
/** /**
@ -312,7 +325,7 @@ int register_interrupt(int sig, void *handler)
err(1, "register_interrupt: sigemptyset"); err(1, "register_interrupt: sigemptyset");
} }
sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
if (sigaction(sig, &sa, NULL)) { if (sigaction(sig, &sa, NULL)) {
err(1, "register_interrupt: sigaction"); err(1, "register_interrupt: sigaction");
@ -342,7 +355,7 @@ int unregister_interrupt(int sig)
if (sigemptyset(&sa.sa_mask) == -1) { if (sigemptyset(&sa.sa_mask) == -1) {
err(1, "unregister_interrupt: sigemptyset"); err(1, "unregister_interrupt: sigemptyset");
} }
sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
if (sigaction(sig, &sa, NULL)) { if (sigaction(sig, &sa, NULL)) {
err(1, "unregister_interrupt: sigaction"); err(1, "unregister_interrupt: sigaction");
@ -363,6 +376,7 @@ void native_interrupt_init(void)
DEBUG("XXX: native_interrupt_init()\n"); DEBUG("XXX: native_interrupt_init()\n");
native_interrupts_enabled = 1; native_interrupts_enabled = 1;
_native_sigpend = 0;
for (int i = 0; i<255; i++) { for (int i = 0; i<255; i++) {
native_irq_handlers[i].func = NULL; native_irq_handlers[i].func = NULL;
@ -372,7 +386,7 @@ void native_interrupt_init(void)
if (sigemptyset(&sa.sa_mask) == -1) { if (sigemptyset(&sa.sa_mask) == -1) {
err(1, "native_interrupt_init: sigemptyset"); err(1, "native_interrupt_init: sigemptyset");
} }
sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
/* /*
if (sigemptyset(&native_sig_set) == -1) { if (sigemptyset(&native_sig_set) == -1) {
@ -391,19 +405,31 @@ void native_interrupt_init(void)
err(1, "native_interrupt_init: sigaction"); err(1, "native_interrupt_init: sigaction");
} }
if (sigdelset(&native_sig_set, SIGALRM) == -1) { if (getcontext(&native_isr_context) == -1) {
err(1, "native_interrupt_init: sigdelset"); err(1, "native_isr_entry(): getcontext()");
} }
if (sigaction(SIGALRM, &sa, NULL)) { if (sigfillset(&(native_isr_context.uc_sigmask)) == -1) {
err(1, "native_interrupt_init: sigaction"); err(1, "native_isr_entry(): sigfillset()");
}
if (sigprocmask(SIG_SETMASK, &native_sig_set, NULL) == -1) {
err(1, "native_interrupt_init(): sigprocmask");
} }
native_isr_context.uc_stack.ss_sp = __isr_stack;
native_isr_context.uc_stack.ss_size = SIGSTKSZ;
native_isr_context.uc_stack.ss_flags = 0;
_native_isr_ctx = &native_isr_context;
for (int i = 0; i<MAXTHREADS; i++) { static stack_t sigstk;
interrupted_contexts[i] = NULL; sigstk.ss_sp = sigalt_stk;
sigstk.ss_size = SIGSTKSZ;
sigstk.ss_flags = 0;
if (sigaltstack(&sigstk, NULL) < 0) {
err(1, "main: sigaltstack");
}
makecontext(&native_isr_context, native_irq_handler, 0);
_native_in_syscall = 0;
if (pipe(pipefd) == -1) {
err(1, "native_interrupt_init(): pipe()");
} }
puts("RIOT native interrupts/signals initialized."); puts("RIOT native interrupts/signals initialized.");

View File

@ -18,9 +18,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#ifdef MODULE_UART0
#include <sys/select.h>
#include <errno.h>
#endif
#include "lpm.h" #include "lpm.h"
#include "debug.h" #include "debug.h"
#include "cpu.h"
#ifdef MODULE_UART0
#include "board.h"
#endif
static enum lpm_mode native_lpm; static enum lpm_mode native_lpm;
@ -31,6 +39,32 @@ void lpm_init(void)
return; return;
} }
void _native_lpm_sleep()
{
#ifdef MODULE_UART0
int retval;
retval = select(1, &_native_uart_rfds, NULL, NULL, NULL);
DEBUG("_native_lpm_sleep: retval: %i\n", retval);
if (retval != -1) {
DEBUG("\n\n\t\treturn from syscall, calling _native_handle_uart0_input\n\n");
makecontext(_native_isr_ctx, _native_handle_uart0_input, 0);
swapcontext(_native_cur_ctx, _native_isr_ctx);
}
else if (errno != EINTR) {
err(1, "lpm_set(): select()");
}
#else
pause();
#endif
if (_native_sigpend > 0) {
DEBUG("\n\n\t\treturn from syscall, calling native_irq_handler\n\n");
_native_in_syscall = 0;
_native_in_isr = 1;
swapcontext(_native_cur_ctx, _native_isr_ctx);
}
}
/** /**
* LPM_IDLE uses sleep() to wait for interrupts * LPM_IDLE uses sleep() to wait for interrupts
* LPM_OFF exits process * LPM_OFF exits process
@ -40,7 +74,7 @@ enum lpm_mode lpm_set(enum lpm_mode target)
{ {
enum lpm_mode last_lpm; enum lpm_mode last_lpm;
DEBUG("lpm_set(%i)\n", target); //DEBUG("lpm_set(%i)\n", target);
last_lpm = native_lpm; last_lpm = native_lpm;
native_lpm = target; native_lpm = target;
@ -51,8 +85,11 @@ enum lpm_mode lpm_set(enum lpm_mode target)
break; break;
case LPM_IDLE: case LPM_IDLE:
DEBUG("lpm_set(): pause()\n"); //DEBUG("lpm_set(): pause()\n");
pause();
_native_in_syscall = 1;
//pause();
_native_lpm_sleep();
break; break;
/* XXX: unfinished modes: */ /* XXX: unfinished modes: */

View File

@ -26,7 +26,7 @@
#include "debug.h" #include "debug.h"
extern volatile tcb_t *active_thread; extern volatile tcb_t *active_thread;
static ucontext_t native_context; static ucontext_t end_context;
static char __isr_stack[SIGSTKSZ]; static char __isr_stack[SIGSTKSZ];
/** /**
@ -63,7 +63,7 @@ char *thread_stack_init(void *task_func, void *stack_start, int stacksize)
p->uc_stack.ss_sp = stk; p->uc_stack.ss_sp = stk;
p->uc_stack.ss_size = stacksize; p->uc_stack.ss_size = stacksize;
p->uc_stack.ss_flags = 0; p->uc_stack.ss_flags = 0;
p->uc_link = &native_context; p->uc_link = &end_context;
if (sigemptyset(&(p->uc_sigmask)) == -1) { if (sigemptyset(&(p->uc_sigmask)) == -1) {
err(1, "thread_stack_init(): sigemptyset()"); err(1, "thread_stack_init(): sigemptyset()");
} }
@ -82,13 +82,8 @@ void cpu_switch_context_exit(void)
sched_run(); sched_run();
DEBUG("XXX: cpu_switch_context_exit(): calling setcontext(%s)\n\n", active_thread->name); DEBUG("XXX: cpu_switch_context_exit(): calling setcontext(%s)\n\n", active_thread->name);
if (interrupted_contexts[thread_getpid()] == NULL) { ctx = (ucontext_t*)(active_thread->sp);
ctx = (ucontext_t*)(active_thread->sp); eINT(); // XXX: workaround for bug (?) in sched_task_exit
}
else {
ctx = interrupted_contexts[thread_getpid()];
interrupted_contexts[thread_getpid()] = NULL;
}
if (setcontext(ctx) == -1) { if (setcontext(ctx) == -1) {
err(1, "cpu_switch_context_exit(): setcontext():"); err(1, "cpu_switch_context_exit(): setcontext():");
} }
@ -103,13 +98,7 @@ void thread_yield()
DEBUG("thread_yield()\n"); DEBUG("thread_yield()\n");
if (interrupted_contexts[thread_getpid()] == NULL) { oc = (ucontext_t*)(active_thread->sp);
oc = (ucontext_t*)(active_thread->sp);
}
else {
oc = interrupted_contexts[thread_getpid()];
interrupted_contexts[thread_getpid()] = NULL;
}
sched_run(); sched_run();
@ -127,13 +116,14 @@ void thread_yield()
void native_cpu_init() void native_cpu_init()
{ {
if (getcontext(&native_context) == -1) { if (getcontext(&end_context) == -1) {
err(1, "native_context(): getcontext()"); err(1, "end_context(): getcontext()");
} }
native_context.uc_stack.ss_sp = __isr_stack; end_context.uc_stack.ss_sp = __isr_stack;
native_context.uc_stack.ss_size = SIGSTKSZ; end_context.uc_stack.ss_size = SIGSTKSZ;
native_context.uc_stack.ss_flags = 0; end_context.uc_stack.ss_flags = 0;
makecontext(&native_context, sched_task_exit, 0); makecontext(&end_context, sched_task_exit, 0);
puts("RIOT native cpu initialized."); puts("RIOT native cpu initialized.");
} }
/** @} */ /** @} */

29
cpu/native/tramp.S Normal file
View File

@ -0,0 +1,29 @@
.text
.extern $_native_saved_eip
.extern $_native_isr_ctx
.extern $_native_cur_ctx
.extern $_native_in_isr
.globl _native_sig_leave_tramp
_native_sig_leave_tramp:
pushl %eax
pushf
pushl %ebp
pushl %esp
movl %esp, %ebp
subl $24, %esp
movl $_native_isr_ctx, 4(%esp)
movl $_native_cur_ctx, (%esp)
call swapcontext
addl $24, %esp
popl %esp
popl %ebp
popf
popl %eax
movl $0x0, _native_in_isr;
jmp *_native_saved_eip