Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- config/config-i386.mak | 2 ++ config/config-x86-common.mak | 4 +++- config/config-x86_64.mak | 2 ++ lib/setjmp.h | 12 ++++++++++++ lib/x86/setjmp32.S | 25 +++++++++++++++++++++++++ lib/x86/setjmp64.S | 27 +++++++++++++++++++++++++++ x86/setjmp.c | 19 +++++++++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 lib/setjmp.h create mode 100644 lib/x86/setjmp32.S create mode 100644 lib/x86/setjmp64.S create mode 100644 x86/setjmp.c
diff --git a/config/config-i386.mak b/config/config-i386.mak index 691381c..e353387 100644 --- a/config/config-i386.mak +++ b/config/config-i386.mak @@ -3,6 +3,8 @@ bits = 32 ldarch = elf32-i386 CFLAGS += -I $(KERNELDIR)/include +cflatobjs += lib/x86/setjmp32.o + tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat \ $(TEST_DIR)/cmpxchg8b.flat diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index f64874d..2bb2f46 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -34,7 +34,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \ $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \ $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/eventinj.flat \ - $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ + $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat $(TEST_DIR)/setjmp.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ $(TEST_DIR)/hyperv_synic.flat @@ -115,6 +115,8 @@ $(TEST_DIR)/memory.elf: $(cstart.o) $(TEST_DIR)/memory.o $(TEST_DIR)/hyperv_synic.elf: $(cstart.o) $(TEST_DIR)/hyperv_synic.o +$(TEST_DIR)/setjmp.elf: $(cstart.o) $(TEST_DIR)/setjmp.o + arch_clean: $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ $(TEST_DIR)/.*.d lib/x86/.*.d diff --git a/config/config-x86_64.mak b/config/config-x86_64.mak index 1764701..d190be8 100644 --- a/config/config-x86_64.mak +++ b/config/config-x86_64.mak @@ -3,6 +3,8 @@ bits = 64 ldarch = elf64-x86-64 CFLAGS += -mno-red-zone +cflatobjs += lib/x86/setjmp64.o + tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \ $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \ diff --git a/lib/setjmp.h b/lib/setjmp.h new file mode 100644 index 0000000..334f466 --- /dev/null +++ b/lib/setjmp.h @@ -0,0 +1,12 @@ +#ifndef LIBCFLAT_SETJMP_H +#define LIBCFLAT_SETJMP_H 1 + +typedef struct jmp_buf_tag { + long int regs[8]; +} jmp_buf[1]; + +extern int setjmp (struct jmp_buf_tag env[1]); +extern void longjmp (struct jmp_buf_tag env[1], int val) + __attribute__ ((__noreturn__)); + +#endif /* setjmp.h */ diff --git a/lib/x86/setjmp32.S b/lib/x86/setjmp32.S new file mode 100644 index 0000000..b0be7c2 --- /dev/null +++ b/lib/x86/setjmp32.S @@ -0,0 +1,25 @@ +.globl setjmp +setjmp: + mov (%esp), %ecx // get return EIP + mov 4(%esp), %eax // get jmp_buf + mov %ecx, (%eax) + mov %esp, 4(%eax) + mov %ebp, 8(%eax) + mov %ebx, 12(%eax) + mov %esi, 16(%eax) + mov %edi, 20(%eax) + xor %eax, %eax + ret + +.globl longjmp +longjmp: + mov 8(%esp), %eax // get return value + mov 4(%esp), %ecx // get jmp_buf + mov 20(%ecx), %edi + mov 16(%ecx), %esi + mov 12(%ecx), %ebx + mov 8(%ecx), %ebp + mov 4(%ecx), %esp + mov (%ecx), %ecx // get saved EIP + mov %ecx, (%esp) // and store it on the stack + ret diff --git a/lib/x86/setjmp64.S b/lib/x86/setjmp64.S new file mode 100644 index 0000000..c8ae790 --- /dev/null +++ b/lib/x86/setjmp64.S @@ -0,0 +1,27 @@ +.globl setjmp +setjmp: + mov (%rsp), %rsi + mov %rsi, (%rdi) + mov %rsp, 0x8(%rdi) + mov %rbp, 0x10(%rdi) + mov %rbx, 0x18(%rdi) + mov %r12, 0x20(%rdi) + mov %r13, 0x28(%rdi) + mov %r14, 0x30(%rdi) + mov %r15, 0x38(%rdi) + xor %eax, %eax + ret + +.globl longjmp +longjmp: + mov %esi, %eax + mov 0x38(%rdi), %r15 + mov 0x30(%rdi), %r14 + mov 0x28(%rdi), %r13 + mov 0x20(%rdi), %r12 + mov 0x18(%rdi), %rbx + mov 0x10(%rdi), %rbp + mov 0x8(%rdi), %rsp + mov (%rdi), %rsi + mov %rsi, (%rsp) + ret diff --git a/x86/setjmp.c b/x86/setjmp.c new file mode 100644 index 0000000..46f0d9c --- /dev/null +++ b/x86/setjmp.c @@ -0,0 +1,19 @@ +#include "stdio.h" +#include "setjmp.h" + +int main() +{ + volatile int i; + jmp_buf j; + + if (setjmp(j) == 0) { + i = 0; + } + printf("%d\n", i); + if (++i < 10) { + longjmp(j, 1); + } + + printf("done\n"); + return 0; +} -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html