tcg: Allocate a guard page after code_gen_buffer
This will catch any overflow of the buffer. Add a native win32 alternative for alloc_code_gen_buffer; remove the malloc alternative. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
		
							parent
							
								
									8163b74938
								
							
						
					
					
						commit
						f293709c6a
					
				
							
								
								
									
										214
									
								
								translate-all.c
								
								
								
								
							
							
						
						
									
										214
									
								
								translate-all.c
								
								
								
								
							| 
						 | 
					@ -312,31 +312,6 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
static __attribute__((unused)) void map_exec(void *addr, long size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    DWORD old_protect;
 | 
					 | 
				
			||||||
    VirtualProtect(addr, size,
 | 
					 | 
				
			||||||
                   PAGE_EXECUTE_READWRITE, &old_protect);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static __attribute__((unused)) void map_exec(void *addr, long size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    unsigned long start, end, page_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    page_size = getpagesize();
 | 
					 | 
				
			||||||
    start = (unsigned long)addr;
 | 
					 | 
				
			||||||
    start &= ~(page_size - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    end = (unsigned long)addr + size;
 | 
					 | 
				
			||||||
    end += page_size - 1;
 | 
					 | 
				
			||||||
    end &= ~(page_size - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mprotect((void *)start, end - start,
 | 
					 | 
				
			||||||
             PROT_READ | PROT_WRITE | PROT_EXEC);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void page_size_init(void)
 | 
					void page_size_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* NOTE: we can always suppose that qemu_host_page_size >=
 | 
					    /* NOTE: we can always suppose that qemu_host_page_size >=
 | 
				
			||||||
| 
						 | 
					@ -473,14 +448,6 @@ static inline PageDesc *page_find(tb_page_addr_t index)
 | 
				
			||||||
#define USE_STATIC_CODE_GEN_BUFFER
 | 
					#define USE_STATIC_CODE_GEN_BUFFER
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ??? Should configure for this, not list operating systems here.  */
 | 
					 | 
				
			||||||
#if (defined(__linux__) \
 | 
					 | 
				
			||||||
    || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
 | 
					 | 
				
			||||||
    || defined(__DragonFly__) || defined(__OpenBSD__) \
 | 
					 | 
				
			||||||
    || defined(__NetBSD__))
 | 
					 | 
				
			||||||
# define USE_MMAP
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Minimum size of the code gen buffer.  This number is randomly chosen,
 | 
					/* Minimum size of the code gen buffer.  This number is randomly chosen,
 | 
				
			||||||
   but not so small that we can't have a fair number of TB's live.  */
 | 
					   but not so small that we can't have a fair number of TB's live.  */
 | 
				
			||||||
#define MIN_CODE_GEN_BUFFER_SIZE     (1024u * 1024)
 | 
					#define MIN_CODE_GEN_BUFFER_SIZE     (1024u * 1024)
 | 
				
			||||||
| 
						 | 
					@ -568,22 +535,102 @@ static inline void *split_cross_256mb(void *buf1, size_t size1)
 | 
				
			||||||
static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
 | 
					static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
 | 
				
			||||||
    __attribute__((aligned(CODE_GEN_ALIGN)));
 | 
					    __attribute__((aligned(CODE_GEN_ALIGN)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ifdef _WIN32
 | 
				
			||||||
 | 
					static inline void do_protect(void *addr, long size, int prot)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    DWORD old_protect;
 | 
				
			||||||
 | 
					    VirtualProtect(addr, size, prot, &old_protect);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void map_exec(void *addr, long size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    do_protect(addr, size, PAGE_EXECUTE_READWRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void map_none(void *addr, long size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    do_protect(addr, size, PAGE_NOACCESS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					# else
 | 
				
			||||||
 | 
					static inline void do_protect(void *addr, long size, int prot)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uintptr_t start, end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    start = (uintptr_t)addr;
 | 
				
			||||||
 | 
					    start &= qemu_real_host_page_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end = (uintptr_t)addr + size;
 | 
				
			||||||
 | 
					    end = ROUND_UP(end, qemu_real_host_page_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mprotect((void *)start, end - start, prot);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void map_exec(void *addr, long size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    do_protect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void map_none(void *addr, long size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    do_protect(addr, size, PROT_NONE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					# endif /* WIN32 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void *alloc_code_gen_buffer(void)
 | 
					static inline void *alloc_code_gen_buffer(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void *buf = static_code_gen_buffer;
 | 
					    void *buf = static_code_gen_buffer;
 | 
				
			||||||
 | 
					    size_t full_size, size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* The size of the buffer, rounded down to end on a page boundary.  */
 | 
				
			||||||
 | 
					    full_size = (((uintptr_t)buf + sizeof(static_code_gen_buffer))
 | 
				
			||||||
 | 
					                 & qemu_real_host_page_mask) - (uintptr_t)buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Reserve a guard page.  */
 | 
				
			||||||
 | 
					    size = full_size - qemu_real_host_page_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Honor a command-line option limiting the size of the buffer.  */
 | 
				
			||||||
 | 
					    if (size > tcg_ctx.code_gen_buffer_size) {
 | 
				
			||||||
 | 
					        size = (((uintptr_t)buf + tcg_ctx.code_gen_buffer_size)
 | 
				
			||||||
 | 
					                & qemu_real_host_page_mask) - (uintptr_t)buf;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    tcg_ctx.code_gen_buffer_size = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __mips__
 | 
					#ifdef __mips__
 | 
				
			||||||
    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
 | 
					    if (cross_256mb(buf, size)) {
 | 
				
			||||||
        buf = split_cross_256mb(buf, tcg_ctx.code_gen_buffer_size);
 | 
					        buf = split_cross_256mb(buf, size);
 | 
				
			||||||
 | 
					        size = tcg_ctx.code_gen_buffer_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    map_exec(buf, tcg_ctx.code_gen_buffer_size);
 | 
					
 | 
				
			||||||
 | 
					    map_exec(buf, size);
 | 
				
			||||||
 | 
					    map_none(buf + size, qemu_real_host_page_size);
 | 
				
			||||||
 | 
					    qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return buf;
 | 
					    return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#elif defined(USE_MMAP)
 | 
					#elif defined(_WIN32)
 | 
				
			||||||
 | 
					static inline void *alloc_code_gen_buffer(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t size = tcg_ctx.code_gen_buffer_size;
 | 
				
			||||||
 | 
					    void *buf1, *buf2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Perform the allocation in two steps, so that the guard page
 | 
				
			||||||
 | 
					       is reserved but uncommitted.  */
 | 
				
			||||||
 | 
					    buf1 = VirtualAlloc(NULL, size + qemu_real_host_page_size,
 | 
				
			||||||
 | 
					                        MEM_RESERVE, PAGE_NOACCESS);
 | 
				
			||||||
 | 
					    if (buf1 != NULL) {
 | 
				
			||||||
 | 
					        buf2 = VirtualAlloc(buf1, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 | 
				
			||||||
 | 
					        assert(buf1 == buf2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return buf1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
static inline void *alloc_code_gen_buffer(void)
 | 
					static inline void *alloc_code_gen_buffer(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
 | 
					    int flags = MAP_PRIVATE | MAP_ANONYMOUS;
 | 
				
			||||||
    uintptr_t start = 0;
 | 
					    uintptr_t start = 0;
 | 
				
			||||||
 | 
					    size_t size = tcg_ctx.code_gen_buffer_size;
 | 
				
			||||||
    void *buf;
 | 
					    void *buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Constrain the position of the buffer based on the host cpu.
 | 
					    /* Constrain the position of the buffer based on the host cpu.
 | 
				
			||||||
| 
						 | 
					@ -599,86 +646,70 @@ static inline void *alloc_code_gen_buffer(void)
 | 
				
			||||||
       Leave the choice of exact location with the kernel.  */
 | 
					       Leave the choice of exact location with the kernel.  */
 | 
				
			||||||
    flags |= MAP_32BIT;
 | 
					    flags |= MAP_32BIT;
 | 
				
			||||||
    /* Cannot expect to map more than 800MB in low memory.  */
 | 
					    /* Cannot expect to map more than 800MB in low memory.  */
 | 
				
			||||||
    if (tcg_ctx.code_gen_buffer_size > 800u * 1024 * 1024) {
 | 
					    if (size > 800u * 1024 * 1024) {
 | 
				
			||||||
        tcg_ctx.code_gen_buffer_size = 800u * 1024 * 1024;
 | 
					        tcg_ctx.code_gen_buffer_size = size = 800u * 1024 * 1024;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
# elif defined(__sparc__)
 | 
					# elif defined(__sparc__)
 | 
				
			||||||
    start = 0x40000000ul;
 | 
					    start = 0x40000000ul;
 | 
				
			||||||
# elif defined(__s390x__)
 | 
					# elif defined(__s390x__)
 | 
				
			||||||
    start = 0x90000000ul;
 | 
					    start = 0x90000000ul;
 | 
				
			||||||
# elif defined(__mips__)
 | 
					# elif defined(__mips__)
 | 
				
			||||||
    /* ??? We ought to more explicitly manage layout for softmmu too.  */
 | 
					#  if _MIPS_SIM == _ABI64
 | 
				
			||||||
#  ifdef CONFIG_USER_ONLY
 | 
					 | 
				
			||||||
    start = 0x68000000ul;
 | 
					 | 
				
			||||||
#  elif _MIPS_SIM == _ABI64
 | 
					 | 
				
			||||||
    start = 0x128000000ul;
 | 
					    start = 0x128000000ul;
 | 
				
			||||||
#  else
 | 
					#  else
 | 
				
			||||||
    start = 0x08000000ul;
 | 
					    start = 0x08000000ul;
 | 
				
			||||||
#  endif
 | 
					#  endif
 | 
				
			||||||
# endif
 | 
					# endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buf = mmap((void *)start, tcg_ctx.code_gen_buffer_size,
 | 
					    buf = mmap((void *)start, size + qemu_real_host_page_size,
 | 
				
			||||||
               PROT_WRITE | PROT_READ | PROT_EXEC, flags, -1, 0);
 | 
					               PROT_NONE, flags, -1, 0);
 | 
				
			||||||
    if (buf == MAP_FAILED) {
 | 
					    if (buf == MAP_FAILED) {
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __mips__
 | 
					#ifdef __mips__
 | 
				
			||||||
    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
 | 
					    if (cross_256mb(buf, size)) {
 | 
				
			||||||
        /* Try again, with the original still mapped, to avoid re-acquiring
 | 
					        /* Try again, with the original still mapped, to avoid re-acquiring
 | 
				
			||||||
           that 256mb crossing.  This time don't specify an address.  */
 | 
					           that 256mb crossing.  This time don't specify an address.  */
 | 
				
			||||||
        size_t size2, size1 = tcg_ctx.code_gen_buffer_size;
 | 
					        size_t size2;
 | 
				
			||||||
        void *buf2 = mmap(NULL, size1, PROT_WRITE | PROT_READ | PROT_EXEC,
 | 
					        void *buf2 = mmap(NULL, size + qemu_real_host_page_size,
 | 
				
			||||||
                          flags, -1, 0);
 | 
					                          PROT_NONE, flags, -1, 0);
 | 
				
			||||||
        if (buf2 != MAP_FAILED) {
 | 
					        switch (buf2 != MAP_FAILED) {
 | 
				
			||||||
            if (!cross_256mb(buf2, size1)) {
 | 
					        case 1:
 | 
				
			||||||
 | 
					            if (!cross_256mb(buf2, size)) {
 | 
				
			||||||
                /* Success!  Use the new buffer.  */
 | 
					                /* Success!  Use the new buffer.  */
 | 
				
			||||||
                munmap(buf, size1);
 | 
					                munmap(buf, size);
 | 
				
			||||||
                return buf2;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            /* Failure.  Work with what we had.  */
 | 
					            /* Failure.  Work with what we had.  */
 | 
				
			||||||
            munmap(buf2, size1);
 | 
					            munmap(buf2, size);
 | 
				
			||||||
 | 
					            /* fallthru */
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            /* Split the original buffer.  Free the smaller half.  */
 | 
				
			||||||
 | 
					            buf2 = split_cross_256mb(buf, size);
 | 
				
			||||||
 | 
					            size2 = tcg_ctx.code_gen_buffer_size;
 | 
				
			||||||
 | 
					            if (buf == buf2) {
 | 
				
			||||||
 | 
					                munmap(buf + size2 + qemu_real_host_page_size, size - size2);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                munmap(buf, size - size2);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            size = size2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        buf = buf2;
 | 
				
			||||||
        /* Split the original buffer.  Free the smaller half.  */
 | 
					 | 
				
			||||||
        buf2 = split_cross_256mb(buf, size1);
 | 
					 | 
				
			||||||
        size2 = tcg_ctx.code_gen_buffer_size;
 | 
					 | 
				
			||||||
        munmap(buf + (buf == buf2 ? size2 : 0), size1 - size2);
 | 
					 | 
				
			||||||
        return buf2;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Make the final buffer accessible.  The guard page at the end
 | 
				
			||||||
 | 
					       will remain inaccessible with PROT_NONE.  */
 | 
				
			||||||
 | 
					    mprotect(buf, size, PROT_WRITE | PROT_READ | PROT_EXEC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Request large pages for the buffer.  */
 | 
				
			||||||
 | 
					    qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return buf;
 | 
					    return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
 | 
				
			||||||
static inline void *alloc_code_gen_buffer(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    void *buf = g_try_malloc(tcg_ctx.code_gen_buffer_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (buf == NULL) {
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __mips__
 | 
					 | 
				
			||||||
    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
 | 
					 | 
				
			||||||
        void *buf2 = g_malloc(tcg_ctx.code_gen_buffer_size);
 | 
					 | 
				
			||||||
        if (buf2 != NULL && !cross_256mb(buf2, size1)) {
 | 
					 | 
				
			||||||
            /* Success!  Use the new buffer.  */
 | 
					 | 
				
			||||||
            free(buf);
 | 
					 | 
				
			||||||
            buf = buf2;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            /* Failure.  Work with what we had.  Since this is malloc
 | 
					 | 
				
			||||||
               and not mmap, we can't free the other half.  */
 | 
					 | 
				
			||||||
            free(buf2);
 | 
					 | 
				
			||||||
            buf = split_cross_256mb(buf, tcg_ctx.code_gen_buffer_size);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    map_exec(buf, tcg_ctx.code_gen_buffer_size);
 | 
					 | 
				
			||||||
    return buf;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* USE_STATIC_CODE_GEN_BUFFER, USE_MMAP */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void code_gen_alloc(size_t tb_size)
 | 
					static inline void code_gen_alloc(size_t tb_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -689,9 +720,6 @@ static inline void code_gen_alloc(size_t tb_size)
 | 
				
			||||||
        exit(1);
 | 
					        exit(1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_madvise(tcg_ctx.code_gen_buffer, tcg_ctx.code_gen_buffer_size,
 | 
					 | 
				
			||||||
                 QEMU_MADV_HUGEPAGE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Estimate a good size for the number of TBs we can support.  We
 | 
					    /* Estimate a good size for the number of TBs we can support.  We
 | 
				
			||||||
       still haven't deducted the prologue from the buffer size here,
 | 
					       still haven't deducted the prologue from the buffer size here,
 | 
				
			||||||
       but that's minimal and won't affect the estimate much.  */
 | 
					       but that's minimal and won't affect the estimate much.  */
 | 
				
			||||||
| 
						 | 
					@ -708,8 +736,8 @@ static inline void code_gen_alloc(size_t tb_size)
 | 
				
			||||||
void tcg_exec_init(unsigned long tb_size)
 | 
					void tcg_exec_init(unsigned long tb_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    cpu_gen_init();
 | 
					    cpu_gen_init();
 | 
				
			||||||
    code_gen_alloc(tb_size);
 | 
					 | 
				
			||||||
    page_init();
 | 
					    page_init();
 | 
				
			||||||
 | 
					    code_gen_alloc(tb_size);
 | 
				
			||||||
#if defined(CONFIG_SOFTMMU)
 | 
					#if defined(CONFIG_SOFTMMU)
 | 
				
			||||||
    /* There's no guest base to take into account, so go ahead and
 | 
					    /* There's no guest base to take into account, so go ahead and
 | 
				
			||||||
       initialize the prologue now.  */
 | 
					       initialize the prologue now.  */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue