vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

commit ca1bfbd9fc9043c99d6c1d4f97caca6ac676bb70
parent 04c6b5b7c2535cf384926b6ccdce3dbeb0c78651
Author: Russ Cox <rsc@swtch.com>
Date:   Sun,  7 Dec 2008 20:18:46 -0800

libvx32: build on x86-64 using gcc 4.3.2

Diffstat:
src/libvx32/Makefrag | 1-
src/libvx32/asm.h | 25-------------------------
src/libvx32/elf.c | 6++++--
src/libvx32/emu.c | 4++--
src/libvx32/linux-asm.S | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/libvx32/linux.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++----
src/libvx32/rts.S | 4++--
src/libvx32/run32.S | 4++--
src/libvx32/run64.S | 4++--
src/libvx32/sig.c | 2+-
src/libvx32/vx32impl.h | 2++
src/libvx32/x86dis.c | 6+++---
12 files changed, 124 insertions(+), 46 deletions(-)

diff --git a/src/libvx32/Makefrag b/src/libvx32/Makefrag @@ -52,4 +52,3 @@ libvx32/libvx32.a: $(VX32_OBJS) $(prefix)/lib/libvx32.a: libvx32/libvx32.a $(INSTALL) $< $@ - diff --git a/src/libvx32/asm.h b/src/libvx32/asm.h @@ -1,25 +0,0 @@ -#define ASDF 12345 -#define VXEMU_DATASEL 12 -#define VXEMU_EMUSEL 16 -#define VXEMU_EMUPTR 28 -#define VXEMU_REG 32 -#define VXEMU_EAX 32 -#define VXEMU_ECX 36 -#define VXEMU_EDX 40 -#define VXEMU_EBX 44 -#define VXEMU_ESP 48 -#define VXEMU_EBP 52 -#define VXEMU_ESI 56 -#define VXEMU_EDI 60 -#define VXEMU_EIP 64 -#define VXEMU_EFLAGS 68 -#define VXEMU_TRAPNO 80 -#define VXEMU_JMPINFO 100 -#define VXEMU_HOST_SS 124 -#define VXEMU_HOST_DS 126 -#define VXEMU_HOST_ES 128 -#define VXEMU_HOST_VS 130 -#define VXEMU_HOST_ESP 132 -#define VXEMU_ETABLEN 152 -#define VXEMU_ETABMASK 156 -#define VXEMU_ETAB 164 diff --git a/src/libvx32/elf.c b/src/libvx32/elf.c @@ -153,10 +153,12 @@ static int elfloader(vxproc *proc, // For "big mem" we need more than 1/2 GB, but 64-bit Linux // has only about 1 GB of address space to give out with MAP_32BIT, // and we've used up some of it for the vxemu structure. - // Ask for (1<<30) - (1<<24), which should be close enough to 1GB + // Used to ask for (1<<30) - (1<<24), which should be close enough to 1GB // to run the SPEC programs but leave enough for things like vxemu. + // On Ubuntu 8.10, I get intermittent ouf of memory errors from this + // mmap, so back off to 1<<29. if (vx_elfbigmem) - size = (1<<30) - (1<<24); + size = (1<<29); mm = NULL; diff --git a/src/libvx32/emu.c b/src/libvx32/emu.c @@ -26,7 +26,7 @@ // Special values for unused entries in entrypoint hash table #define NULLSRCEIP ((uint32_t)-1) -#define NULLDSTEIP ((uint32_t)vxrun_nullfrag); +#define NULLDSTEIP ((uint32_t)(uintptr_t)vxrun_nullfrag); int vx32_debugxlate = 0; @@ -1904,6 +1904,6 @@ void vxprint(char *fmt, ...) va_start(arg, fmt); vsnprintf(buf, sizeof buf, fmt, arg); va_end(arg); - write(2, buf, strlen(buf)); + USED(write(2, buf, strlen(buf))); } diff --git a/src/libvx32/linux-asm.S b/src/libvx32/linux-asm.S @@ -6,6 +6,8 @@ // notice also that unlike the linux getcontext, // we *do* copy the segment registers +#ifdef i386 + .globl vx32_getcontext vx32_getcontext: movl 4(%esp), %eax @@ -33,8 +35,10 @@ vx32_getcontext: /* 56(%eax) is eip */ movw %cs, %cx movl %ecx, 60(%eax) - pushfl - popl 64(%eax) + pushf + movl 0(%esp), %ecx + popf + movl %ecx, 64(%eax) /* 68(%eax) is another esp */ movw %ss, %cx movl %ecx, 72(%eax) @@ -49,3 +53,53 @@ vx32_getcontext: movl $0, %eax ret +#else /* x86-64 */ + +.globl vx32_getcontext +vx32_getcontext: + // mcontext_t pointer is in %rdi + movq %r8, 0(%rdi) + movq %r9, 8(%rdi) + movq %r10, 16(%rdi) + movq %r11, 24(%rdi) + movq %r12, 32(%rdi) + movq %r13, 40(%rdi) + movq %r14, 48(%rdi) + movq %r15, 56(%rdi) + movq %rdi, 64(%rdi) + movq %rsi, 72(%rdi) + movq %rbp, 80(%rdi) + movq %rbx, 88(%rdi) + movq %rdx, 96(%rdi) + movq $1, 104(%rdi) /* %rax */ + movq %rcx, 112(%rdi) + /* 120(%rdi) is rsp */ + leaq 8(%rsp), %rax + movq %rax, 120(%rdi) + /* 128(%rdi) is rip */ + movq 0(%rsp), %rax + movq %rax, 128(%rdi) + /* 136(%rdi) is eflags */ + pushf + popq %rax + movq %rax, 136(%rdi) + /* 144(%rdi) is cs, gs, fs, pad */ + xorq %rax, %rax + movw %fs, %ax + shlq $16, %rax + movw %gs, %ax + shlq $16, %rax + movw %cs, %ax + movq %rax, 144(%rdi) + /* 152(%rdi) is err */ + movq $0, 152(%rdi) + /* 160(%rdi) is trapno */ + movq $0, 160(%rdi) + /* 168(%rdi) is oldmask */ + movq $0, 168(%rdi) + /* 176(%rdi) is cr2 */ + movq $0, 176(%rdi) + movq $0, %rax + ret + +#endif diff --git a/src/libvx32/linux.c b/src/libvx32/linux.c @@ -8,6 +8,7 @@ #include <ucontext.h> #include <sys/ucontext.h> #include <asm/ldt.h> +#include <errno.h> #include "vx32.h" #include "vx32impl.h" @@ -19,6 +20,7 @@ int vxemu_map(vxemu *emu, vxmmap *mm) { struct vxproc *vxp; struct user_desc desc; + uint ldt[2]; #ifdef __x86_64 static int didflat; #endif @@ -73,13 +75,55 @@ int vxemu_map(vxemu *emu, vxmmap *mm) desc.seg_not_present = 0; desc.useable = 1; - desc.entry_number = emu->runptr.sel / 8; + desc.entry_number = FLATCODE / 8; desc.base_addr = 0; desc.limit = 0xfffff; desc.contents = MODIFY_LDT_CONTENTS_CODE; if (modify_ldt(1, &desc, sizeof(desc)) < 0) return -1; - + + /* + * Linux 2.6.27 has a bug: it does not load the L (long mode) + * bit from desc.lm when copying desc into its own + * copy of the LDT entry on the kernel stack. + * Instead, it leaves L uninitialized, picking up whatever + * random bit was left on the kernel stack by the + * previous call sequence. We need L to be 0. + * If it ends up 1, the *ljmpq in run64.S will GP fault. + * Luckily, we can look for this by asking to read + * back the raw LDT bytes. If we observe this problem, + * try to fix it by doing a modify_ldt with base = limit = 0, + * which clears the entire stack ldt structure, and then + * quickly do another modify_ldt with desc, hoping that + * the bit will still be zero when we get there for the + * second modify_ldt. I wish I were making this up. + * This is fixed in Linus's git repository, but the Ubuntu + * git repositories are still out of date. See for example + * http://swtch.com/go/ubuntu-ldt + * http://swtch.com/go/linus-ldt + * + * Remember, folks, Free Software is only free if your + * time has no value. + */ + if(modify_ldt(0, ldt, sizeof ldt) < 0) + return -1; + if(ldt[1] & 0x00200000) { + if (vx32_debugxlate) + vxprint("FLATCODE LDT=%08x %08x; working around\n", ldt[0], ldt[1]); + desc.limit = 0; + modify_ldt(1, &desc, sizeof desc); + desc.limit = 0xfffff; + modify_ldt(1, &desc, sizeof desc); + modify_ldt(0, ldt, sizeof ldt); + if(ldt[1] & 0x00200000) { + vxprint("cannot work around Linux FLATCODE bug\n"); + errno = EBADE; + return -1; + } + if (vx32_debugxlate) + vxprint("FLATCODE LDT=%08x %08x\n", ldt[0], ldt[1]); + } + desc.entry_number = FLATDATA / 8; desc.base_addr = 0; desc.limit = 0xfffff; @@ -179,6 +223,7 @@ int vx32_sighandler(int signo, siginfo_t *si, void *v) if(0) vxprint("vx32_sighandler signo=%d eip=%#x esp=%#x vs=%#x\n", signo, ctx->ctxeip, ctx->esp, vs); + if(0) dumpsigcontext(ctx); if ((vs & 15) != 15) // 8 (emu), LDT, RPL=3 return 0; @@ -325,8 +370,9 @@ int vx32_sighandler(int signo, siginfo_t *si, void *v) // But on a segmentation fault (as opposed to a paging fault), // cr2 is not updated and the kernel sends an si_addr == 0. // Be sure to use si_addr, not cr2. - emu->cpu.trapva = (uint32_t)si->si_addr; - memmove(mc->gregs, emu->trapenv->gregs, 19*4); + emu->cpu.trapva = (uint32_t)(uintptr_t)si->si_addr; + memmove(mc->gregs, emu->trapenv->gregs, sizeof emu->trapenv->gregs); + return 1; } diff --git a/src/libvx32/rts.S b/src/libvx32/rts.S @@ -2,8 +2,8 @@ // Assembly-language runtime support for translated vx32 code. // -#include "asm.h" -#include "os.h" +#include "libvx32/asm.h" +#include "libvx32/os.h" // The method we use to get back out to host code differs for 32/64-bit hosts. diff --git a/src/libvx32/run32.S b/src/libvx32/run32.S @@ -2,8 +2,8 @@ // Assembly-language support code for vx32-to-x86-32 translation // -#include "asm.h" -#include "os.h" +#include "libvx32/asm.h" +#include "libvx32/os.h" .text diff --git a/src/libvx32/run64.S b/src/libvx32/run64.S @@ -2,8 +2,8 @@ // Assembly-language support code for vx32-to-x86-64 translation // -#include "asm.h" -#include "os.h" +#include "libvx32/asm.h" +#include "libvx32/os.h" .text diff --git a/src/libvx32/sig.c b/src/libvx32/sig.c @@ -69,7 +69,7 @@ int vxemu_sighandler(vxemu *emu, uint32_t trapeip) // In vx32 runtime code (rts.S, run32/64.S), the registers are in flux. // Single-step until we can get out; then they'll be safe to look at. // This only makes sense if the trap is an external trap like a timer. - char *eip = (char*)trapeip; + char *eip = (char*)(uintptr_t)trapeip; if ((emu->cpu_trap&VXTRAP_CATEGORY) != VXTRAP_CPU){ // The check for run32/64.S doesn't look for the entire file. // Instead it looks for anywhere in the file except diff --git a/src/libvx32/vx32impl.h b/src/libvx32/vx32impl.h @@ -251,5 +251,7 @@ void vxprint(char*, ...); int vx32_sighandler(int, siginfo_t*, void*); int vxemu_sighandler(vxemu*, uint32_t); +#define USED(x) if(x){} /* shut up gcc not-used warning */ + #endif // VX32_IMPL_H diff --git a/src/libvx32/x86dis.c b/src/libvx32/x86dis.c @@ -1700,11 +1700,11 @@ fmtarg(char *p, char *ep, xdarg *da, uint32_t npc) break; case DA_REL: addr = da->disp + npc; - if (addr == (uint32_t)vxrun_gentrap) + if (addr == (uint32_t)(uintptr_t)vxrun_gentrap) p += snprintf(p, ep-p, "vxrun_gentrap"); - else if (addr == (uint32_t)vxrun_lookup_backpatch) + else if (addr == (uint32_t)(uintptr_t)vxrun_lookup_backpatch) p += snprintf(p, ep-p, "vxrun_lookup_backpatch"); - else if (addr == (uint32_t)vxrun_lookup_indirect) + else if (addr == (uint32_t)(uintptr_t)vxrun_lookup_indirect) p += snprintf(p, ep-p, "vxrun_lookup_indirect"); else p += snprintf(p, ep-p, "%#x", da->disp + npc);