diff options
106 files changed, 4910 insertions, 4293 deletions
diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index 4ef76d1f54..765408ae27 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -144,19 +144,12 @@ mipsel-debian-cross-container: variables: NAME: debian-mipsel-cross -powerpc-debian-cross-container: +powerpc-test-cross-container: extends: .container_job_template stage: containers-layer2 - needs: ['amd64-debian10-container'] - variables: - NAME: debian-powerpc-cross - -ppc64-debian-cross-container: - extends: .container_job_template - stage: containers-layer2 - needs: ['amd64-debian10-container'] + needs: ['amd64-debian11-container'] variables: - NAME: debian-ppc64-cross + NAME: debian-powerpc-test-cross ppc64el-debian-cross-container: extends: .container_job_template diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24f300aace..f718b61fa7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -416,6 +416,17 @@ build-user-static: CONFIGURE_ARGS: --disable-tools --disable-system --static MAKE_CHECK_ARGS: check-tcg +# Because the hexagon cross-compiler takes so long to build we don't rely +# on the CI system to build it and hence this job has no dependency +# declared. The image is manually uploaded. +build-user-hexagon: + extends: .native_build_job_template + variables: + IMAGE: debian-hexagon-cross + TARGETS: hexagon-linux-user + CONFIGURE_ARGS: --disable-tools --disable-docs --enable-debug-tcg + MAKE_CHECK_ARGS: check-tcg + # Only build the softmmu targets we have check-tcg tests for build-some-softmmu: extends: .native_build_job_template diff --git a/MAINTAINERS b/MAINTAINERS index 89741cfc19..75e0f2d750 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -197,6 +197,8 @@ F: linux-user/hexagon/ F: tests/tcg/hexagon/ F: disas/hexagon.c F: default-configs/targets/hexagon-linux-user.mak +F: docker/dockerfiles/debian-hexagon-cross.docker +F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh HPPA (PA-RISC) TCG CPUs M: Richard Henderson <richard.henderson@linaro.org> @@ -347,6 +349,7 @@ S: Maintained F: target/tricore/ F: hw/tricore/ F: include/hw/tricore/ +F: tests/tcg/tricore/ Multiarch Linux User Tests M: Alex Bennée <alex.bennee@linaro.org> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index fbf8fc630b..640ff6e3e7 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1912,6 +1912,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->cpu = env_cpu(env); gen_intermediate_code(cpu, tb, max_insns); + assert(tb->size != 0); tcg_ctx->cpu = NULL; max_insns = tb->icount; diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index e1ed3b7b60..8d83f21eda 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -32,7 +32,7 @@ static int count(char **vec) return i; } -static int prepare_binprm(struct linux_binprm *bprm) +static int prepare_binprm(struct bsd_binprm *bprm) { struct stat st; int mode; @@ -127,7 +127,7 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, int loader_exec(const char *filename, char **argv, char **envp, struct target_pt_regs *regs, struct image_info *infop) { - struct linux_binprm bprm; + struct bsd_binprm bprm; int retval; int i; diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 5f4d824d78..6edceb3ea6 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -111,7 +111,7 @@ static uint32_t get_elf_hwcap(void) #ifdef TARGET_X86_64 #define ELF_START_MMAP 0x2aaaaab000ULL -#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) +#define elf_check_arch(x) (((x) == ELF_ARCH)) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2LSB @@ -134,7 +134,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) +#define elf_check_arch(x) (((x) == EM_386) || ((x) == EM_486)) /* * These are used to set parameters in the core dumps. @@ -168,7 +168,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_ARM ) +#define elf_check_arch(x) ((x) == EM_ARM) #define ELF_CLASS ELFCLASS32 #ifdef TARGET_WORDS_BIGENDIAN @@ -184,7 +184,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) - regs->ARM_cpsr |= CPSR_T; + regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; /* FIXME - what to for failure of get_user()? */ @@ -224,9 +224,9 @@ enum #define ELF_START_MMAP 0x80000000 #ifndef TARGET_ABI32 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) +#define elf_check_arch(x) ((x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS) #else -#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC ) +#define elf_check_arch(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC) #endif #define ELF_CLASS ELFCLASS64 @@ -261,7 +261,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #else #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARC ) +#define elf_check_arch(x) ((x) == EM_SPARC) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -285,13 +285,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) -#define elf_check_arch(x) ( (x) == EM_PPC64 ) +#define elf_check_arch(x) ((x) == EM_PPC64) #define ELF_CLASS ELFCLASS64 #else -#define elf_check_arch(x) ( (x) == EM_PPC ) +#define elf_check_arch(x) ((x) == EM_PPC) #define ELF_CLASS ELFCLASS32 @@ -376,7 +376,7 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_MIPS ) +#define elf_check_arch(x) ((x) == EM_MIPS) #ifdef TARGET_MIPS64 #define ELF_CLASS ELFCLASS64 @@ -406,7 +406,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SH ) +#define elf_check_arch(x) ((x) == EM_SH) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB @@ -428,7 +428,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_CRIS ) +#define elf_check_arch(x) ((x) == EM_CRIS) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB @@ -448,7 +448,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_68K ) +#define elf_check_arch(x) ((x) == EM_68K) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -473,7 +473,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP (0x30000000000ULL) -#define elf_check_arch(x) ( (x) == ELF_ARCH ) +#define elf_check_arch(x) ((x) == ELF_ARCH) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -538,8 +538,8 @@ struct exec /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE -#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) -#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE - 1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE - 1)) #define INTERPRETER_NONE 0 #define INTERPRETER_AOUT 1 @@ -547,12 +547,12 @@ struct exec #define DLINFO_ITEMS 12 -static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +static inline void memcpy_fromfs(void *to, const void *from, unsigned long n) { memcpy(to, from, n); } -static int load_aout_interp(void * exptr, int interp_fd); +static int load_aout_interp(void *exptr, int interp_fd); #ifdef BSWAP_NEEDED static void bswap_ehdr(struct elfhdr *ehdr) @@ -613,7 +613,7 @@ static void bswap_sym(struct elf_sym *sym) * to be put directly into the top of new user memory. * */ -static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, +static abi_ulong copy_elf_strings(int argc, char **argv, void **page, abi_ulong p) { char *tmp, *tmp1, *pag = NULL; @@ -638,10 +638,10 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - pag = (char *)page[p/TARGET_PAGE_SIZE]; + pag = (char *)page[p / TARGET_PAGE_SIZE]; if (!pag) { pag = g_try_malloc0(TARGET_PAGE_SIZE); - page[p/TARGET_PAGE_SIZE] = pag; + page[p / TARGET_PAGE_SIZE] = pag; if (!pag) return 0; } @@ -662,7 +662,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, return p; } -static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, +static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, struct image_info *info) { abi_ulong stack_base, size, error; @@ -672,8 +672,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, * it for args, we'll use it for something else... */ size = x86_stack_size; - if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) - size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + if (size < MAX_ARG_PAGES * TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES * TARGET_PAGE_SIZE; error = target_mmap(0, size + qemu_host_page_size, PROT_READ | PROT_WRITE, @@ -686,7 +686,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, /* we reserve one extra page at the top of the stack as guard */ target_mprotect(error + size, qemu_host_page_size, PROT_NONE); - stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + stack_base = error + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE; p += stack_base; for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -708,7 +708,7 @@ static void set_brk(abi_ulong start, abi_ulong end) end = HOST_PAGE_ALIGN(end); if (end <= start) return; - if(target_mmap(start, end - start, + if (target_mmap(start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) { perror("cannot mmap brk"); @@ -738,12 +738,12 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss) end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); } } - nbyte = elf_bss & (qemu_host_page_size-1); + nbyte = elf_bss & (qemu_host_page_size - 1); if (nbyte) { nbyte = qemu_host_page_size - nbyte; do { @@ -781,10 +781,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* * Force 16 byte _final_ alignment here for generality. */ - sp = sp &~ (abi_ulong)15; + sp = sp & ~(abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) - size += 2; + size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; #endif @@ -792,7 +792,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size += (!ibcs ? 3 : 1); /* argc itself */ size *= n; if (size & 15) - sp -= 16 - (size & 15); + sp -= 16 - (size & 15); /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off @@ -800,13 +800,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, #define NEW_AUX_ENT(id, val) do { \ sp -= n; put_user_ual(val, sp); \ sp -= n; put_user_ual(id, sp); \ - } while(0) + } while (0) - NEW_AUX_ENT (AT_NULL, 0); + NEW_AUX_ENT(AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof(struct elf_phdr))); NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); @@ -834,90 +834,90 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, } -static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, +static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, int interpreter_fd, abi_ulong *interp_load_addr) { - struct elf_phdr *elf_phdata = NULL; - struct elf_phdr *eppnt; - abi_ulong load_addr = 0; - int load_addr_set = 0; - int retval; - abi_ulong last_bss, elf_bss; - abi_ulong error; - int i; + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + abi_ulong load_addr = 0; + int load_addr_set = 0; + int retval; + abi_ulong last_bss, elf_bss; + abi_ulong error; + int i; - elf_bss = 0; - last_bss = 0; - error = 0; + elf_bss = 0; + last_bss = 0; + error = 0; #ifdef BSWAP_NEEDED - bswap_ehdr(interp_elf_ex); + bswap_ehdr(interp_elf_ex); #endif - /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - !elf_check_arch(interp_elf_ex->e_machine)) { - return ~((abi_ulong)0UL); - } + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine)) { + return ~((abi_ulong)0UL); + } - /* Now read in all of the header information */ + /* Now read in all of the header information */ - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~(abi_ulong)0UL; + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) + return ~(abi_ulong)0UL; - elf_phdata = (struct elf_phdr *) - malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - if (!elf_phdata) - return ~((abi_ulong)0UL); + if (!elf_phdata) + return ~((abi_ulong)0UL); - /* - * If the size of this structure has changed, then punt, since - * we will be doing the wrong thing. - */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { - free(elf_phdata); - return ~((abi_ulong)0UL); - } + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { + free(elf_phdata); + return ~((abi_ulong)0UL); + } - retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd, - (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - } - if (retval < 0) { - perror("load_elf_interp"); - exit(-1); - free (elf_phdata); - return retval; - } + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if (retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } #ifdef BSWAP_NEEDED - eppnt = elf_phdata; - for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { - bswap_phdr(eppnt); - } + eppnt = elf_phdata; + for (i = 0; i<interp_elf_ex->e_phnum; i++, eppnt++) { + bswap_phdr(eppnt); + } #endif - if (interp_elf_ex->e_type == ET_DYN) { - /* in order to avoid hardcoding the interpreter load - address in qemu, we allocate a big enough memory zone */ - error = target_mmap(0, INTERP_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { - perror("mmap"); - exit(-1); - } - load_addr = error; - load_addr_set = 1; + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid hardcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); } + load_addr = error; + load_addr_set = 1; + } - eppnt = elf_phdata; - for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { + eppnt = elf_phdata; + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; abi_ulong vaddr = 0; @@ -930,23 +930,23 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; } - error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), - eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - interpreter_fd, - eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); + error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + interpreter_fd, + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); if (error == -1) { - /* Real error */ - close(interpreter_fd); - free(elf_phdata); - return ~((abi_ulong)0UL); + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~((abi_ulong)0UL); } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; + load_addr = error; + load_addr_set = 1; } /* @@ -962,31 +962,31 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, */ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; if (k > last_bss) last_bss = k; - } + } - /* Now use mmap to map the library into memory. */ + /* Now use mmap to map the library into memory. */ - close(interpreter_fd); + close(interpreter_fd); - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - padzero(elf_bss, last_bss); - elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ - - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { - target_mmap(elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); - } - free(elf_phdata); + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss, last_bss); + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + target_mmap(elf_bss, last_bss - elf_bss, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); + } + free(elf_phdata); - *interp_load_addr = load_addr; - return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; + *interp_load_addr = load_addr; + return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; } static int symfind(const void *s0, const void *s1) @@ -1102,7 +1102,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) } continue; } -#if defined(TARGET_ARM) || defined (TARGET_MIPS) +#if defined(TARGET_ARM) || defined(TARGET_MIPS) /* The bottom address bit marks a Thumb or MIPS16 symbol. */ syms[i].st_value &= ~(target_ulong)1; #endif @@ -1143,8 +1143,8 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } -int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; @@ -1178,13 +1178,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || - (! elf_check_arch(elf_ex.e_machine))) { + (!elf_check_arch(elf_ex.e_machine))) { return -ENOEXEC; } bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); - bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); - bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page,bprm->p); if (!bprm->p) { retval = -E2BIG; } @@ -1196,21 +1196,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); - if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, + if (retval > 0) { + retval = read(bprm->fd, (char *)elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum); } if (retval < 0) { perror("load_elf_binary"); exit(-1); - free (elf_phdata); + free(elf_phdata); return -errno; } #ifdef BSWAP_NEEDED elf_ppnt = elf_phdata; - for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { + for (i = 0; i < elf_ex.e_phnum; i++, elf_ppnt++) { bswap_phdr(elf_ppnt); } #endif @@ -1227,11 +1227,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, end_data = 0; interp_ex.a_info = 0; - for(i=0;i < elf_ex.e_phnum; i++) { + for (i = 0;i < elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { - if ( elf_interpreter != NULL ) + if (elf_interpreter != NULL) { - free (elf_phdata); + free(elf_phdata); free(elf_interpreter); close(bprm->fd); return -EINVAL; @@ -1245,16 +1245,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (elf_interpreter == NULL) { - free (elf_phdata); + free(elf_phdata); close(bprm->fd); return -ENOMEM; } retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); - if(retval >= 0) { + if (retval >= 0) { retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); } - if(retval < 0) { + if (retval < 0) { perror("load_elf_binary2"); exit(-1); } @@ -1265,8 +1265,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* JRP - Need to add X86 lib dir stuff here... */ - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) { ibcs2_interpreter = 1; } @@ -1275,7 +1275,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, #endif if (retval >= 0) { retval = open(path(elf_interpreter), O_RDONLY); - if(retval >= 0) { + if (retval >= 0) { interpreter_fd = retval; } else { @@ -1287,8 +1287,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (retval >= 0) { retval = lseek(interpreter_fd, 0, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd,bprm->buf,128); + if (retval >= 0) { + retval = read(interpreter_fd, bprm->buf, 128); } } if (retval >= 0) { @@ -1298,7 +1298,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (retval < 0) { perror("load_elf_binary3"); exit(-1); - free (elf_phdata); + free(elf_phdata); free(elf_interpreter); close(bprm->fd); return retval; @@ -1308,17 +1308,17 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ + if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) { - interpreter_type = INTERPRETER_ELF; + interpreter_type = INTERPRETER_ELF; } if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) { interpreter_type &= ~INTERPRETER_ELF; } @@ -1334,20 +1334,20 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, and then start this sucker up */ { - char * passed_p; + char *passed_p; if (interpreter_type == INTERPRETER_AOUT) { snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); passed_p = passed_fileno; if (elf_interpreter) { - bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); + bprm->p = copy_elf_strings(1, &passed_p, bprm->page, bprm->p); bprm->argc++; } } if (!bprm->p) { free(elf_interpreter); - free (elf_phdata); + free(elf_phdata); close(bprm->fd); return -E2BIG; } @@ -1393,7 +1393,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, * address. */ - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; abi_ulong error; @@ -1538,7 +1538,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, printf("(brk) %x\n" , info->brk); #endif - if ( info->personality == PER_SVR4 ) + if (info->personality == PER_SVR4) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. @@ -1553,7 +1553,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, return 0; } -static int load_aout_interp(void * exptr, int interp_fd) +static int load_aout_interp(void *exptr, int interp_fd) { printf("a.out interpreter not yet supported\n"); return(0); diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h deleted file mode 100644 index 2ef36d1f98..0000000000 --- a/bsd-user/i386/target_signal.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/main.c b/bsd-user/main.c index 715129e624..9d370bc8f6 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -36,6 +36,7 @@ #include "tcg/tcg.h" #include "qemu/timer.h" #include "qemu/envlist.h" +#include "qemu/cutils.h" #include "exec/log.h" #include "trace/control.h" @@ -47,12 +48,13 @@ unsigned long reserved_va; static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; -extern char **environ; enum BSDType bsd_type; -/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - we allocate a bigger stack. Need a better solution, for example - by remapping the process stack directly at the right place */ +/* + * XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + * we allocate a bigger stack. Need a better solution, for example + * by remapping the process stack directly at the right place + */ unsigned long x86_stack_size = 512 * 1024; void gemu_log(const char *fmt, ...) @@ -147,15 +149,15 @@ void cpu_loop(CPUX86State *env) CPUState *cs = env_cpu(env); int trapnr; abi_ulong pc; - //target_siginfo_t info; + /* target_siginfo_t info; */ - for(;;) { + for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); process_queued_cpu_work(cs); - switch(trapnr) { + switch (trapnr) { case 0x80: /* syscall from int $0x80 */ if (bsd_type == target_freebsd) { @@ -196,7 +198,7 @@ void cpu_loop(CPUX86State *env) arg6, arg7, arg8); - } else { //if (bsd_type == target_openbsd) + } else { /* if (bsd_type == target_openbsd) */ env->regs[R_EAX] = do_openbsd_syscall(env, env->regs[R_EAX], env->regs[R_EBX], @@ -216,7 +218,7 @@ void cpu_loop(CPUX86State *env) #ifndef TARGET_ABI32 case EXCP_SYSCALL: /* syscall from syscall instruction */ - if (bsd_type == target_freebsd) + if (bsd_type == target_freebsd) { env->regs[R_EAX] = do_freebsd_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -225,7 +227,7 @@ void cpu_loop(CPUX86State *env) env->regs[R_ECX], env->regs[8], env->regs[9], 0, 0); - else { //if (bsd_type == target_openbsd) + } else { /* if (bsd_type == target_openbsd) */ env->regs[R_EAX] = do_openbsd_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -244,120 +246,13 @@ void cpu_loop(CPUX86State *env) } break; #endif -#if 0 - case EXCP0B_NOSEG: - case EXCP0C_STACK: - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - break; - case EXCP0D_GPF: - /* XXX: potential problem if ABI32 */ -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_fault(env); - } else -#endif - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP0E_PAGE: - info.si_signo = SIGSEGV; - info.si_errno = 0; - if (!(env->error_code & 1)) - info.si_code = TARGET_SEGV_MAPERR; - else - info.si_code = TARGET_SEGV_ACCERR; - info._sifields._sigfault._addr = env->cr[2]; - queue_signal(env, info.si_signo, &info); - break; - case EXCP00_DIVZ: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - /* division by zero */ - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_code = TARGET_FPE_INTDIV; - info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP01_DB: - case EXCP03_INT3: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - info.si_signo = SIGTRAP; - info.si_errno = 0; - if (trapnr == EXCP01_DB) { - info.si_code = TARGET_TRAP_BRKPT; - info._sifields._sigfault._addr = env->eip; - } else { - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - } - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP04_INTO: - case EXCP05_BOUND: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP06_ILLOP: - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); - break; -#endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -#if 0 - case EXCP_DEBUG: - { - int sig; - - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } - } - break; -#endif default: pc = env->segs[R_CS].base + env->eip; - fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, + "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } @@ -369,16 +264,21 @@ void cpu_loop(CPUX86State *env) #ifdef TARGET_SPARC #define SPARC64_STACK_BIAS 2047 -//#define DEBUG_WIN -/* WARNING: dealing with register windows _is_ complicated. More info - can be found at http://www.sics.se/~psm/sparcstack.html */ +/* #define DEBUG_WIN */ +/* + * WARNING: dealing with register windows _is_ complicated. More info + * can be found at http://www.sics.se/~psm/sparcstack.html + */ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) { index = (index + cwp * 16) % (16 * env->nwindows); - /* wrap handling : if cwp is on the last window, then we use the - registers 'after' the end */ - if (index < 8 && env->cwp == env->nwindows - 1) + /* + * wrap handling : if cwp is on the last window, then we use the + * registers 'after' the end + */ + if (index < 8 && env->cwp == env->nwindows - 1) { index += 16 * env->nwindows; + } return index; } @@ -390,14 +290,15 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #ifdef TARGET_SPARC64 - if (sp_ptr & 3) + if (sp_ptr & 3) { sp_ptr += SPARC64_STACK_BIAS; + } #endif #if defined(DEBUG_WIN) printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { /* FIXME - what to do if put_user() fails? */ put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); @@ -440,22 +341,24 @@ static void restore_window(CPUSPARCState *env) cwp1 = cpu_cwp_inc(env, env->cwp + 1); sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #ifdef TARGET_SPARC64 - if (sp_ptr & 3) + if (sp_ptr & 3) { sp_ptr += SPARC64_STACK_BIAS; + } #endif #if defined(DEBUG_WIN) printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { /* FIXME - what to do if get_user() fails? */ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); } #ifdef TARGET_SPARC64 env->canrestore++; - if (env->cleanwin < env->nwindows - 1) + if (env->cleanwin < env->nwindows - 1) { env->cleanwin++; + } env->cansave--; #else env->wim = new_wim; @@ -467,15 +370,17 @@ static void flush_windows(CPUSPARCState *env) int offset, cwp1; offset = 1; - for(;;) { + for (;;) { /* if restore would invoke restore_window(), then we can stop */ cwp1 = cpu_cwp_inc(env, env->cwp + offset); #ifndef TARGET_SPARC64 - if (env->wim & (1 << cwp1)) + if (env->wim & (1 << cwp1)) { break; + } #else - if (env->canrestore == 0) + if (env->canrestore == 0) { break; + } env->cansave++; env->canrestore--; #endif @@ -496,7 +401,7 @@ void cpu_loop(CPUSPARCState *env) { CPUState *cs = env_cpu(env); int trapnr, ret, syscall_nr; - //target_siginfo_t info; + /* target_siginfo_t info; */ while (1) { cpu_exec_start(cs); @@ -510,8 +415,9 @@ void cpu_loop(CPUSPARCState *env) #else /* FreeBSD uses 0x141 for syscalls too */ case 0x141: - if (bsd_type != target_freebsd) + if (bsd_type != target_freebsd) { goto badtrap; + } /* fallthrough */ case 0x100: #endif @@ -520,13 +426,14 @@ void cpu_loop(CPUSPARCState *env) ret = do_freebsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5], 0, 0); + env->regwptr[4], env->regwptr[5], + 0, 0); else if (bsd_type == target_netbsd) ret = do_netbsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5]); - else { //if (bsd_type == target_openbsd) + else { /* if (bsd_type == target_openbsd) */ #if defined(TARGET_SPARC64) syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG | TARGET_OPENBSD_SYSCALL_G2RFLAG); @@ -588,16 +495,6 @@ void cpu_loop(CPUSPARCState *env) break; case TT_TFAULT: case TT_DFAULT: -#if 0 - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->mmuregs[4]; - queue_signal(env, info.si_signo, &info); - } -#endif break; #else case TT_SPILL: /* window overflow */ @@ -608,19 +505,6 @@ void cpu_loop(CPUSPARCState *env) break; case TT_TFAULT: case TT_DFAULT: -#if 0 - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - if (trapnr == TT_DFAULT) - info._sifields._sigfault._addr = env->dmmuregs[4]; - else - info._sifields._sigfault._addr = env->tsptr->tpc; - //queue_signal(env, info.si_signo, &info); - } -#endif break; #endif case EXCP_INTERRUPT: @@ -628,30 +512,18 @@ void cpu_loop(CPUSPARCState *env) break; case EXCP_DEBUG: { -#if 0 - int sig = -#endif gdb_handlesig(cs, TARGET_SIGTRAP); -#if 0 - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - //queue_signal(env, info.si_signo, &info); - } -#endif } break; default: #ifdef TARGET_SPARC64 badtrap: #endif - printf ("Unhandled trap: 0x%x\n", trapnr); + printf("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); - exit (1); + exit(1); } - process_pending_signals (env); + process_pending_signals(env); } } @@ -741,15 +613,16 @@ int main(int argc, char **argv) TaskState ts1, *ts = &ts1; CPUArchState *env; CPUState *cpu; - int optind; + int optind, rv; const char *r; const char *gdbstub = NULL; char **target_environ, **wrk; envlist_t *envlist = NULL; bsd_type = target_openbsd; - if (argc <= 1) + if (argc <= 1) { usage(); + } error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); @@ -769,11 +642,13 @@ int main(int argc, char **argv) optind = 1; for (;;) { - if (optind >= argc) + if (optind >= argc) { break; + } r = argv[optind]; - if (r[0] != '-') + if (r[0] != '-') { break; + } optind++; r++; if (!strcmp(r, "-")) { @@ -790,24 +665,28 @@ int main(int argc, char **argv) log_file = argv[optind++]; } else if (!strcmp(r, "E")) { r = argv[optind++]; - if (envlist_setenv(envlist, r) != 0) + if (envlist_setenv(envlist, r) != 0) { usage(); + } } else if (!strcmp(r, "ignore-environment")) { envlist_free(envlist); envlist = envlist_create(); } else if (!strcmp(r, "U")) { r = argv[optind++]; - if (envlist_unsetenv(envlist, r) != 0) + if (envlist_unsetenv(envlist, r) != 0) { usage(); + } } else if (!strcmp(r, "s")) { r = argv[optind++]; - x86_stack_size = strtol(r, (char **)&r, 0); - if (x86_stack_size <= 0) + rv = qemu_strtoul(r, &r, 0, &x86_stack_size); + if (rv < 0 || x86_stack_size <= 0) { usage(); - if (*r == 'M') + } + if (*r == 'M') { x86_stack_size *= MiB; - else if (*r == 'k' || *r == 'K') + } else if (*r == 'k' || *r == 'K') { x86_stack_size *= KiB; + } } else if (!strcmp(r, "L")) { interp_prefix = argv[optind++]; } else if (!strcmp(r, "p")) { @@ -824,15 +703,18 @@ int main(int argc, char **argv) } else if (!strcmp(r, "cpu")) { cpu_model = argv[optind++]; if (is_help_option(cpu_model)) { -/* XXX: implement xxx_cpu_list for targets that still miss it */ + /* XXX: implement xxx_cpu_list for targets that still miss it */ #if defined(cpu_list) - cpu_list(); + cpu_list(); #endif exit(1); } } else if (!strcmp(r, "B")) { - guest_base = strtol(argv[optind++], NULL, 0); - have_guest_base = true; + rv = qemu_strtoul(argv[optind++], NULL, 0, &guest_base); + if (rv < 0) { + usage(); + } + have_guest_base = true; } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "bsd")) { @@ -947,17 +829,19 @@ int main(int argc, char **argv) if (!have_guest_base) { FILE *fp; - if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { + fp = fopen("/proc/sys/vm/mmap_min_addr", "r"); + if (fp != NULL) { unsigned long tmp; if (fscanf(fp, "%lu", &tmp) == 1) { mmap_min_addr = tmp; - qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", mmap_min_addr); + qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", + mmap_min_addr); } fclose(fp); } } - if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { + if (loader_exec(filename, argv + optind, target_environ, regs, info) != 0) { printf("Error loading %s\n", filename); _exit(1); } @@ -989,9 +873,11 @@ int main(int argc, char **argv) syscall_init(); signal_init(); - /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay - generating the prologue until now so that the prologue can take - the real value of GUEST_BASE into account. */ + /* + * Now that we've loaded the binary, GUEST_BASE is fixed. Delay + * generating the prologue until now so that the prologue can take + * the real value of GUEST_BASE into account. + */ tcg_prologue_init(tcg_ctx); tcg_region_init(); @@ -1052,8 +938,8 @@ int main(int argc, char **argv) env->idt.limit = 255; #endif env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); idt_table = g2h_untagged(env->idt.base); set_idt(0, 0); set_idt(1, 0); @@ -1081,8 +967,8 @@ int main(int argc, char **argv) { uint64_t *gdt_table; env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; gdt_table = g2h_untagged(env->gdt.base); #ifdef TARGET_ABI32 @@ -1122,10 +1008,12 @@ int main(int argc, char **argv) env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; - for(i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { env->gregs[i] = regs->u_regs[i]; - for(i = 0; i < 8; i++) + } + for (i = 0; i < 8; i++) { env->regwptr[i] = regs->u_regs[i + 8]; + } } #else #error unsupported target CPU diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 01ec808003..0ac1b92706 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -93,11 +93,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) if (start > host_start) { /* handle host page containing start */ prot1 = prot; - for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } if (host_end == host_start + qemu_host_page_size) { - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } end = host_end; @@ -110,7 +110,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) } if (end < host_end) { prot1 = prot; - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } ret = mprotect(g2h_untagged(host_end - qemu_host_page_size), @@ -148,7 +148,7 @@ static int mmap_frag(abi_ulong real_start, /* get the protection of the target pages outside the mapping */ prot1 = 0; - for(addr = real_start; addr < real_end; addr++) { + for (addr = real_start; addr < real_end; addr++) { if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } @@ -225,9 +225,9 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) if (addr == 0) addr = mmap_next_start; addr_start = addr; - for(;;) { + for (;;) { prot = 0; - for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { + for (addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr1); } if (prot == 0) @@ -262,7 +262,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, printf("MAP_FIXED "); if (flags & MAP_ANON) printf("MAP_ANON "); - switch(flags & TARGET_BSD_MAP_FLAGMASK) { + switch (flags & TARGET_BSD_MAP_FLAGMASK) { case MAP_PRIVATE: printf("MAP_PRIVATE "); break; @@ -321,7 +321,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, end = start + len; real_end = HOST_PAGE_ALIGN(end); - for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { flg = page_get_flags(addr); if (flg & PAGE_RESERVED) { errno = ENXIO; @@ -433,11 +433,11 @@ int target_munmap(abi_ulong start, abi_ulong len) if (start > real_start) { /* handle host page containing start */ prot = 0; - for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (real_end == real_start + qemu_host_page_size) { - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } end = real_end; @@ -447,7 +447,7 @@ int target_munmap(abi_ulong start, abi_ulong len) } if (end < real_end) { prot = 0; - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (prot != 0) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index b836b603af..c02e8a5ca1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -27,6 +27,8 @@ #include "exec/user/abitypes.h" +extern char **environ; + enum BSDType { target_freebsd, target_netbsd, @@ -36,7 +38,6 @@ extern enum BSDType bsd_type; #include "syscall_defs.h" #include "target_syscall.h" -#include "target_signal.h" #include "exec/gdbstub.h" #if defined(CONFIG_USE_NPTL) @@ -45,9 +46,10 @@ extern enum BSDType bsd_type; #define THREAD #endif -/* This struct is used to hold certain information about the image. - * Basically, it replicates in user space what would be certain - * task_struct fields in the kernel +/* + * This struct is used to hold certain information about the image. Basically, + * it replicates in user space what would be certain task_struct fields in the + * kernel */ struct image_info { abi_ulong load_addr; @@ -71,18 +73,18 @@ struct image_info { struct sigqueue { struct sigqueue *next; - //target_siginfo_t info; }; struct emulated_sigtable { int pending; /* true if signal is pending */ struct sigqueue *first; - struct sigqueue info; /* in order to always have memory for the - first signal, we put it here */ + /* in order to always have memory for the first signal, we put it here */ + struct sigqueue info; }; -/* NOTE: we force a big alignment so that the stack stored after is - aligned too */ +/* + * NOTE: we force a big alignment so that the stack stored after is aligned too + */ typedef struct TaskState { pid_t ts_tid; /* tid (or pid) of this task */ @@ -102,7 +104,6 @@ void init_task_state(TaskState *ts); extern const char *qemu_uname_release; extern unsigned long mmap_min_addr; -/* ??? See if we can avoid exposing so much of the loader internals. */ /* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives @@ -114,7 +115,7 @@ extern unsigned long mmap_min_addr; * This structure is used to hold the arguments that are * used when loading binaries. */ -struct linux_binprm { +struct bsd_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; abi_ulong p; @@ -123,19 +124,19 @@ struct linux_binprm { int argc, envc; char **argv; char **envp; - char * filename; /* Name of binary */ + char *filename; /* Name of binary */ }; void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr); -int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop); +int loader_exec(const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop); -int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); -int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); +int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len); @@ -193,9 +194,6 @@ extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); void signal_init(void); -//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); -//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); -//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUArchState *env); long do_rt_sigreturn(CPUArchState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); @@ -226,9 +224,11 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) return page_check_range((target_ulong)addr, size, type) == 0; } -/* NOTE __get_user and __put_user use host pointers and don't check access. */ -/* These are usually used to access struct data members once the - * struct has been locked - usually with lock_user_struct(). +/* + * NOTE __get_user and __put_user use host pointers and don't check access. + * + * These are usually used to access struct data members once the struct has been + * locked - usually with lock_user_struct(). */ #define __put_user(x, hptr)\ ({\ @@ -248,7 +248,7 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) break;\ default:\ abort();\ - }\ + } \ 0;\ }) @@ -269,24 +269,26 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ break;\ default:\ - /* avoid warning */\ x = 0;\ abort();\ - }\ + } \ 0;\ }) -/* put_user()/get_user() take a guest address and check access */ -/* These are usually used to access an atomic data type, such as an int, - * that has been passed by address. These internally perform locking - * and unlocking on the data type. +/* + * put_user()/get_user() take a guest address and check access + * + * These are usually used to access an atomic data type, such as an int, that + * has been passed by address. These internally perform locking and unlocking + * on the data type. */ #define put_user(x, gaddr, target_type) \ ({ \ abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0); \ + if (__hptr) { \ __ret = __put_user((x), __hptr); \ unlock_user(__hptr, __gaddr, sizeof(target_type)); \ } else \ @@ -299,11 +301,11 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1); \ + if (__hptr) { \ __ret = __get_user((x), __hptr); \ unlock_user(__hptr, __gaddr, 0); \ } else { \ - /* avoid warning */ \ (x) = 0; \ __ret = -TARGET_EFAULT; \ } \ @@ -332,33 +334,41 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) #define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) #define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) -/* copy_from_user() and copy_to_user() are usually used to copy data +/* + * copy_from_user() and copy_to_user() are usually used to copy data * buffers between the target and host. These internally perform * locking/unlocking of the memory. */ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); -/* Functions for accessing guest memory. The tget and tput functions - read/write single values, byteswapping as necessary. The lock_user function - gets a pointer to a contiguous area of guest memory, but does not perform - any byteswapping. lock_user may return either a pointer to the guest - memory, or a temporary buffer. */ +/* + * Functions for accessing guest memory. The tget and tput functions + * read/write single values, byteswapping as necessary. The lock_user function + * gets a pointer to a contiguous area of guest memory, but does not perform + * any byteswapping. lock_user may return either a pointer to the guest + * memory, or a temporary buffer. + */ -/* Lock an area of guest memory into the host. If copy is true then the - host area will have the same contents as the guest. */ -static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) +/* + * Lock an area of guest memory into the host. If copy is true then the + * host area will have the same contents as the guest. + */ +static inline void *lock_user(int type, abi_ulong guest_addr, long len, + int copy) { - if (!access_ok(type, guest_addr, len)) + if (!access_ok(type, guest_addr, len)) { return NULL; + } #ifdef DEBUG_REMAP { void *addr; addr = g_malloc(len); - if (copy) + if (copy) { memcpy(addr, g2h_untagged(guest_addr), len); - else + } else { memset(addr, 0, len); + } return addr; } #else @@ -366,26 +376,32 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy #endif } -/* Unlock an area of guest memory. The first LEN bytes must be - flushed back to guest memory. host_ptr = NULL is explicitly - allowed and does nothing. */ +/* + * Unlock an area of guest memory. The first LEN bytes must be flushed back to + * guest memory. host_ptr = NULL is explicitly allowed and does nothing. + */ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) { #ifdef DEBUG_REMAP - if (!host_ptr) + if (!host_ptr) { return; - if (host_ptr == g2h_untagged(guest_addr)) + } + if (host_ptr == g2h_untagged(guest_addr)) { return; - if (len > 0) + } + if (len > 0) { memcpy(g2h_untagged(guest_addr), host_ptr, len); + } g_free(host_ptr); #endif } -/* Return the length of a string in target memory or -TARGET_EFAULT if - access error. */ +/* + * Return the length of a string in target memory or -TARGET_EFAULT if access + * error. + */ abi_long target_strlen(abi_ulong gaddr); /* Like lock_user but for null terminated strings. */ @@ -393,8 +409,9 @@ static inline void *lock_user_string(abi_ulong guest_addr) { abi_long len; len = target_strlen(guest_addr); - if (len < 0) + if (len < 0) { return NULL; + } return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); } diff --git a/bsd-user/signal.c b/bsd-user/signal.c index f6f7aa2427..ad6d935569 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "target_signal.h" void signal_init(void) { diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h deleted file mode 100644 index 5b2abba40f..0000000000 --- a/bsd-user/sparc/target_signal.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h deleted file mode 100644 index 5b2abba40f..0000000000 --- a/bsd-user/sparc64/target_signal.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/strace.c b/bsd-user/strace.c index 2c3b59caf0..be40b8a20c 100644 --- a/bsd-user/strace.c +++ b/bsd-user/strace.c @@ -128,14 +128,6 @@ static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) } } -#if 0 /* currently unused */ -static void -print_syscall_ret_raw(struct syscallname *name, abi_long ret) -{ - gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); -} -#endif - /* * An array of all of the syscalls we know about */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 4abff796c7..7d986e9700 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -95,7 +95,7 @@ static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms) abi_ulong val; int idx; - switch(op) { + switch (op) { #ifdef TARGET_ABI32 case TARGET_FREEBSD_I386_SET_GSBASE: case TARGET_FREEBSD_I386_SET_FSBASE: @@ -272,7 +272,7 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); if (!target_vec) return -TARGET_EFAULT; - for(i = 0;i < count; i++) { + for (i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); if (vec[i].iov_len != 0) { @@ -298,7 +298,7 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); if (!target_vec) return -TARGET_EFAULT; - for(i = 0;i < count; i++) { + for (i = 0;i < count; i++) { if (target_vec[i].iov_base) { base = tswapl(target_vec[i].iov_base); unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); @@ -326,10 +326,10 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, #endif record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_FREEBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); @@ -428,10 +428,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_NETBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); @@ -507,10 +507,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_OPENBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); diff --git a/bsd-user/uaccess.c b/bsd-user/uaccess.c index 91e2067933..89163257f4 100644 --- a/bsd-user/uaccess.c +++ b/bsd-user/uaccess.c @@ -46,7 +46,7 @@ abi_long target_strlen(abi_ulong guest_addr1) int max_len, len; guest_addr = guest_addr1; - for(;;) { + for (;;) { max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); if (!ptr) diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h deleted file mode 100644 index 659cd401b8..0000000000 --- a/bsd-user/x86_64/target_signal.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/configure b/configure index 0e4233fd8a..9470fff09a 100755 --- a/configure +++ b/configure @@ -1651,7 +1651,7 @@ case "$cpu" in # No special flags required for other host CPUs esac -eval "cross_cc_${cpu}=\$host_cc" +eval "cross_cc_${cpu}=\$cc" cross_cc_vars="$cross_cc_vars cross_cc_${cpu}" QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS" @@ -6164,6 +6164,7 @@ echo "GENISOIMAGE=$genisoimage" >> $config_host_mak echo "MESON=$meson" >> $config_host_mak echo "NINJA=$ninja" >> $config_host_mak echo "CC=$cc" >> $config_host_mak +echo "HOST_CC=$host_cc" >> $config_host_mak if $iasl -h > /dev/null 2>&1; then echo "CONFIG_IASL=$iasl" >> $config_host_mak fi diff --git a/default-configs/targets/sparc-bsd-user.mak b/default-configs/targets/sparc-bsd-user.mak deleted file mode 100644 index 9ba3d7b07f..0000000000 --- a/default-configs/targets/sparc-bsd-user.mak +++ /dev/null @@ -1,3 +0,0 @@ -TARGET_ARCH=sparc -TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y diff --git a/default-configs/targets/sparc64-bsd-user.mak b/default-configs/targets/sparc64-bsd-user.mak deleted file mode 100644 index 8dd3217800..0000000000 --- a/default-configs/targets/sparc64-bsd-user.mak +++ /dev/null @@ -1,4 +0,0 @@ -TARGET_ARCH=sparc64 -TARGET_BASE_ARCH=sparc -TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 86d6f379d1..597d974dd4 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -29,6 +29,9 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files( 'spapr_numa.c', 'pef.c', )) +ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_TCG'], if_true: files( + 'spapr_softmmu.c', +)) ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c')) ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_LINUX'], if_true: files( 'spapr_pci_vfio.c', diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index ffe01977cd..d16dd2d080 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -196,7 +196,7 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); - if (env->spr_cb[SPR_PURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8f40319aee..c23bcc4490 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -703,10 +703,10 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset, _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); - if (env->spr_cb[SPR_PURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1))); } - if (env->spr_cb[SPR_SPURR].oea_read) { + if (ppc_has_spr(cpu, SPR_PURR)) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1))); } @@ -979,6 +979,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, */ val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */ val[3] = 0x00; /* Hash */ + spapr_check_mmu_mode(false); } else if (kvm_enabled()) { if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { val[3] = 0x80; /* OV5_MMU_BOTH */ @@ -1556,6 +1557,22 @@ void spapr_setup_hpt(SpaprMachineState *spapr) } } +void spapr_check_mmu_mode(bool guest_radix) +{ + if (guest_radix) { + if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { + error_report("Guest requested unavailable MMU mode (radix)."); + exit(EXIT_FAILURE); + } + } else { + if (kvm_enabled() && kvmppc_has_cap_mmu_radix() + && !kvmppc_has_cap_mmu_hash_v3()) { + error_report("Guest requested unavailable MMU mode (hash)."); + exit(EXIT_FAILURE); + } + } +} + static void spapr_machine_reset(MachineState *machine) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 9ea7ddd1e9..d0c419b392 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -371,6 +371,65 @@ static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift, return true; } +static void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, + bool (*cb)(void *, uint32_t, uint32_t), + void *opaque) +{ + PPCHash64Options *opts = cpu->hash64_opts; + int i; + int n = 0; + bool ci_largepage = false; + + assert(opts); + + n = 0; + for (i = 0; i < ARRAY_SIZE(opts->sps); i++) { + PPCHash64SegmentPageSizes *sps = &opts->sps[i]; + int j; + int m = 0; + + assert(n <= i); + + if (!sps->page_shift) { + break; + } + + for (j = 0; j < ARRAY_SIZE(sps->enc); j++) { + PPCHash64PageSize *ps = &sps->enc[j]; + + assert(m <= j); + if (!ps->page_shift) { + break; + } + + if (cb(opaque, sps->page_shift, ps->page_shift)) { + if (ps->page_shift >= 16) { + ci_largepage = true; + } + sps->enc[m++] = *ps; + } + } + + /* Clear rest of the row */ + for (j = m; j < ARRAY_SIZE(sps->enc); j++) { + memset(&sps->enc[j], 0, sizeof(sps->enc[j])); + } + + if (m) { + n++; + } + } + + /* Clear the rest of the table */ + for (i = n; i < ARRAY_SIZE(opts->sps); i++) { + memset(&opts->sps[i], 0, sizeof(opts->sps[i])); + } + + if (!ci_largepage) { + opts->flags &= ~PPC_HASH64_CI_LARGEPAGE; + } +} + static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu, uint8_t val, Error **errp) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 16c719c3de..f25014afda 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -20,24 +20,7 @@ #include "mmu-book3s-v3.h" #include "hw/mem/memory-device.h" -static bool has_spr(PowerPCCPU *cpu, int spr) -{ - /* We can test whether the SPR is defined by checking for a valid name */ - return cpu->env.spr_cb[spr].name != NULL; -} - -static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) -{ - /* - * hash value/pteg group index is normalized by HPT mask - */ - if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { - return false; - } - return true; -} - -static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) +bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) { MachineState *machine = MACHINE(spapr); DeviceMemoryState *dms = machine->device_memory; @@ -53,355 +36,6 @@ static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr) return false; } -static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong pteh = args[2]; - target_ulong ptel = args[3]; - unsigned apshift; - target_ulong raddr; - target_ulong slot; - const ppc_hash_pte64_t *hptes; - - apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); - if (!apshift) { - /* Bad page size encoding */ - return H_PARAMETER; - } - - raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); - - if (is_ram_address(spapr, raddr)) { - /* Regular RAM - should have WIMG=0010 */ - if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { - return H_PARAMETER; - } - } else { - target_ulong wimg_flags; - /* Looks like an IO address */ - /* FIXME: What WIMG combinations could be sensible for IO? - * For now we allow WIMG=010x, but are there others? */ - /* FIXME: Should we check against registered IO addresses? */ - wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); - - if (wimg_flags != HPTE64_R_I && - wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { - return H_PARAMETER; - } - } - - pteh &= ~0x60ULL; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - slot = ptex & 7ULL; - ptex = ptex & ~7ULL; - - if (likely((flags & H_EXACT) == 0)) { - hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); - for (slot = 0; slot < 8; slot++) { - if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { - break; - } - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - if (slot == 8) { - return H_PTEG_FULL; - } - } else { - hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); - if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { - ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); - return H_PTEG_FULL; - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - } - - spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); - - args[0] = ptex + slot; - return H_SUCCESS; -} - -typedef enum { - REMOVE_SUCCESS = 0, - REMOVE_NOT_FOUND = 1, - REMOVE_PARM = 2, - REMOVE_HW = 3, -} RemoveResult; - -static RemoveResult remove_hpte(PowerPCCPU *cpu - , target_ulong ptex, - target_ulong avpn, - target_ulong flags, - target_ulong *vp, target_ulong *rp) -{ - const ppc_hash_pte64_t *hptes; - target_ulong v, r; - - if (!valid_ptex(cpu, ptex)) { - return REMOVE_PARM; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, 1); - v = ppc_hash64_hpte0(cpu, hptes, 0); - r = ppc_hash64_hpte1(cpu, hptes, 0); - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - - if ((v & HPTE64_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || - ((flags & H_ANDCOND) && (v & avpn) != 0)) { - return REMOVE_NOT_FOUND; - } - *vp = v; - *rp = r; - spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); - ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); - return REMOVE_SUCCESS; -} - -static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong avpn = args[2]; - RemoveResult ret; - - ret = remove_hpte(cpu, ptex, avpn, flags, - &args[0], &args[1]); - - switch (ret) { - case REMOVE_SUCCESS: - check_tlb_flush(env, true); - return H_SUCCESS; - - case REMOVE_NOT_FOUND: - return H_NOT_FOUND; - - case REMOVE_PARM: - return H_PARAMETER; - - case REMOVE_HW: - return H_HARDWARE; - } - - g_assert_not_reached(); -} - -#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL -#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL -#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL -#define H_BULK_REMOVE_END 0xc000000000000000ULL -#define H_BULK_REMOVE_CODE 0x3000000000000000ULL -#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL -#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL -#define H_BULK_REMOVE_PARM 0x2000000000000000ULL -#define H_BULK_REMOVE_HW 0x3000000000000000ULL -#define H_BULK_REMOVE_RC 0x0c00000000000000ULL -#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL -#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL -#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL -#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL -#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL - -#define H_BULK_REMOVE_MAX_BATCH 4 - -static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - int i; - target_ulong rc = H_SUCCESS; - - for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { - target_ulong *tsh = &args[i*2]; - target_ulong tsl = args[i*2 + 1]; - target_ulong v, r, ret; - - if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { - break; - } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { - return H_PARAMETER; - } - - *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; - *tsh |= H_BULK_REMOVE_RESPONSE; - - if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { - *tsh |= H_BULK_REMOVE_PARM; - return H_PARAMETER; - } - - ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, - (*tsh & H_BULK_REMOVE_FLAGS) >> 26, - &v, &r); - - *tsh |= ret << 60; - - switch (ret) { - case REMOVE_SUCCESS: - *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; - break; - - case REMOVE_PARM: - rc = H_PARAMETER; - goto exit; - - case REMOVE_HW: - rc = H_HARDWARE; - goto exit; - } - } - exit: - check_tlb_flush(env, true); - - return rc; -} - -static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUPPCState *env = &cpu->env; - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - target_ulong avpn = args[2]; - const ppc_hash_pte64_t *hptes; - target_ulong v, r; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, 1); - v = ppc_hash64_hpte0(cpu, hptes, 0); - r = ppc_hash64_hpte1(cpu, hptes, 0); - ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); - - if ((v & HPTE64_V_VALID) == 0 || - ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - return H_NOT_FOUND; - } - - r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | - HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); - r |= (flags << 55) & HPTE64_R_PP0; - r |= (flags << 48) & HPTE64_R_KEY_HI; - r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); - spapr_store_hpte(cpu, ptex, - (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); - ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); - /* Flush the tlb */ - check_tlb_flush(env, true); - /* Don't need a memory barrier, due to qemu's global lock */ - spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); - return H_SUCCESS; -} - -static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong flags = args[0]; - target_ulong ptex = args[1]; - int i, ridx, n_entries = 1; - const ppc_hash_pte64_t *hptes; - - if (!valid_ptex(cpu, ptex)) { - return H_PARAMETER; - } - - if (flags & H_READ_4) { - /* Clear the two low order bits */ - ptex &= ~(3ULL); - n_entries = 4; - } - - hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); - for (i = 0, ridx = 0; i < n_entries; i++) { - args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); - args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); - - return H_SUCCESS; -} - -struct SpaprPendingHpt { - /* These fields are read-only after initialization */ - int shift; - QemuThread thread; - - /* These fields are protected by the BQL */ - bool complete; - - /* These fields are private to the preparation thread if - * !complete, otherwise protected by the BQL */ - int ret; - void *hpt; -}; - -static void free_pending_hpt(SpaprPendingHpt *pending) -{ - if (pending->hpt) { - qemu_vfree(pending->hpt); - } - - g_free(pending); -} - -static void *hpt_prepare_thread(void *opaque) -{ - SpaprPendingHpt *pending = opaque; - size_t size = 1ULL << pending->shift; - - pending->hpt = qemu_try_memalign(size, size); - if (pending->hpt) { - memset(pending->hpt, 0, size); - pending->ret = H_SUCCESS; - } else { - pending->ret = H_NO_MEM; - } - - qemu_mutex_lock_iothread(); - - if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { - /* Ready to go */ - pending->complete = true; - } else { - /* We've been cancelled, clean ourselves up */ - free_pending_hpt(pending); - } - - qemu_mutex_unlock_iothread(); - return NULL; -} - -/* Must be called with BQL held */ -static void cancel_hpt_prepare(SpaprMachineState *spapr) -{ - SpaprPendingHpt *pending = spapr->pending_hpt; - - /* Let the thread know it's cancelled */ - spapr->pending_hpt = NULL; - - if (!pending) { - /* Nothing to do */ - return; - } - - if (!pending->complete) { - /* thread will clean itself up */ - return; - } - - free_pending_hpt(pending); -} - /* Convert a return code from the KVM ioctl()s implementing resize HPT * into a PAPR hypercall return code */ static target_ulong resize_hpt_convert_rc(int ret) @@ -447,7 +81,6 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, { target_ulong flags = args[0]; int shift = args[1]; - SpaprPendingHpt *pending = spapr->pending_hpt; uint64_t current_ram_size; int rc; @@ -484,182 +117,11 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, return resize_hpt_convert_rc(rc); } - if (pending) { - /* something already in progress */ - if (pending->shift == shift) { - /* and it's suitable */ - if (pending->complete) { - return pending->ret; - } else { - return H_LONG_BUSY_ORDER_100_MSEC; - } - } - - /* not suitable, cancel and replace */ - cancel_hpt_prepare(spapr); - } - - if (!shift) { - /* nothing to do */ - return H_SUCCESS; - } - - /* start new prepare */ - - pending = g_new0(SpaprPendingHpt, 1); - pending->shift = shift; - pending->ret = H_HARDWARE; - - qemu_thread_create(&pending->thread, "sPAPR HPT prepare", - hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); - - spapr->pending_hpt = pending; - - /* In theory we could estimate the time more accurately based on - * the new size, but there's not much point */ - return H_LONG_BUSY_ORDER_100_MSEC; -} - -static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) -{ - uint8_t *addr = htab; - - addr += pteg * HASH_PTEG_SIZE_64; - addr += slot * HASH_PTE_SIZE_64; - return ldq_p(addr); -} - -static void new_hpte_store(void *htab, uint64_t pteg, int slot, - uint64_t pte0, uint64_t pte1) -{ - uint8_t *addr = htab; - - addr += pteg * HASH_PTEG_SIZE_64; - addr += slot * HASH_PTE_SIZE_64; - - stq_p(addr, pte0); - stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1); -} - -static int rehash_hpte(PowerPCCPU *cpu, - const ppc_hash_pte64_t *hptes, - void *old_hpt, uint64_t oldsize, - void *new_hpt, uint64_t newsize, - uint64_t pteg, int slot) -{ - uint64_t old_hash_mask = (oldsize >> 7) - 1; - uint64_t new_hash_mask = (newsize >> 7) - 1; - target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); - target_ulong pte1; - uint64_t avpn; - unsigned base_pg_shift; - uint64_t hash, new_pteg, replace_pte0; - - if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { - return H_SUCCESS; - } - - pte1 = ppc_hash64_hpte1(cpu, hptes, slot); - - base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); - assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ - avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); - - if (pte0 & HPTE64_V_SECONDARY) { - pteg = ~pteg; - } - - if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { - uint64_t offset, vsid; - - /* We only have 28 - 23 bits of offset in avpn */ - offset = (avpn & 0x1f) << 23; - vsid = avpn >> 5; - /* We can find more bits from the pteg value */ - if (base_pg_shift < 23) { - offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; - } - - hash = vsid ^ (offset >> base_pg_shift); - } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { - uint64_t offset, vsid; - - /* We only have 40 - 23 bits of seg_off in avpn */ - offset = (avpn & 0x1ffff) << 23; - vsid = avpn >> 17; - if (base_pg_shift < 23) { - offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) - << base_pg_shift; - } - - hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); - } else { - error_report("rehash_pte: Bad segment size in HPTE"); + if (kvm_enabled()) { return H_HARDWARE; } - new_pteg = hash & new_hash_mask; - if (pte0 & HPTE64_V_SECONDARY) { - assert(~pteg == (hash & old_hash_mask)); - new_pteg = ~new_pteg; - } else { - assert(pteg == (hash & old_hash_mask)); - } - assert((oldsize != newsize) || (pteg == new_pteg)); - replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); - /* - * Strictly speaking, we don't need all these tests, since we only - * ever rehash bolted HPTEs. We might in future handle non-bolted - * HPTEs, though so make the logic correct for those cases as - * well. - */ - if (replace_pte0 & HPTE64_V_VALID) { - assert(newsize < oldsize); - if (replace_pte0 & HPTE64_V_BOLTED) { - if (pte0 & HPTE64_V_BOLTED) { - /* Bolted collision, nothing we can do */ - return H_PTEG_FULL; - } else { - /* Discard this hpte */ - return H_SUCCESS; - } - } - } - - new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); - return H_SUCCESS; -} - -static int rehash_hpt(PowerPCCPU *cpu, - void *old_hpt, uint64_t oldsize, - void *new_hpt, uint64_t newsize) -{ - uint64_t n_ptegs = oldsize >> 7; - uint64_t pteg; - int slot; - int rc; - - for (pteg = 0; pteg < n_ptegs; pteg++) { - hwaddr ptex = pteg * HPTES_PER_GROUP; - const ppc_hash_pte64_t *hptes - = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); - - if (!hptes) { - return H_HARDWARE; - } - - for (slot = 0; slot < HPTES_PER_GROUP; slot++) { - rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, - pteg, slot); - if (rc != H_SUCCESS) { - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - return rc; - } - } - ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); - } - - return H_SUCCESS; + return softmmu_resize_hpt_prepare(cpu, spapr, shift); } static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data) @@ -675,7 +137,7 @@ static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data) } } -static void push_sregs_to_kvm_pr(SpaprMachineState *spapr) +void push_sregs_to_kvm_pr(SpaprMachineState *spapr) { CPUState *cs; @@ -700,9 +162,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, { target_ulong flags = args[0]; target_ulong shift = args[1]; - SpaprPendingHpt *pending = spapr->pending_hpt; int rc; - size_t newsize; if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { return H_AUTHORITY; @@ -725,42 +185,14 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, return rc; } - if (flags != 0) { - return H_PARAMETER; - } - - if (!pending || (pending->shift != shift)) { - /* no matching prepare */ - return H_CLOSED; - } - - if (!pending->complete) { - /* prepare has not completed */ - return H_BUSY; + if (kvm_enabled()) { + return H_HARDWARE; } - /* Shouldn't have got past PREPARE without an HPT */ - g_assert(spapr->htab_shift); - - newsize = 1ULL << pending->shift; - rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), - pending->hpt, newsize); - if (rc == H_SUCCESS) { - qemu_vfree(spapr->htab); - spapr->htab = pending->hpt; - spapr->htab_shift = pending->shift; - - push_sregs_to_kvm_pr(spapr); - - pending->hpt = NULL; /* so it's not free()d */ - } + return softmmu_resize_hpt_commit(cpu, spapr, flags, shift); +} - /* Clean up */ - spapr->pending_hpt = NULL; - free_pending_hpt(pending); - return rc; -} static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) @@ -774,12 +206,12 @@ static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr, static target_ulong h_set_dabr(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) { - if (!has_spr(cpu, SPR_DABR)) { + if (!ppc_has_spr(cpu, SPR_DABR)) { return H_HARDWARE; /* DABR register not available */ } cpu_synchronize_state(CPU(cpu)); - if (has_spr(cpu, SPR_DABRX)) { + if (ppc_has_spr(cpu, SPR_DABRX)) { cpu->env.spr[SPR_DABRX] = 0x3; /* Use Problem and Privileged state */ } else if (!(args[0] & 0x4)) { /* Breakpoint Translation set? */ return H_RESERVED_DABR; @@ -794,7 +226,7 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, SpaprMachineState *spapr, { target_ulong dabrx = args[1]; - if (!has_spr(cpu, SPR_DABR) || !has_spr(cpu, SPR_DABRX)) { + if (!ppc_has_spr(cpu, SPR_DABR) || !ppc_has_spr(cpu, SPR_DABRX)) { return H_HARDWARE; } @@ -1760,18 +1192,8 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest); spapr_ovec_cleanup(ov5_guest); - if (guest_radix) { - if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) { - error_report("Guest requested unavailable MMU mode (radix)."); - exit(EXIT_FAILURE); - } - } else { - if (kvm_enabled() && kvmppc_has_cap_mmu_radix() - && !kvmppc_has_cap_mmu_hash_v3()) { - error_report("Guest requested unavailable MMU mode (hash)."); - exit(EXIT_FAILURE); - } - } + spapr_check_mmu_mode(guest_radix); + spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); spapr_ovec_cleanup(ov1_guest); @@ -2023,16 +1445,34 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, return H_FUNCTION; } -static void hypercall_register_types(void) +#ifndef CONFIG_TCG +static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + g_assert_not_reached(); +} + +static void hypercall_register_softmmu(void) { /* hcall-pft */ - spapr_register_hypercall(H_ENTER, h_enter); - spapr_register_hypercall(H_REMOVE, h_remove); - spapr_register_hypercall(H_PROTECT, h_protect); - spapr_register_hypercall(H_READ, h_read); + spapr_register_hypercall(H_ENTER, h_softmmu); + spapr_register_hypercall(H_REMOVE, h_softmmu); + spapr_register_hypercall(H_PROTECT, h_softmmu); + spapr_register_hypercall(H_READ, h_softmmu); /* hcall-bulk */ - spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + spapr_register_hypercall(H_BULK_REMOVE, h_softmmu); +} +#else +static void hypercall_register_softmmu(void) +{ + /* DO NOTHING */ +} +#endif + +static void hypercall_register_types(void) +{ + hypercall_register_softmmu(); /* hcall-hpt-resize */ spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare); diff --git a/hw/ppc/spapr_softmmu.c b/hw/ppc/spapr_softmmu.c new file mode 100644 index 0000000000..6c6b86dd3c --- /dev/null +++ b/hw/ppc/spapr_softmmu.c @@ -0,0 +1,627 @@ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qapi/error.h" +#include "sysemu/hw_accel.h" +#include "sysemu/runstate.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "helper_regs.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_cpu_core.h" +#include "mmu-hash64.h" +#include "cpu-models.h" +#include "trace.h" +#include "kvm_ppc.h" +#include "hw/ppc/fdt.h" +#include "hw/ppc/spapr_ovec.h" +#include "mmu-book3s-v3.h" +#include "hw/mem/memory-device.h" + +static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) +{ + /* + * hash value/pteg group index is normalized by HPT mask + */ + if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { + return false; + } + return true; +} + +static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong pteh = args[2]; + target_ulong ptel = args[3]; + unsigned apshift; + target_ulong raddr; + target_ulong slot; + const ppc_hash_pte64_t *hptes; + + apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); + if (!apshift) { + /* Bad page size encoding */ + return H_PARAMETER; + } + + raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); + + if (is_ram_address(spapr, raddr)) { + /* Regular RAM - should have WIMG=0010 */ + if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { + return H_PARAMETER; + } + } else { + target_ulong wimg_flags; + /* Looks like an IO address */ + /* FIXME: What WIMG combinations could be sensible for IO? + * For now we allow WIMG=010x, but are there others? */ + /* FIXME: Should we check against registered IO addresses? */ + wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); + + if (wimg_flags != HPTE64_R_I && + wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { + return H_PARAMETER; + } + } + + pteh &= ~0x60ULL; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + slot = ptex & 7ULL; + ptex = ptex & ~7ULL; + + if (likely((flags & H_EXACT) == 0)) { + hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); + for (slot = 0; slot < 8; slot++) { + if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { + break; + } + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + if (slot == 8) { + return H_PTEG_FULL; + } + } else { + hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); + if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); + return H_PTEG_FULL; + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + } + + spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); + + args[0] = ptex + slot; + return H_SUCCESS; +} + +typedef enum { + REMOVE_SUCCESS = 0, + REMOVE_NOT_FOUND = 1, + REMOVE_PARM = 2, + REMOVE_HW = 3, +} RemoveResult; + +static RemoveResult remove_hpte(PowerPCCPU *cpu + , target_ulong ptex, + target_ulong avpn, + target_ulong flags, + target_ulong *vp, target_ulong *rp) +{ + const ppc_hash_pte64_t *hptes; + target_ulong v, r; + + if (!valid_ptex(cpu, ptex)) { + return REMOVE_PARM; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + + if ((v & HPTE64_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || + ((flags & H_ANDCOND) && (v & avpn) != 0)) { + return REMOVE_NOT_FOUND; + } + *vp = v; + *rp = r; + spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); + ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); + return REMOVE_SUCCESS; +} + +static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong avpn = args[2]; + RemoveResult ret; + + ret = remove_hpte(cpu, ptex, avpn, flags, + &args[0], &args[1]); + + switch (ret) { + case REMOVE_SUCCESS: + check_tlb_flush(env, true); + return H_SUCCESS; + + case REMOVE_NOT_FOUND: + return H_NOT_FOUND; + + case REMOVE_PARM: + return H_PARAMETER; + + case REMOVE_HW: + return H_HARDWARE; + } + + g_assert_not_reached(); +} + +#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL +#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL +#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL +#define H_BULK_REMOVE_END 0xc000000000000000ULL +#define H_BULK_REMOVE_CODE 0x3000000000000000ULL +#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL +#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL +#define H_BULK_REMOVE_PARM 0x2000000000000000ULL +#define H_BULK_REMOVE_HW 0x3000000000000000ULL +#define H_BULK_REMOVE_RC 0x0c00000000000000ULL +#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL +#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL +#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL +#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL +#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL + +#define H_BULK_REMOVE_MAX_BATCH 4 + +static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + int i; + target_ulong rc = H_SUCCESS; + + for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { + target_ulong *tsh = &args[i*2]; + target_ulong tsl = args[i*2 + 1]; + target_ulong v, r, ret; + + if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { + break; + } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { + return H_PARAMETER; + } + + *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; + *tsh |= H_BULK_REMOVE_RESPONSE; + + if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { + *tsh |= H_BULK_REMOVE_PARM; + return H_PARAMETER; + } + + ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, + (*tsh & H_BULK_REMOVE_FLAGS) >> 26, + &v, &r); + + *tsh |= ret << 60; + + switch (ret) { + case REMOVE_SUCCESS: + *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; + break; + + case REMOVE_PARM: + rc = H_PARAMETER; + goto exit; + + case REMOVE_HW: + rc = H_HARDWARE; + goto exit; + } + } + exit: + check_tlb_flush(env, true); + + return rc; +} + +static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + target_ulong avpn = args[2]; + const ppc_hash_pte64_t *hptes; + target_ulong v, r; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, 1); + v = ppc_hash64_hpte0(cpu, hptes, 0); + r = ppc_hash64_hpte1(cpu, hptes, 0); + ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); + + if ((v & HPTE64_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { + return H_NOT_FOUND; + } + + r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | + HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); + r |= (flags << 55) & HPTE64_R_PP0; + r |= (flags << 48) & HPTE64_R_KEY_HI; + r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); + spapr_store_hpte(cpu, ptex, + (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); + ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); + /* Flush the tlb */ + check_tlb_flush(env, true); + /* Don't need a memory barrier, due to qemu's global lock */ + spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); + return H_SUCCESS; +} + +static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong ptex = args[1]; + int i, ridx, n_entries = 1; + const ppc_hash_pte64_t *hptes; + + if (!valid_ptex(cpu, ptex)) { + return H_PARAMETER; + } + + if (flags & H_READ_4) { + /* Clear the two low order bits */ + ptex &= ~(3ULL); + n_entries = 4; + } + + hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); + for (i = 0, ridx = 0; i < n_entries; i++) { + args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); + args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); + + return H_SUCCESS; +} + +struct SpaprPendingHpt { + /* These fields are read-only after initialization */ + int shift; + QemuThread thread; + + /* These fields are protected by the BQL */ + bool complete; + + /* These fields are private to the preparation thread if + * !complete, otherwise protected by the BQL */ + int ret; + void *hpt; +}; + +static void free_pending_hpt(SpaprPendingHpt *pending) +{ + if (pending->hpt) { + qemu_vfree(pending->hpt); + } + + g_free(pending); +} + +static void *hpt_prepare_thread(void *opaque) +{ + SpaprPendingHpt *pending = opaque; + size_t size = 1ULL << pending->shift; + + pending->hpt = qemu_try_memalign(size, size); + if (pending->hpt) { + memset(pending->hpt, 0, size); + pending->ret = H_SUCCESS; + } else { + pending->ret = H_NO_MEM; + } + + qemu_mutex_lock_iothread(); + + if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { + /* Ready to go */ + pending->complete = true; + } else { + /* We've been cancelled, clean ourselves up */ + free_pending_hpt(pending); + } + + qemu_mutex_unlock_iothread(); + return NULL; +} + +/* Must be called with BQL held */ +static void cancel_hpt_prepare(SpaprMachineState *spapr) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + + /* Let the thread know it's cancelled */ + spapr->pending_hpt = NULL; + + if (!pending) { + /* Nothing to do */ + return; + } + + if (!pending->complete) { + /* thread will clean itself up */ + return; + } + + free_pending_hpt(pending); +} + +target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong shift) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + + if (pending) { + /* something already in progress */ + if (pending->shift == shift) { + /* and it's suitable */ + if (pending->complete) { + return pending->ret; + } else { + return H_LONG_BUSY_ORDER_100_MSEC; + } + } + + /* not suitable, cancel and replace */ + cancel_hpt_prepare(spapr); + } + + if (!shift) { + /* nothing to do */ + return H_SUCCESS; + } + + /* start new prepare */ + + pending = g_new0(SpaprPendingHpt, 1); + pending->shift = shift; + pending->ret = H_HARDWARE; + + qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); + + spapr->pending_hpt = pending; + + /* In theory we could estimate the time more accurately based on + * the new size, but there's not much point */ + return H_LONG_BUSY_ORDER_100_MSEC; +} + +static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) +{ + uint8_t *addr = htab; + + addr += pteg * HASH_PTEG_SIZE_64; + addr += slot * HASH_PTE_SIZE_64; + return ldq_p(addr); +} + +static void new_hpte_store(void *htab, uint64_t pteg, int slot, + uint64_t pte0, uint64_t pte1) +{ + uint8_t *addr = htab; + + addr += pteg * HASH_PTEG_SIZE_64; + addr += slot * HASH_PTE_SIZE_64; + + stq_p(addr, pte0); + stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1); +} + +static int rehash_hpte(PowerPCCPU *cpu, + const ppc_hash_pte64_t *hptes, + void *old_hpt, uint64_t oldsize, + void *new_hpt, uint64_t newsize, + uint64_t pteg, int slot) +{ + uint64_t old_hash_mask = (oldsize >> 7) - 1; + uint64_t new_hash_mask = (newsize >> 7) - 1; + target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); + target_ulong pte1; + uint64_t avpn; + unsigned base_pg_shift; + uint64_t hash, new_pteg, replace_pte0; + + if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { + return H_SUCCESS; + } + + pte1 = ppc_hash64_hpte1(cpu, hptes, slot); + + base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); + assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ + avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); + + if (pte0 & HPTE64_V_SECONDARY) { + pteg = ~pteg; + } + + if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { + uint64_t offset, vsid; + + /* We only have 28 - 23 bits of offset in avpn */ + offset = (avpn & 0x1f) << 23; + vsid = avpn >> 5; + /* We can find more bits from the pteg value */ + if (base_pg_shift < 23) { + offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; + } + + hash = vsid ^ (offset >> base_pg_shift); + } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { + uint64_t offset, vsid; + + /* We only have 40 - 23 bits of seg_off in avpn */ + offset = (avpn & 0x1ffff) << 23; + vsid = avpn >> 17; + if (base_pg_shift < 23) { + offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) + << base_pg_shift; + } + + hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); + } else { + error_report("rehash_pte: Bad segment size in HPTE"); + return H_HARDWARE; + } + + new_pteg = hash & new_hash_mask; + if (pte0 & HPTE64_V_SECONDARY) { + assert(~pteg == (hash & old_hash_mask)); + new_pteg = ~new_pteg; + } else { + assert(pteg == (hash & old_hash_mask)); + } + assert((oldsize != newsize) || (pteg == new_pteg)); + replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); + /* + * Strictly speaking, we don't need all these tests, since we only + * ever rehash bolted HPTEs. We might in future handle non-bolted + * HPTEs, though so make the logic correct for those cases as + * well. + */ + if (replace_pte0 & HPTE64_V_VALID) { + assert(newsize < oldsize); + if (replace_pte0 & HPTE64_V_BOLTED) { + if (pte0 & HPTE64_V_BOLTED) { + /* Bolted collision, nothing we can do */ + return H_PTEG_FULL; + } else { + /* Discard this hpte */ + return H_SUCCESS; + } + } + } + + new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); + return H_SUCCESS; +} + +static int rehash_hpt(PowerPCCPU *cpu, + void *old_hpt, uint64_t oldsize, + void *new_hpt, uint64_t newsize) +{ + uint64_t n_ptegs = oldsize >> 7; + uint64_t pteg; + int slot; + int rc; + + for (pteg = 0; pteg < n_ptegs; pteg++) { + hwaddr ptex = pteg * HPTES_PER_GROUP; + const ppc_hash_pte64_t *hptes + = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); + + if (!hptes) { + return H_HARDWARE; + } + + for (slot = 0; slot < HPTES_PER_GROUP; slot++) { + rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, + pteg, slot); + if (rc != H_SUCCESS) { + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + return rc; + } + } + ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); + } + + return H_SUCCESS; +} + +target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong flags, + target_ulong shift) +{ + SpaprPendingHpt *pending = spapr->pending_hpt; + int rc; + size_t newsize; + + if (flags != 0) { + return H_PARAMETER; + } + + if (!pending || (pending->shift != shift)) { + /* no matching prepare */ + return H_CLOSED; + } + + if (!pending->complete) { + /* prepare has not completed */ + return H_BUSY; + } + + /* Shouldn't have got past PREPARE without an HPT */ + g_assert(spapr->htab_shift); + + newsize = 1ULL << pending->shift; + rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), + pending->hpt, newsize); + if (rc == H_SUCCESS) { + qemu_vfree(spapr->htab); + spapr->htab = pending->hpt; + spapr->htab_shift = pending->shift; + + push_sregs_to_kvm_pr(spapr); + + pending->hpt = NULL; /* so it's not free()d */ + } + + /* Clean up */ + spapr->pending_hpt = NULL; + free_pending_hpt(pending); + + return rc; +} + +static void hypercall_register_types(void) +{ + /* hcall-pft */ + spapr_register_hypercall(H_ENTER, h_enter); + spapr_register_hypercall(H_REMOVE, h_remove); + spapr_register_hypercall(H_PROTECT, h_protect); + spapr_register_hypercall(H_READ, h_read); + + /* hcall-bulk */ + spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + +} + +type_init(hypercall_register_types) diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 25e628f575..13e93d8d8f 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -158,7 +158,6 @@ static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, emulated_ccw_3270_properties); - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; dc->realize = emulated_ccw_3270_realize; dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c index c9707110e9..95f269ab44 100644 --- a/hw/s390x/ccw-device.c +++ b/hw/s390x/ccw-device.c @@ -59,6 +59,7 @@ static void ccw_device_class_init(ObjectClass *klass, void *data) k->refill_ids = ccw_device_refill_ids; device_class_set_props(dc, ccw_device_properties); dc->reset = ccw_device_reset; + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; } const VMStateDescription vmstate_ccw_dev = { diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h index 832c78cd42..6dff95225d 100644 --- a/hw/s390x/ccw-device.h +++ b/hw/s390x/ccw-device.h @@ -14,6 +14,7 @@ #include "qom/object.h" #include "hw/qdev-core.h" #include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" struct CcwDevice { DeviceState parent_obj; diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 242491a1ae..c227c77984 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -176,10 +176,8 @@ static void s390_ccw_instance_init(Object *obj) static void s390_ccw_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; cdc->realize = s390_ccw_realize; cdc->unrealize = s390_ccw_unrealize; } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 92b950e09a..220b9efcf9 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1234,7 +1234,6 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) k->unplug = virtio_ccw_busdev_unplug; dc->realize = virtio_ccw_busdev_realize; dc->unrealize = virtio_ccw_busdev_unrealize; - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; device_class_set_parent_reset(dc, virtio_ccw_reset, &vdc->parent_reset); } diff --git a/hw/tricore/meson.build b/hw/tricore/meson.build index 77ff6fd137..47e36bb077 100644 --- a/hw/tricore/meson.build +++ b/hw/tricore/meson.build @@ -1,5 +1,6 @@ tricore_ss = ss.source_set() tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testboard.c')) +tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testdevice.c')) tricore_ss.add(when: 'CONFIG_TRIBOARD', if_true: files('triboard.c')) tricore_ss.add(when: 'CONFIG_TC27X_SOC', if_true: files('tc27x_soc.c')) diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index 51658d9e37..b6810e3be0 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -27,6 +27,7 @@ #include "hw/loader.h" #include "elf.h" #include "hw/tricore/tricore.h" +#include "hw/tricore/tricore_testdevice.h" #include "qemu/error-report.h" @@ -56,6 +57,7 @@ static void tricore_testboard_init(MachineState *machine, int board_id) { TriCoreCPU *cpu; CPUTriCoreState *env; + TriCoreTestDeviceState *test_dev; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ext_cram = g_new(MemoryRegion, 1); @@ -87,6 +89,12 @@ static void tricore_testboard_init(MachineState *machine, int board_id) memory_region_add_subregion(sysmem, 0xf0050000, pcp_data); memory_region_add_subregion(sysmem, 0xf0060000, pcp_text); + test_dev = g_new(TriCoreTestDeviceState, 1); + object_initialize(test_dev, sizeof(TriCoreTestDeviceState), + TYPE_TRICORE_TESTDEVICE); + memory_region_add_subregion(sysmem, 0xf0000000, &test_dev->iomem); + + tricoretb_binfo.ram_size = machine->ram_size; tricoretb_binfo.kernel_filename = machine->kernel_filename; diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c new file mode 100644 index 0000000000..a1563aa568 --- /dev/null +++ b/hw/tricore/tricore_testdevice.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2021 Bastian Koppelmann Paderborn University + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/qdev-properties.h" +#include "hw/tricore/tricore_testdevice.h" + +static void tricore_testdevice_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + exit(value); +} + +static uint64_t tricore_testdevice_read(void *opaque, hwaddr offset, + unsigned size) +{ + return 0xdeadbeef; +} + +static void tricore_testdevice_reset(DeviceState *dev) +{ +} + +static const MemoryRegionOps tricore_testdevice_ops = { + .read = tricore_testdevice_read, + .write = tricore_testdevice_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void tricore_testdevice_init(Object *obj) +{ + TriCoreTestDeviceState *s = TRICORE_TESTDEVICE(obj); + /* map memory */ + memory_region_init_io(&s->iomem, OBJECT(s), &tricore_testdevice_ops, s, + "tricore_testdevice", 0x4); +} + +static Property tricore_testdevice_properties[] = { + DEFINE_PROP_END_OF_LIST() +}; + +static void tricore_testdevice_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, tricore_testdevice_properties); + dc->reset = tricore_testdevice_reset; +} + +static const TypeInfo tricore_testdevice_info = { + .name = TYPE_TRICORE_TESTDEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TriCoreTestDeviceState), + .instance_init = tricore_testdevice_init, + .class_init = tricore_testdevice_class_init, +}; + +static void tricore_testdevice_register_types(void) +{ + type_register_static(&tricore_testdevice_info); +} + +type_init(tricore_testdevice_register_types) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index e752c845e9..139a3d9d1b 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -411,8 +411,8 @@ static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, } if (vdev->num_irqs < irq + 1) { - error_setg(errp, "vfio: unexpected number of irqs %u", - vdev->num_irqs); + error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)", + irq, vdev->num_irqs); return; } @@ -469,7 +469,7 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, if (vfio_set_irq_signaling(&vcdev->vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { - error_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); + warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); } qemu_set_fd_handler(event_notifier_get_fd(notifier), @@ -689,20 +689,24 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) if (vcdev->crw_region) { vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err); if (err) { - goto out_crw_notifier_err; + goto out_irq_notifier_err; } } vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX, &err); if (err) { - goto out_req_notifier_err; + /* + * Report this error, but do not make it a failing condition. + * Lack of this IRQ in the host does not prevent normal operation. + */ + error_report_err(err); } return; -out_req_notifier_err: +out_irq_notifier_err: + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); -out_crw_notifier_err: vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); out_io_notifier_err: vfio_ccw_put_region(vcdev); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 7f40a158f4..bbf817af46 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -582,6 +582,12 @@ typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm, void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); +target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong shift); +target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong flags, target_ulong shift); +bool is_ram_address(SpaprMachineState *spapr, hwaddr addr); +void push_sregs_to_kvm_pr(SpaprMachineState *spapr); /* Virtual Processor Area structure constants */ #define VPA_MIN_SIZE 640 @@ -821,6 +827,7 @@ void spapr_dt_events(SpaprMachineState *sm, void *fdt); void close_htab_fd(SpaprMachineState *spapr); void spapr_setup_hpt(SpaprMachineState *spapr); void spapr_free_hpt(SpaprMachineState *spapr); +void spapr_check_mmu_mode(bool guest_radix); SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn); void spapr_tce_table_enable(SpaprTceTable *tcet, uint32_t page_shift, uint64_t bus_offset, diff --git a/include/hw/tricore/tricore_testdevice.h b/include/hw/tricore/tricore_testdevice.h new file mode 100644 index 0000000000..2c56c51bcb --- /dev/null +++ b/include/hw/tricore/tricore_testdevice.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2021 Bastian Koppelmann Paderborn University + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef HW_TRICORE_TESTDEV_H +#define HW_TRICORE_TESTDEV_H + +#include "hw/sysbus.h" +#include "hw/hw.h" + +#define TYPE_TRICORE_TESTDEVICE "tricore_testdevice" +#define TRICORE_TESTDEVICE(obj) \ + OBJECT_CHECK(TriCoreTestDeviceState, (obj), TYPE_TRICORE_TESTDEVICE) + +typedef struct { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion iomem; + +} TriCoreTestDeviceState; + +#endif diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index 4a0f6c8dc2..fa91ea0eed 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -423,12 +423,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(cs, "Maintenance exception while in user mode. " "Aborting\n"); break; - case POWERPC_EXCP_STOP: /* stop translation */ - /* We did invalidate the instruction cache. Go on */ - break; - case POWERPC_EXCP_BRANCH: /* branch instruction: */ - /* We just stopped because of a branch. Go on */ - break; case POWERPC_EXCP_SYSCALL_USER: /* system call in user-mode emulation */ /* WARNING: diff --git a/target/arm/translate.c b/target/arm/translate.c index 455352bcf6..8e0e55c1e0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8981,6 +8981,7 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) unsigned int insn; if (arm_pre_translate_insn(dc)) { + dc->base.pc_next += 4; return; } @@ -9050,6 +9051,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) bool is_16bit; if (arm_pre_translate_insn(dc)) { + dc->base.pc_next += 2; return; } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 324ef92beb..e6836393f7 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2146,8 +2146,16 @@ static inline void cpu_set_fpuc(CPUX86State *env, uint16_t fpuc) void helper_lock_init(void); /* svm_helper.c */ +#ifdef CONFIG_USER_ONLY +static inline void +cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type, + uint64_t param, uintptr_t retaddr) +{ /* no-op */ } +#else void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type, uint64_t param, uintptr_t retaddr); +#endif + /* apic.c */ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, diff --git a/target/i386/helper.h b/target/i386/helper.h index 095520f81f..f3d8c3f949 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -42,9 +42,6 @@ DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl) DEF_HELPER_2(iret_real, void, env, int) DEF_HELPER_3(iret_protected, void, env, int, int) DEF_HELPER_3(lret_protected, void, env, int, int) -DEF_HELPER_2(read_crN, tl, env, int) -DEF_HELPER_3(write_crN, void, env, int, tl) -DEF_HELPER_2(lmsw, void, env, tl) DEF_HELPER_1(clts, void, env) #ifndef CONFIG_USER_ONLY @@ -52,7 +49,6 @@ DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl) #endif /* !CONFIG_USER_ONLY */ DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int) -DEF_HELPER_2(invlpg, void, env, tl) DEF_HELPER_1(sysenter, void, env) DEF_HELPER_2(sysexit, void, env, int) @@ -60,14 +56,11 @@ DEF_HELPER_2(sysexit, void, env, int) DEF_HELPER_2(syscall, void, env, int) DEF_HELPER_2(sysret, void, env, int) #endif -DEF_HELPER_2(hlt, void, env, int) -DEF_HELPER_2(monitor, void, env, tl) -DEF_HELPER_2(mwait, void, env, int) -DEF_HELPER_2(pause, void, env, int) -DEF_HELPER_1(debug, void, env) +DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int) +DEF_HELPER_FLAGS_1(debug, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_1(reset_rf, void, env) -DEF_HELPER_3(raise_interrupt, void, env, int, int) -DEF_HELPER_2(raise_exception, void, env, int) +DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int) +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int) DEF_HELPER_1(cli, void, env) DEF_HELPER_1(sti, void, env) DEF_HELPER_1(clac, void, env) @@ -86,30 +79,23 @@ DEF_HELPER_2(cmpxchg8b, void, env, tl) DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl) DEF_HELPER_2(cmpxchg16b, void, env, tl) #endif -DEF_HELPER_1(single_step, void, env) +DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_1(rechecking_single_step, void, env) DEF_HELPER_1(cpuid, void, env) DEF_HELPER_1(rdtsc, void, env) DEF_HELPER_1(rdtscp, void, env) -DEF_HELPER_1(rdpmc, void, env) -DEF_HELPER_1(rdmsr, void, env) -DEF_HELPER_1(wrmsr, void, env) +DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env) -DEF_HELPER_2(check_iob, void, env, i32) -DEF_HELPER_2(check_iow, void, env, i32) -DEF_HELPER_2(check_iol, void, env, i32) +#ifndef CONFIG_USER_ONLY DEF_HELPER_3(outb, void, env, i32, i32) DEF_HELPER_2(inb, tl, env, i32) DEF_HELPER_3(outw, void, env, i32, i32) DEF_HELPER_2(inw, tl, env, i32) DEF_HELPER_3(outl, void, env, i32, i32) DEF_HELPER_2(inl, tl, env, i32) - -#ifndef CONFIG_USER_ONLY +DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32) DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl) -#endif /* !CONFIG_USER_ONLY */ - -DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64) +DEF_HELPER_2(svm_check_intercept, void, env, i32) DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32) DEF_HELPER_3(vmrun, void, env, int, int) DEF_HELPER_1(vmmcall, void, env) @@ -117,8 +103,15 @@ DEF_HELPER_2(vmload, void, env, int) DEF_HELPER_2(vmsave, void, env, int) DEF_HELPER_1(stgi, void, env) DEF_HELPER_1(clgi, void, env) -DEF_HELPER_1(skinit, void, env) -DEF_HELPER_2(invlpga, void, env, int) +DEF_HELPER_FLAGS_2(flush_page, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int) +DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl) +DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int) +DEF_HELPER_1(rdmsr, void, env) +DEF_HELPER_1(wrmsr, void, env) +DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int) +DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl) +#endif /* !CONFIG_USER_ONLY */ /* x86 FPU */ diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c index fb2a65ac9c..83cd89581e 100644 --- a/target/i386/tcg/bpt_helper.c +++ b/target/i386/tcg/bpt_helper.c @@ -22,7 +22,7 @@ #include "exec/helper-proto.h" #include "helper-tcg.h" -void helper_single_step(CPUX86State *env) +void QEMU_NORETURN helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY check_hw_breakpoints(env, true); diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index 0183f3932e..bdae887d0a 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -25,12 +25,13 @@ #include "exec/helper-proto.h" #include "helper-tcg.h" -void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend) +void QEMU_NORETURN helper_raise_interrupt(CPUX86State *env, int intno, + int next_eip_addend) { raise_interrupt(env, intno, 1, 0, next_eip_addend); } -void helper_raise_exception(CPUX86State *env, int exception_index) +void QEMU_NORETURN helper_raise_exception(CPUX86State *env, int exception_index) { raise_exception(env, exception_index); } @@ -116,24 +117,25 @@ void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int, raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0); } -void raise_exception_err(CPUX86State *env, int exception_index, - int error_code) +void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index, + int error_code) { raise_interrupt2(env, exception_index, 0, error_code, 0, 0); } -void raise_exception_err_ra(CPUX86State *env, int exception_index, - int error_code, uintptr_t retaddr) +void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index, + int error_code, uintptr_t retaddr) { raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr); } -void raise_exception(CPUX86State *env, int exception_index) +void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index) { raise_interrupt2(env, exception_index, 0, 0, 0, 0); } -void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t retaddr) +void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index, + uintptr_t retaddr) { raise_interrupt2(env, exception_index, 0, 0, 0, retaddr); } diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 97fb7a226a..2510cc244e 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -76,11 +76,14 @@ extern const uint8_t parity_table[256]; /* misc_helper.c */ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask); +void do_pause(CPUX86State *env) QEMU_NORETURN; -/* svm_helper.c */ +/* sysemu/svm_helper.c */ +#ifndef CONFIG_USER_ONLY void QEMU_NORETURN cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, uintptr_t retaddr); void do_vmexit(CPUX86State *env); +#endif /* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index a30379283e..baffa5d7ba 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -60,22 +60,6 @@ void helper_cpuid(CPUX86State *env) env->regs[R_EDX] = edx; } -void helper_lmsw(CPUX86State *env, target_ulong t0) -{ - /* only 4 lower bits of CR0 are modified. PE cannot be set to zero - if already set to one. */ - t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); - helper_write_crN(env, 0, t0); -} - -void helper_invlpg(CPUX86State *env, target_ulong addr) -{ - X86CPU *cpu = env_archcpu(env); - - cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC()); - tlb_flush_page(CPU(cpu), addr); -} - void helper_rdtsc(CPUX86State *env) { uint64_t val; @@ -96,7 +80,7 @@ void helper_rdtscp(CPUX86State *env) env->regs[R_ECX] = (uint32_t)(env->tsc_aux); } -void helper_rdpmc(CPUX86State *env) +void QEMU_NORETURN helper_rdpmc(CPUX86State *env) { if (((env->cr[4] & CR4_PCE_MASK) == 0 ) && ((env->hflags & HF_CPL_MASK) != 0)) { @@ -109,75 +93,24 @@ void helper_rdpmc(CPUX86State *env) raise_exception_err(env, EXCP06_ILLOP, 0); } -static void do_pause(X86CPU *cpu) +void QEMU_NORETURN do_pause(CPUX86State *env) { - CPUState *cs = CPU(cpu); + CPUState *cs = env_cpu(env); /* Just let another CPU run. */ cs->exception_index = EXCP_INTERRUPT; cpu_loop_exit(cs); } -static void do_hlt(X86CPU *cpu) -{ - CPUState *cs = CPU(cpu); - CPUX86State *env = &cpu->env; - - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - cs->halted = 1; - cs->exception_index = EXCP_HLT; - cpu_loop_exit(cs); -} - -void helper_hlt(CPUX86State *env, int next_eip_addend) +void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend) { - X86CPU *cpu = env_archcpu(env); - - cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC()); - env->eip += next_eip_addend; - - do_hlt(cpu); -} - -void helper_monitor(CPUX86State *env, target_ulong ptr) -{ - if ((uint32_t)env->regs[R_ECX] != 0) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } - /* XXX: store address? */ - cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC()); -} - -void helper_mwait(CPUX86State *env, int next_eip_addend) -{ - CPUState *cs = env_cpu(env); - X86CPU *cpu = env_archcpu(env); - - if ((uint32_t)env->regs[R_ECX] != 0) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } - cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC()); - env->eip += next_eip_addend; - - /* XXX: not complete but not completely erroneous */ - if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) { - do_pause(cpu); - } else { - do_hlt(cpu); - } -} - -void helper_pause(CPUX86State *env, int next_eip_addend) -{ - X86CPU *cpu = env_archcpu(env); - cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC()); env->eip += next_eip_addend; - do_pause(cpu); + do_pause(env); } -void helper_debug(CPUX86State *env) +void QEMU_NORETURN helper_debug(CPUX86State *env) { CPUState *cs = env_cpu(env); diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index cf3f051524..2f6cdc8239 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -2416,46 +2416,3 @@ void helper_verw(CPUX86State *env, target_ulong selector1) } CC_SRC = eflags | CC_Z; } - -/* check if Port I/O is allowed in TSS */ -static inline void check_io(CPUX86State *env, int addr, int size, - uintptr_t retaddr) -{ - int io_offset, val, mask; - - /* TSS must be a valid 32 bit one */ - if (!(env->tr.flags & DESC_P_MASK) || - ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || - env->tr.limit < 103) { - goto fail; - } - io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr); - io_offset += (addr >> 3); - /* Note: the check needs two bytes */ - if ((io_offset + 1) > env->tr.limit) { - goto fail; - } - val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr); - val >>= (addr & 7); - mask = (1 << size) - 1; - /* all bits must be zero to allow the I/O */ - if ((val & mask) != 0) { - fail: - raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr); - } -} - -void helper_check_iob(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 1, GETPC()); -} - -void helper_check_iow(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 2, GETPC()); -} - -void helper_check_iol(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 4, GETPC()); -} diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index 66e7939537..0cef2f1a4c 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -65,7 +65,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) { target_ulong val; - cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); switch (reg) { default: val = env->cr[reg]; @@ -83,7 +82,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg) void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) { - cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); switch (reg) { case 0: cpu_x86_update_cr0(env, t0); @@ -440,3 +438,53 @@ void helper_rdmsr(CPUX86State *env) env->regs[R_EAX] = (uint32_t)(val); env->regs[R_EDX] = (uint32_t)(val >> 32); } + +void helper_flush_page(CPUX86State *env, target_ulong addr) +{ + tlb_flush_page(env_cpu(env), addr); +} + +static void QEMU_NORETURN do_hlt(CPUX86State *env) +{ + CPUState *cs = env_cpu(env); + + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + cs->halted = 1; + cs->exception_index = EXCP_HLT; + cpu_loop_exit(cs); +} + +void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend) +{ + cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC()); + env->eip += next_eip_addend; + + do_hlt(env); +} + +void helper_monitor(CPUX86State *env, target_ulong ptr) +{ + if ((uint32_t)env->regs[R_ECX] != 0) { + raise_exception_ra(env, EXCP0D_GPF, GETPC()); + } + /* XXX: store address? */ + cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC()); +} + +void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend) +{ + CPUState *cs = env_cpu(env); + + if ((uint32_t)env->regs[R_ECX] != 0) { + raise_exception_ra(env, EXCP0D_GPF, GETPC()); + } + cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC()); + env->eip += next_eip_addend; + + /* XXX: not complete but not completely erroneous */ + if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) { + do_pause(env); + } else { + do_hlt(env); + } +} diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index e0d7b32b82..82c0856c41 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -23,6 +23,7 @@ #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #include "tcg/helper-tcg.h" +#include "../seg_helper.h" #ifdef TARGET_X86_64 void helper_syscall(CPUX86State *env, int next_eip_addend) @@ -123,3 +124,31 @@ void x86_cpu_do_interrupt(CPUState *cs) env->old_exception = -1; } } + +/* check if Port I/O is allowed in TSS */ +void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size) +{ + uintptr_t retaddr = GETPC(); + uint32_t io_offset, val, mask; + + /* TSS must be a valid 32 bit one */ + if (!(env->tr.flags & DESC_P_MASK) || + ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || + env->tr.limit < 103) { + goto fail; + } + io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr); + io_offset += (addr >> 3); + /* Note: the check needs two bytes */ + if ((io_offset + 1) > env->tr.limit) { + goto fail; + } + val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr); + val >>= (addr & 7); + mask = (1 << size) - 1; + /* all bits must be zero to allow the I/O */ + if ((val & mask) != 0) { + fail: + raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr); + } +} diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index c4e8e717a9..9d671297cf 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -412,31 +412,6 @@ void helper_clgi(CPUX86State *env) env->hflags2 &= ~HF2_GIF_MASK; } -void helper_skinit(CPUX86State *env) -{ - cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0, GETPC()); - /* XXX: not implemented */ - raise_exception(env, EXCP06_ILLOP); -} - -void helper_invlpga(CPUX86State *env, int aflag) -{ - X86CPU *cpu = env_archcpu(env); - target_ulong addr; - - cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0, GETPC()); - - if (aflag == 2) { - addr = env->regs[R_EAX]; - } else { - addr = (uint32_t)env->regs[R_EAX]; - } - - /* XXX: could use the ASID to see if it is needed to do the - flush */ - tlb_flush_page(CPU(cpu), addr); -} - void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, uint64_t param, uintptr_t retaddr) { @@ -513,10 +488,9 @@ void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, } } -void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) +void helper_svm_check_intercept(CPUX86State *env, uint32_t type) { - cpu_svm_check_intercept_param(env, type, param, GETPC()); + cpu_svm_check_intercept_param(env, type, 0, GETPC()); } void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index db56a48343..834186bcae 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -39,16 +39,7 @@ #define PREFIX_DATA 0x08 #define PREFIX_ADR 0x10 #define PREFIX_VEX 0x20 - -#ifdef TARGET_X86_64 -#define CODE64(s) ((s)->code64) -#define REX_X(s) ((s)->rex_x) -#define REX_B(s) ((s)->rex_b) -#else -#define CODE64(s) 0 -#define REX_X(s) 0 -#define REX_B(s) 0 -#endif +#define PREFIX_REX 0x40 #ifdef TARGET_X86_64 # define ctztl ctz64 @@ -85,42 +76,38 @@ static TCGv_i64 cpu_bndu[4]; typedef struct DisasContext { DisasContextBase base; - /* current insn context */ - int override; /* -1 if no override */ - int prefix; + target_ulong pc; /* pc = eip + cs_base */ + target_ulong pc_start; /* pc at TB entry */ + target_ulong cs_base; /* base of CS segment */ + MemOp aflag; MemOp dflag; - target_ulong pc_start; - target_ulong pc; /* pc = eip + cs_base */ - /* current block context */ - target_ulong cs_base; /* base of CS segment */ - int pe; /* protected mode */ - int code32; /* 32 bit code segment */ -#ifdef TARGET_X86_64 - int lma; /* long mode active */ - int code64; /* 64 bit code segment */ - int rex_x, rex_b; + + int8_t override; /* -1 if no override, else R_CS, R_DS, etc */ + uint8_t prefix; + +#ifndef CONFIG_USER_ONLY + uint8_t cpl; /* code priv level */ + uint8_t iopl; /* i/o priv level */ #endif - int vex_l; /* vex vector length */ - int vex_v; /* vex vvvv register, without 1's complement. */ - int ss32; /* 32 bit stack segment */ - CCOp cc_op; /* current CC operation */ - bool cc_op_dirty; + uint8_t vex_l; /* vex vector length */ + uint8_t vex_v; /* vex vvvv register, without 1's complement. */ + uint8_t popl_esp_hack; /* for correct popl with esp base handling */ + uint8_t rip_offset; /* only used in x86_64, but left for simplicity */ + #ifdef TARGET_X86_64 - bool x86_64_hregs; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + bool rex_w; #endif - int addseg; /* non zero if either DS/ES/SS have a non zero base */ - int f_st; /* currently unused */ - int vm86; /* vm86 mode */ - int cpl; - int iopl; - int tf; /* TF cpu flag */ - int jmp_opt; /* use direct block chaining for direct jumps */ - int repz_opt; /* optimize jumps within repz instructions */ + bool jmp_opt; /* use direct block chaining for direct jumps */ + bool repz_opt; /* optimize jumps within repz instructions */ + bool cc_op_dirty; + + CCOp cc_op; /* current CC operation */ int mem_index; /* select memory access functions */ - uint64_t flags; /* all execution flags */ - int popl_esp_hack; /* for correct popl with esp base handling */ - int rip_offset; /* only used in x86_64, but left for simplicity */ + uint32_t flags; /* all execution flags */ int cpuid_features; int cpuid_ext_features; int cpuid_ext2_features; @@ -146,11 +133,96 @@ typedef struct DisasContext { sigjmp_buf jmpbuf; } DisasContext; +/* The environment in which user-only runs is constrained. */ +#ifdef CONFIG_USER_ONLY +#define PE(S) true +#define CPL(S) 3 +#define IOPL(S) 0 +#define SVME(S) false +#define GUEST(S) false +#else +#define PE(S) (((S)->flags & HF_PE_MASK) != 0) +#define CPL(S) ((S)->cpl) +#define IOPL(S) ((S)->iopl) +#define SVME(S) (((S)->flags & HF_SVME_MASK) != 0) +#define GUEST(S) (((S)->flags & HF_GUEST_MASK) != 0) +#endif +#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64) +#define VM86(S) false +#define CODE32(S) true +#define SS32(S) true +#define ADDSEG(S) false +#else +#define VM86(S) (((S)->flags & HF_VM_MASK) != 0) +#define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0) +#define SS32(S) (((S)->flags & HF_SS32_MASK) != 0) +#define ADDSEG(S) (((S)->flags & HF_ADDSEG_MASK) != 0) +#endif +#if !defined(TARGET_X86_64) +#define CODE64(S) false +#define LMA(S) false +#elif defined(CONFIG_USER_ONLY) +#define CODE64(S) true +#define LMA(S) true +#else +#define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0) +#define LMA(S) (((S)->flags & HF_LMA_MASK) != 0) +#endif + +#ifdef TARGET_X86_64 +#define REX_PREFIX(S) (((S)->prefix & PREFIX_REX) != 0) +#define REX_W(S) ((S)->rex_w) +#define REX_R(S) ((S)->rex_r + 0) +#define REX_X(S) ((S)->rex_x + 0) +#define REX_B(S) ((S)->rex_b + 0) +#else +#define REX_PREFIX(S) false +#define REX_W(S) false +#define REX_R(S) 0 +#define REX_X(S) 0 +#define REX_B(S) 0 +#endif + +/* + * Many sysemu-only helpers are not reachable for user-only. + * Define stub generators here, so that we need not either sprinkle + * ifdefs through the translator, nor provide the helper function. + */ +#define STUB_HELPER(NAME, ...) \ + static inline void gen_helper_##NAME(__VA_ARGS__) \ + { qemu_build_not_reached(); } + +#ifdef CONFIG_USER_ONLY +STUB_HELPER(clgi, TCGv_env env) +STUB_HELPER(flush_page, TCGv_env env, TCGv addr) +STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs) +STUB_HELPER(inb, TCGv ret, TCGv_env env, TCGv_i32 port) +STUB_HELPER(inw, TCGv ret, TCGv_env env, TCGv_i32 port) +STUB_HELPER(inl, TCGv ret, TCGv_env env, TCGv_i32 port) +STUB_HELPER(monitor, TCGv_env env, TCGv addr) +STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs) +STUB_HELPER(outb, TCGv_env env, TCGv_i32 port, TCGv_i32 val) +STUB_HELPER(outw, TCGv_env env, TCGv_i32 port, TCGv_i32 val) +STUB_HELPER(outl, TCGv_env env, TCGv_i32 port, TCGv_i32 val) +STUB_HELPER(rdmsr, TCGv_env env) +STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg) +STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val) +STUB_HELPER(stgi, TCGv_env env) +STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type) +STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag) +STUB_HELPER(vmmcall, TCGv_env env) +STUB_HELPER(vmrun, TCGv_env env, TCGv_i32 aflag, TCGv_i32 pc_ofs) +STUB_HELPER(vmsave, TCGv_env env, TCGv_i32 aflag) +STUB_HELPER(write_crN, TCGv_env env, TCGv_i32 reg, TCGv val) +STUB_HELPER(wrmsr, TCGv_env env) +#endif + static void gen_eob(DisasContext *s); static void gen_jr(DisasContext *s, TCGv dest); static void gen_jmp(DisasContext *s, target_ulong eip); static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); static void gen_op(DisasContext *s1, int op, MemOp ot, int d); +static void gen_exception_gpf(DisasContext *s); /* i386 arith/logic operations */ enum { @@ -309,14 +381,10 @@ static void gen_update_cc_op(DisasContext *s) */ static inline bool byte_reg_is_xH(DisasContext *s, int reg) { - if (reg < 4) { + /* Any time the REX prefix is present, byte registers are uniform */ + if (reg < 4 || REX_PREFIX(s)) { return false; } -#ifdef TARGET_X86_64 - if (reg >= 8 || s->x86_64_hregs) { - return false; - } -#endif return true; } @@ -333,7 +401,7 @@ static inline MemOp mo_pushpop(DisasContext *s, MemOp ot) /* Select the size of the stack pointer. */ static inline MemOp mo_stacksize(DisasContext *s) { - return CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16; + return CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16; } /* Select only size 64 else 32. Used for SSE operand sizes. */ @@ -466,7 +534,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0, #endif case MO_32: /* 32 bit address */ - if (ovr_seg < 0 && s->addseg) { + if (ovr_seg < 0 && ADDSEG(s)) { ovr_seg = def_seg; } if (ovr_seg < 0) { @@ -479,7 +547,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0, tcg_gen_ext16u_tl(s->A0, a0); a0 = s->A0; if (ovr_seg < 0) { - if (s->addseg) { + if (ADDSEG(s)) { ovr_seg = def_seg; } else { return; @@ -612,37 +680,40 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n) } } -static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip, +/* + * Validate that access to [port, port + 1<<ot) is allowed. + * Raise #GP, or VMM exit if not. + */ +static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port, uint32_t svm_flags) { - target_ulong next_eip; - - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - switch (ot) { - case MO_8: - gen_helper_check_iob(cpu_env, s->tmp2_i32); - break; - case MO_16: - gen_helper_check_iow(cpu_env, s->tmp2_i32); - break; - case MO_32: - gen_helper_check_iol(cpu_env, s->tmp2_i32); - break; - default: - tcg_abort(); - } +#ifdef CONFIG_USER_ONLY + /* + * We do not implement the ioperm(2) syscall, so the TSS check + * will always fail. + */ + gen_exception_gpf(s); + return false; +#else + if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) { + gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot)); } - if(s->flags & HF_GUEST_MASK) { + if (GUEST(s)) { + target_ulong cur_eip = s->base.pc_next - s->cs_base; + target_ulong next_eip = s->pc - s->cs_base; + gen_update_cc_op(s); gen_jmp_im(s, cur_eip); - svm_flags |= (1 << (4 + ot)); - next_eip = s->pc - s->cs_base; - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_svm_check_io(cpu_env, s->tmp2_i32, - tcg_const_i32(svm_flags), - tcg_const_i32(next_eip - cur_eip)); + if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) { + svm_flags |= SVM_IOIO_REP_MASK; + } + svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot); + gen_helper_svm_check_io(cpu_env, port, + tcg_constant_i32(svm_flags), + tcg_constant_i32(next_eip - cur_eip)); } + return true; +#endif } static inline void gen_movs(DisasContext *s, MemOp ot) @@ -1276,6 +1347,42 @@ static void gen_illegal_opcode(DisasContext *s) gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base); } +/* Generate #GP for the current instruction. */ +static void gen_exception_gpf(DisasContext *s) +{ + gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base); +} + +/* Check for cpl == 0; if not, raise #GP and return false. */ +static bool check_cpl0(DisasContext *s) +{ + if (CPL(s) == 0) { + return true; + } + gen_exception_gpf(s); + return false; +} + +/* If vm86, check for iopl == 3; if not, raise #GP and return false. */ +static bool check_vm86_iopl(DisasContext *s) +{ + if (!VM86(s) || IOPL(s) == 3) { + return true; + } + gen_exception_gpf(s); + return false; +} + +/* Check for iopl allowing access; if not, raise #GP and return false. */ +static bool check_iopl(DisasContext *s) +{ + if (VM86(s) ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) { + return true; + } + gen_exception_gpf(s); + return false; +} + /* if d == OR_TMP0, it means memory operand (address in A0) */ static void gen_op(DisasContext *s1, int op, MemOp ot, int d) { @@ -2309,14 +2416,14 @@ static inline void gen_op_movl_seg_T0_vm(DisasContext *s, X86Seg seg_reg) call this function with seg_reg == R_CS */ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg) { - if (s->pe && !s->vm86) { + if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), s->tmp2_i32); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware interrupts for the next instruction */ - if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) { + if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) { s->base.is_jmp = DISAS_TOO_MANY; } } else { @@ -2327,28 +2434,13 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg) } } -static inline int svm_is_rep(int prefixes) -{ - return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); -} - -static inline void -gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, - uint32_t type, uint64_t param) +static void gen_svm_check_intercept(DisasContext *s, uint32_t type) { /* no SVM activated; fast case */ - if (likely(!(s->flags & HF_GUEST_MASK))) + if (likely(!GUEST(s))) { return; - gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type), - tcg_const_i64(param)); -} - -static inline void -gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type) -{ - gen_svm_check_intercept_param(s, pc_start, type, 0); + } + gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type)); } static inline void gen_stack_update(DisasContext *s, int addend) @@ -2367,7 +2459,7 @@ static void gen_push_v(DisasContext *s, TCGv val) tcg_gen_subi_tl(s->A0, cpu_regs[R_ESP], size); if (!CODE64(s)) { - if (s->addseg) { + if (ADDSEG(s)) { new_esp = s->tmp4; tcg_gen_mov_tl(new_esp, s->A0); } @@ -2396,12 +2488,12 @@ static inline void gen_pop_update(DisasContext *s, MemOp ot) static inline void gen_stack_A0(DisasContext *s) { - gen_lea_v_seg(s, s->ss32 ? MO_32 : MO_16, cpu_regs[R_ESP], R_SS, -1); + gen_lea_v_seg(s, SS32(s) ? MO_32 : MO_16, cpu_regs[R_ESP], R_SS, -1); } static void gen_pusha(DisasContext *s) { - MemOp s_ot = s->ss32 ? MO_32 : MO_16; + MemOp s_ot = SS32(s) ? MO_32 : MO_16; MemOp d_ot = s->dflag; int size = 1 << d_ot; int i; @@ -2417,7 +2509,7 @@ static void gen_pusha(DisasContext *s) static void gen_popa(DisasContext *s) { - MemOp s_ot = s->ss32 ? MO_32 : MO_16; + MemOp s_ot = SS32(s) ? MO_32 : MO_16; MemOp d_ot = s->dflag; int size = 1 << d_ot; int i; @@ -2439,7 +2531,7 @@ static void gen_popa(DisasContext *s) static void gen_enter(DisasContext *s, int esp_addend, int level) { MemOp d_ot = mo_pushpop(s, s->dflag); - MemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16; + MemOp a_ot = CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16; int size = 1 << d_ot; /* Push BP; compute FrameTemp into T1. */ @@ -2522,10 +2614,10 @@ static void gen_interrupt(DisasContext *s, int intno, s->base.is_jmp = DISAS_NORETURN; } -static void gen_debug(DisasContext *s, target_ulong cur_eip) +static void gen_debug(DisasContext *s) { gen_update_cc_op(s); - gen_jmp_im(s, cur_eip); + gen_jmp_im(s, s->base.pc_next - s->cs_base); gen_helper_debug(cpu_env); s->base.is_jmp = DISAS_NORETURN; } @@ -2591,7 +2683,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr) } else if (recheck_tf) { gen_helper_rechecking_single_step(cpu_env); tcg_gen_exit_tb(NULL, 0); - } else if (s->tf) { + } else if (s->flags & HF_TF_MASK) { gen_helper_single_step(cpu_env); } else if (jr) { tcg_gen_lookup_and_goto_ptr(); @@ -3034,7 +3126,7 @@ static const struct SSEOpHelper_eppi sse_op_table7[256] = { }; static void gen_sse(CPUX86State *env, DisasContext *s, int b, - target_ulong pc_start, int rex_r) + target_ulong pc_start) { int b1, op1_offset, op2_offset, is_xmm, val; int modrm, mod, rm, reg; @@ -3104,8 +3196,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, modrm = x86_ldub_code(env, s); reg = ((modrm >> 3) & 7); - if (is_xmm) - reg |= rex_r; + if (is_xmm) { + reg |= REX_R(s); + } mod = (modrm >> 6) & 3; if (sse_fn_epp == SSE_SPECIAL) { b |= (b1 << 8); @@ -3639,7 +3732,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_ld16u_tl(s->T0, cpu_env, offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val))); } - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_op_mov_reg_v(s, ot, reg, s->T0); break; case 0x1d6: /* movq ea, xmm */ @@ -3683,7 +3776,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, offsetof(CPUX86State, fpregs[rm].mmx)); gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, s->ptr0); } - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32); break; @@ -3695,7 +3788,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } modrm = x86_ldub_code(env, s); rm = modrm & 7; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; if (b1 >= 2) { goto unknown_op; @@ -3771,7 +3864,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, /* Various integer extensions at 0f 38 f[0-f]. */ b = modrm | (b1 << 8); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); switch (b) { case 0x3f0: /* crc32 Gd,Eb */ @@ -4125,7 +4218,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, b = modrm; modrm = x86_ldub_code(env, s); rm = modrm & 7; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; if (b1 >= 2) { goto unknown_op; @@ -4145,7 +4238,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, rm = (modrm & 7) | REX_B(s); if (mod != 3) gen_lea_modrm(env, s, modrm); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); val = x86_ldub_code(env, s); switch (b) { case 0x14: /* pextrb */ @@ -4314,7 +4407,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, /* Various integer extensions at 0f 3a f[0-f]. */ b = modrm | (b1 << 8); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); switch (b) { case 0x3f0: /* rorx Gy,Ey, Ib */ @@ -4488,27 +4581,25 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) MemOp ot, aflag, dflag; int modrm, reg, rm, mod, op, opreg, val; target_ulong next_eip, tval; - int rex_w, rex_r; target_ulong pc_start = s->base.pc_next; s->pc_start = s->pc = pc_start; s->override = -1; #ifdef TARGET_X86_64 + s->rex_w = false; + s->rex_r = 0; s->rex_x = 0; s->rex_b = 0; - s->x86_64_hregs = false; #endif s->rip_offset = 0; /* for relative ip address */ s->vex_l = 0; s->vex_v = 0; if (sigsetjmp(s->jmpbuf, 0) != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + gen_exception_gpf(s); return s->pc; } prefixes = 0; - rex_w = -1; - rex_r = 0; next_byte: b = x86_ldub_code(env, s); @@ -4551,12 +4642,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x40 ... 0x4f: if (CODE64(s)) { /* REX prefix */ - rex_w = (b >> 3) & 1; - rex_r = (b & 0x4) << 1; + prefixes |= PREFIX_REX; + s->rex_w = (b >> 3) & 1; + s->rex_r = (b & 0x4) << 1; s->rex_x = (b & 0x2) << 2; - REX_B(s) = (b & 0x1) << 3; - /* select uniform byte register addressing */ - s->x86_64_hregs = true; + s->rex_b = (b & 0x1) << 3; goto next_byte; } break; @@ -4565,7 +4655,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xc4: /* 3-byte VEX */ /* VEX prefixes cannot be used except in 32-bit mode. Otherwise the instruction is LES or LDS. */ - if (s->code32 && !s->vm86) { + if (CODE32(s) && !VM86(s)) { static const int pp_prefix[4] = { 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ }; @@ -4580,27 +4670,24 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ - | PREFIX_LOCK | PREFIX_DATA)) { + | PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) { goto illegal_op; } #ifdef TARGET_X86_64 - if (s->x86_64_hregs) { - goto illegal_op; - } + s->rex_r = (~vex2 >> 4) & 8; #endif - rex_r = (~vex2 >> 4) & 8; if (b == 0xc5) { /* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */ vex3 = vex2; b = x86_ldub_code(env, s) | 0x100; } else { /* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */ + vex3 = x86_ldub_code(env, s); #ifdef TARGET_X86_64 s->rex_x = (~vex2 >> 3) & 8; s->rex_b = (~vex2 >> 2) & 8; + s->rex_w = (vex3 >> 7) & 1; #endif - vex3 = x86_ldub_code(env, s); - rex_w = (vex3 >> 7) & 1; switch (vex2 & 0x1f) { case 0x01: /* Implied 0f leading opcode bytes. */ b = x86_ldub_code(env, s) | 0x100; @@ -4627,18 +4714,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* In 64-bit mode, the default data size is 32-bit. Select 64-bit data with rex_w, and 16-bit data with 0x66; rex_w takes precedence over 0x66 if both are present. */ - dflag = (rex_w > 0 ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32); + dflag = (REX_W(s) ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32); /* In 64-bit mode, 0x67 selects 32-bit addressing. */ aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64); } else { /* In 16/32-bit mode, 0x66 selects the opposite data size. */ - if (s->code32 ^ ((prefixes & PREFIX_DATA) != 0)) { + if (CODE32(s) ^ ((prefixes & PREFIX_DATA) != 0)) { dflag = MO_32; } else { dflag = MO_16; } /* In 16/32-bit mode, 0x67 selects the opposite addressing. */ - if (s->code32 ^ ((prefixes & PREFIX_ADR) != 0)) { + if (CODE32(s) ^ ((prefixes & PREFIX_ADR) != 0)) { aflag = MO_32; } else { aflag = MO_16; @@ -4678,7 +4765,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) switch(f) { case 0: /* OP Ev, Gv */ modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { @@ -4700,7 +4787,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 1: /* OP Gv, Ev */ modrm = x86_ldub_code(env, s); mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(env, s, modrm); @@ -5023,7 +5110,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* operand size for jumps is 64 bit */ ot = MO_64; } else if (op == 3 || op == 5) { - ot = dflag != MO_16 ? MO_32 + (rex_w == 1) : MO_16; + ot = dflag != MO_16 ? MO_32 + REX_W(s) : MO_16; } else if (op == 6) { /* default push size is 64 bit */ ot = mo_pushpop(s, dflag); @@ -5072,7 +5159,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); do_lcall: - if (s->pe && !s->vm86) { + if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1, tcg_const_i32(dflag - 1), @@ -5102,7 +5189,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); do_ljmp: - if (s->pe && !s->vm86) { + if (PE(s) && !VM86(s)) { tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1, tcg_const_tl(s->pc - s->cs_base)); @@ -5126,7 +5213,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); gen_op_mov_v_reg(s, ot, s->T1, reg); @@ -5198,7 +5285,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x6b: ot = dflag; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (b == 0x69) s->rip_offset = insn_const_size(ot); else if (b == 0x6b) @@ -5250,7 +5337,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1c1: /* xadd Ev, Gv */ ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; gen_op_mov_v_reg(s, ot, s->T0, reg); if (mod == 3) { @@ -5282,7 +5369,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; oldv = tcg_temp_new(); newv = tcg_temp_new(); @@ -5480,7 +5567,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (s->base.is_jmp) { gen_jmp_im(s, s->pc - s->cs_base); if (reg == R_SS) { - s->tf = 0; + s->flags &= ~HF_TF_MASK; gen_eob_inhibit_irq(s, true); } else { gen_eob(s); @@ -5504,7 +5591,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x89: /* mov Gv, Ev */ ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); /* generate a generic store */ gen_ldst_modrm(env, s, modrm, ot, reg, 1); @@ -5530,7 +5617,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x8b: /* mov Ev, Gv */ ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_v(s, ot, reg, s->T0); @@ -5546,7 +5633,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (s->base.is_jmp) { gen_jmp_im(s, s->pc - s->cs_base); if (reg == R_SS) { - s->tf = 0; + s->flags &= ~HF_TF_MASK; gen_eob_inhibit_irq(s, true); } else { gen_eob(s); @@ -5580,7 +5667,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) s_ot = b & 8 ? MO_SIGN | ot : ot; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); @@ -5619,7 +5706,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); { AddressParts a = gen_lea_modrm_0(env, s, modrm); TCGv ea = gen_lea_modrm_1(s, a); @@ -5701,7 +5788,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x87: /* xchg Ev, Gv */ ot = mo_b_d(b, dflag); modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; if (mod == 3) { rm = (modrm & 7) | REX_B(s); @@ -5738,7 +5825,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) do_lxx: ot = dflag != MO_16 ? MO_32 : MO_16; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; @@ -5821,7 +5908,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (mod != 3) { gen_lea_modrm(env, s, modrm); opreg = OR_TMP0; @@ -6399,9 +6486,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x6c: /* insS */ case 0x6d: ot = mo_b_d32(b, dflag); - tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); - gen_check_io(s, ot, pc_start - s->cs_base, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); + tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); + tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32); + if (!gen_check_io(s, ot, s->tmp2_i32, + SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } @@ -6418,9 +6508,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x6e: /* outsS */ case 0x6f: ot = mo_b_d32(b, dflag); - tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); - gen_check_io(s, ot, pc_start - s->cs_base, - svm_is_rep(prefixes) | 4); + tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); + tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32); + if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_STR_MASK)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } @@ -6442,13 +6534,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xe5: ot = mo_b_d32(b, dflag); val = x86_ldub_code(env, s); - tcg_gen_movi_tl(s->T0, val); - gen_check_io(s, ot, pc_start - s->cs_base, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + tcg_gen_movi_i32(s->tmp2_i32, val); + if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - tcg_gen_movi_i32(s->tmp2_i32, val); gen_helper_in_func(ot, s->T1, s->tmp2_i32); gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); @@ -6460,15 +6552,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xe7: ot = mo_b_d32(b, dflag); val = x86_ldub_code(env, s); - tcg_gen_movi_tl(s->T0, val); - gen_check_io(s, ot, pc_start - s->cs_base, - svm_is_rep(prefixes)); - gen_op_mov_v_reg(s, ot, s->T1, R_EAX); - + tcg_gen_movi_i32(s->tmp2_i32, val); + if (!gen_check_io(s, ot, s->tmp2_i32, 0)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - tcg_gen_movi_i32(s->tmp2_i32, val); + gen_op_mov_v_reg(s, ot, s->T1, R_EAX); tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); @@ -6479,13 +6570,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xec: case 0xed: ot = mo_b_d32(b, dflag); - tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); - gen_check_io(s, ot, pc_start - s->cs_base, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); + tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32); + if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_in_func(ot, s->T1, s->tmp2_i32); gen_op_mov_reg_v(s, ot, R_EAX, s->T1); gen_bpt_io(s, s->tmp2_i32, ot); @@ -6496,15 +6588,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xee: case 0xef: ot = mo_b_d32(b, dflag); - tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]); - gen_check_io(s, ot, pc_start - s->cs_base, - svm_is_rep(prefixes)); - gen_op_mov_v_reg(s, ot, s->T1, R_EAX); - + tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); + tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32); + if (!gen_check_io(s, ot, s->tmp2_i32, 0)) { + break; + } if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + gen_op_mov_v_reg(s, ot, s->T1, R_EAX); tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); gen_bpt_io(s, s->tmp2_i32, ot); @@ -6535,7 +6627,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xca: /* lret im */ val = x86_ldsw_code(env, s); do_lret: - if (s->pe && !s->vm86) { + if (PE(s) && !VM86(s)) { gen_update_cc_op(s); gen_jmp_im(s, pc_start - s->cs_base); gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1), @@ -6560,23 +6652,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) val = 0; goto do_lret; case 0xcf: /* iret */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET); - if (!s->pe) { - /* real mode */ - gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1)); - set_cc_op(s, CC_OP_EFLAGS); - } else if (s->vm86) { - if (s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1)); - set_cc_op(s, CC_OP_EFLAGS); + gen_svm_check_intercept(s, SVM_EXIT_IRET); + if (!PE(s) || VM86(s)) { + /* real mode or vm86 mode */ + if (!check_vm86_iopl(s)) { + break; } + gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1)); } else { gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1), tcg_const_i32(s->pc - s->cs_base)); - set_cc_op(s, CC_OP_EFLAGS); } + set_cc_op(s, CC_OP_EFLAGS); gen_eob(s); break; case 0xe8: /* call im */ @@ -6680,29 +6767,25 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } ot = dflag; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_cmovcc1(env, s, ot, b, modrm, reg); break; /************************/ /* flags */ case 0x9c: /* pushf */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF); - if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + gen_svm_check_intercept(s, SVM_EXIT_PUSHF); + if (check_vm86_iopl(s)) { gen_update_cc_op(s); gen_helper_read_eflags(s->T0, cpu_env); gen_push_v(s, s->T0); } break; case 0x9d: /* popf */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF); - if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + gen_svm_check_intercept(s, SVM_EXIT_POPF); + if (check_vm86_iopl(s)) { ot = gen_pop_T0(s); - if (s->cpl == 0) { + if (CPL(s) == 0) { if (dflag != MO_16) { gen_helper_write_eflags(cpu_env, s->T0, tcg_const_i32((TF_MASK | AC_MASK | @@ -6717,7 +6800,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) & 0xffff)); } } else { - if (s->cpl <= s->iopl) { + if (CPL(s) <= IOPL(s)) { if (dflag != MO_16) { gen_helper_write_eflags(cpu_env, s->T0, tcg_const_i32((TF_MASK | @@ -6830,7 +6913,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) do_btx: ot = dflag; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(s, MO_32, s->T1, reg); @@ -6935,7 +7018,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1bd: /* bsr / lzcnt */ ot = dflag; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); gen_extu(ot, s->T0); @@ -7060,9 +7143,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xcd: /* int N */ val = x86_ldub_code(env, s); - if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + if (check_vm86_iopl(s)) { gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); } break; @@ -7075,33 +7156,21 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; #ifdef WANT_ICEBP case 0xf1: /* icebp (undocumented, exits to external debugger) */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP); - gen_debug(s, pc_start - s->cs_base); + gen_svm_check_intercept(s, SVM_EXIT_ICEBP); + gen_debug(s); break; #endif case 0xfa: /* cli */ - if (!s->vm86) { - if (s->cpl <= s->iopl) { - gen_helper_cli(cpu_env); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } - } else { - if (s->iopl == 3) { - gen_helper_cli(cpu_env); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } + if (check_iopl(s)) { + gen_helper_cli(cpu_env); } break; case 0xfb: /* sti */ - if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) { + if (check_iopl(s)) { gen_helper_sti(cpu_env); /* interruptions are enabled only the first insn after sti */ gen_jmp_im(s, s->pc - s->cs_base); gen_eob_inhibit_irq(s, true); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } break; case 0x62: /* bound */ @@ -7193,15 +7262,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0x130: /* wrmsr */ case 0x132: /* rdmsr */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + if (check_cpl0(s)) { gen_update_cc_op(s); gen_jmp_im(s, pc_start - s->cs_base); if (b & 2) { gen_helper_rdmsr(cpu_env); } else { gen_helper_wrmsr(cpu_env); + gen_jmp_im(s, s->pc - s->cs_base); + gen_eob(s); } } break; @@ -7220,13 +7289,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_jmp_im(s, pc_start - s->cs_base); gen_helper_rdpmc(cpu_env); + s->base.is_jmp = DISAS_NORETURN; break; case 0x134: /* sysenter */ /* For Intel SYSENTER is valid on 64-bit */ if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; - if (!s->pe) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!PE(s)) { + gen_exception_gpf(s); } else { gen_helper_sysenter(cpu_env); gen_eob(s); @@ -7236,8 +7306,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) /* For Intel SYSEXIT is valid on 64-bit */ if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) goto illegal_op; - if (!s->pe) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!PE(s)) { + gen_exception_gpf(s); } else { gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1)); gen_eob(s); @@ -7255,12 +7325,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_eob_worker(s, false, true); break; case 0x107: /* sysret */ - if (!s->pe) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!PE(s)) { + gen_exception_gpf(s); } else { gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1)); /* condition codes are modified only in long mode */ - if (s->lma) { + if (LMA(s)) { set_cc_op(s, CC_OP_EFLAGS); } /* TF handling for the sysret insn is different. The TF bit is @@ -7277,9 +7347,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_cpuid(cpu_env); break; case 0xf4: /* hlt */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + if (check_cpl0(s)) { gen_update_cc_op(s); gen_jmp_im(s, pc_start - s->cs_base); gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start)); @@ -7292,42 +7360,38 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) op = (modrm >> 3) & 7; switch(op) { case 0: /* sldt */ - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; - gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ); + gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, ldt.selector)); ot = mod == 3 ? dflag : MO_16; gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); break; case 2: /* lldt */ - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE); + if (check_cpl0(s)) { + gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_lldt(cpu_env, s->tmp2_i32); } break; case 1: /* str */ - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; - gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ); + gen_svm_check_intercept(s, SVM_EXIT_TR_READ); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, tr.selector)); ot = mod == 3 ? dflag : MO_16; gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); break; case 3: /* ltr */ - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE); + if (check_cpl0(s)) { + gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); gen_helper_ltr(cpu_env, s->tmp2_i32); @@ -7335,7 +7399,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 4: /* verr */ case 5: /* verw */ - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_update_cc_op(s); @@ -7355,7 +7419,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); switch (modrm) { CASE_MODRM_MEM_OP(0): /* sgdt */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); + gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, gdt.limit)); @@ -7369,7 +7433,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xc8: /* monitor */ - if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) { + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) { goto illegal_op; } gen_update_cc_op(s); @@ -7381,18 +7445,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xc9: /* mwait */ - if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) { + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) { goto illegal_op; } gen_update_cc_op(s); gen_jmp_im(s, pc_start - s->cs_base); gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start)); - gen_eob(s); + s->base.is_jmp = DISAS_NORETURN; break; case 0xca: /* clac */ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) - || s->cpl != 0) { + || CPL(s) != 0) { goto illegal_op; } gen_helper_clac(cpu_env); @@ -7402,7 +7466,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xcb: /* stac */ if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) - || s->cpl != 0) { + || CPL(s) != 0) { goto illegal_op; } gen_helper_stac(cpu_env); @@ -7411,7 +7475,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; CASE_MODRM_MEM_OP(1): /* sidt */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); + gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.limit)); gen_op_st_v(s, MO_16, s->T0, s->A0); @@ -7440,8 +7504,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) | PREFIX_REPZ | PREFIX_REPNZ))) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX], @@ -7454,11 +7517,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xd8: /* VMRUN */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) { + if (!SVME(s) || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } gen_update_cc_op(s); @@ -7470,7 +7532,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xd9: /* VMMCALL */ - if (!(s->flags & HF_SVME_MASK)) { + if (!SVME(s)) { goto illegal_op; } gen_update_cc_op(s); @@ -7479,11 +7541,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xda: /* VMLOAD */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) { + if (!SVME(s) || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } gen_update_cc_op(s); @@ -7492,11 +7553,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xdb: /* VMSAVE */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) { + if (!SVME(s) || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } gen_update_cc_op(s); @@ -7505,13 +7565,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xdc: /* STGI */ - if ((!(s->flags & HF_SVME_MASK) - && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) - || !s->pe) { + if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) + || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } gen_update_cc_op(s); @@ -7521,11 +7579,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xdd: /* CLGI */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) { + if (!SVME(s) || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } gen_update_cc_op(s); @@ -7534,35 +7591,37 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; case 0xde: /* SKINIT */ - if ((!(s->flags & HF_SVME_MASK) - && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) - || !s->pe) { + if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) + || !PE(s)) { goto illegal_op; } - gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_skinit(cpu_env); - break; + gen_svm_check_intercept(s, SVM_EXIT_SKINIT); + /* If not intercepted, not implemented -- raise #UD. */ + goto illegal_op; case 0xdf: /* INVLPGA */ - if (!(s->flags & HF_SVME_MASK) || !s->pe) { + if (!SVME(s) || !PE(s)) { goto illegal_op; } - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } - gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1)); + gen_svm_check_intercept(s, SVM_EXIT_INVLPGA); + if (s->aflag == MO_64) { + tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]); + } else { + tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]); + } + gen_helper_flush_page(cpu_env, s->A0); + gen_jmp_im(s, s->pc - s->cs_base); + gen_eob(s); break; CASE_MODRM_MEM_OP(2): /* lgdt */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } - gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_WRITE); + gen_svm_check_intercept(s, SVM_EXIT_GDTR_WRITE); gen_lea_modrm(env, s, modrm); gen_op_ld_v(s, MO_16, s->T1, s->A0); gen_add_A0_im(s, 2); @@ -7575,11 +7634,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; CASE_MODRM_MEM_OP(3): /* lidt */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } - gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_WRITE); + gen_svm_check_intercept(s, SVM_EXIT_IDTR_WRITE); gen_lea_modrm(env, s, modrm); gen_op_ld_v(s, MO_16, s->T1, s->A0); gen_add_A0_im(s, 2); @@ -7592,7 +7650,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) break; CASE_MODRM_OP(4): /* smsw */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); + gen_svm_check_intercept(s, SVM_EXIT_READ_CR0); tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0])); /* * In 32-bit mode, the higher 16 bits of the destination @@ -7620,27 +7678,33 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]); gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64); break; + CASE_MODRM_OP(6): /* lmsw */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } - gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); + gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); - gen_helper_lmsw(cpu_env, s->T0); + /* + * Only the 4 lower bits of CR0 are modified. + * PE cannot be set to zero if already set to one. + */ + tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0])); + tcg_gen_andi_tl(s->T0, s->T0, 0xf); + tcg_gen_andi_tl(s->T1, s->T1, ~0xe); + tcg_gen_or_tl(s->T0, s->T0, s->T1); + gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0); gen_jmp_im(s, s->pc - s->cs_base); gen_eob(s); break; CASE_MODRM_MEM_OP(7): /* invlpg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (!check_cpl0(s)) { break; } - gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); + gen_svm_check_intercept(s, SVM_EXIT_INVLPG); gen_lea_modrm(env, s, modrm); - gen_helper_invlpg(cpu_env, s->A0); + gen_helper_flush_page(cpu_env, s->A0); gen_jmp_im(s, s->pc - s->cs_base); gen_eob(s); break; @@ -7648,9 +7712,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0xf8: /* swapgs */ #ifdef TARGET_X86_64 if (CODE64(s)) { - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { + if (check_cpl0(s)) { tcg_gen_mov_tl(s->T0, cpu_seg_base[R_GS]); tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env, offsetof(CPUX86State, kernelgsbase)); @@ -7684,10 +7746,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x108: /* invd */ case 0x109: /* wbinvd */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); + if (check_cpl0(s)) { + gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); /* nothing to do */ } break; @@ -7699,7 +7759,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) d_ot = dflag; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); @@ -7721,7 +7781,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) TCGLabel *label1; TCGv t0, t1, t2, a0; - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; t0 = tcg_temp_local_new(); t1 = tcg_temp_local_new(); @@ -7769,11 +7829,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) { TCGLabel *label1; TCGv t0; - if (!s->pe || s->vm86) + if (!PE(s) || VM86(s)) goto illegal_op; ot = dflag != MO_16 ? MO_32 : MO_16; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); t0 = tcg_temp_local_new(); gen_update_cc_op(s); @@ -7814,7 +7874,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); if (s->flags & HF_MPX_EN_MASK) { mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (prefixes & PREFIX_REPZ) { /* bndcl */ if (reg >= 4 @@ -7904,7 +7964,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); if (s->flags & HF_MPX_EN_MASK) { mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (mod != 3 && (prefixes & PREFIX_REPZ)) { /* bndmk */ if (reg >= 4 @@ -8006,66 +8066,59 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) modrm = x86_ldub_code(env, s); gen_nop_modrm(env, s, modrm); break; + case 0x120: /* mov reg, crN */ case 0x122: /* mov crN, reg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - modrm = x86_ldub_code(env, s); - /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). - * AMD documentation (24594.pdf) and testing of - * intel 386 and 486 processors all show that the mod bits - * are assumed to be 1's, regardless of actual values. - */ - rm = (modrm & 7) | REX_B(s); - reg = ((modrm >> 3) & 7) | rex_r; - if (CODE64(s)) - ot = MO_64; - else - ot = MO_32; - if ((prefixes & PREFIX_LOCK) && (reg == 0) && + if (!check_cpl0(s)) { + break; + } + modrm = x86_ldub_code(env, s); + /* + * Ignore the mod bits (assume (modrm&0xc0)==0xc0). + * AMD documentation (24594.pdf) and testing of Intel 386 and 486 + * processors all show that the mod bits are assumed to be 1's, + * regardless of actual values. + */ + rm = (modrm & 7) | REX_B(s); + reg = ((modrm >> 3) & 7) | REX_R(s); + switch (reg) { + case 0: + if ((prefixes & PREFIX_LOCK) && (s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) { reg = 8; } - switch(reg) { - case 0: - case 2: - case 3: - case 4: - case 8: - gen_update_cc_op(s); - gen_jmp_im(s, pc_start - s->cs_base); - if (b & 2) { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_op_mov_v_reg(s, ot, s->T0, rm); - gen_helper_write_crN(cpu_env, tcg_const_i32(reg), - s->T0); - gen_jmp_im(s, s->pc - s->cs_base); - gen_eob(s); - } else { - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_read_crN(s->T0, cpu_env, tcg_const_i32(reg)); - gen_op_mov_reg_v(s, ot, rm, s->T0); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_jmp(s, s->pc - s->cs_base); - } - } - break; - default: - goto unknown_op; + break; + case 2: + case 3: + case 4: + break; + default: + goto unknown_op; + } + ot = (CODE64(s) ? MO_64 : MO_32); + + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } + if (b & 2) { + gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg); + gen_op_mov_v_reg(s, ot, s->T0, rm); + gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0); + gen_jmp_im(s, s->pc - s->cs_base); + gen_eob(s); + } else { + gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg); + gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg)); + gen_op_mov_reg_v(s, ot, rm, s->T0); + if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + gen_jmp(s, s->pc - s->cs_base); } } break; + case 0x121: /* mov reg, drN */ case 0x123: /* mov drN, reg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { -#ifndef CONFIG_USER_ONLY + if (check_cpl0(s)) { modrm = x86_ldub_code(env, s); /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). * AMD documentation (24594.pdf) and testing of @@ -8073,7 +8126,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) * are assumed to be 1's, regardless of actual values. */ rm = (modrm & 7) | REX_B(s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (CODE64(s)) ot = MO_64; else @@ -8082,26 +8135,23 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; } if (b & 2) { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); + gen_svm_check_intercept(s, SVM_EXIT_WRITE_DR0 + reg); gen_op_mov_v_reg(s, ot, s->T0, rm); tcg_gen_movi_i32(s->tmp2_i32, reg); gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0); gen_jmp_im(s, s->pc - s->cs_base); gen_eob(s); } else { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg); + gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg); tcg_gen_movi_i32(s->tmp2_i32, reg); gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32); gen_op_mov_reg_v(s, ot, rm, s->T0); } -#endif /* !CONFIG_USER_ONLY */ } break; case 0x106: /* clts */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); + if (check_cpl0(s)) { + gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0); gen_helper_clts(cpu_env); /* abort block because static cpu state changed */ gen_jmp_im(s, s->pc - s->cs_base); @@ -8117,7 +8167,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); /* generate a generic store */ gen_ldst_modrm(env, s, modrm, ot, reg, 1); break; @@ -8328,7 +8378,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_nop_modrm(env, s, modrm); break; case 0x1aa: /* rsm */ - gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); + gen_svm_check_intercept(s, SVM_EXIT_RSM); if (!(s->flags & HF_SMM_MASK)) goto illegal_op; #ifdef CONFIG_USER_ONLY @@ -8349,7 +8399,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) goto illegal_op; modrm = x86_ldub_code(env, s); - reg = ((modrm >> 3) & 7) | rex_r; + reg = ((modrm >> 3) & 7) | REX_R(s); if (s->prefix & PREFIX_DATA) { ot = MO_16; @@ -8377,7 +8427,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) case 0x1c2: case 0x1c4 ... 0x1c6: case 0x1d0 ... 0x1fe: - gen_sse(env, s, b, pc_start, rex_r); + gen_sse(env, s, b, pc_start); break; default: goto unknown_op; @@ -8477,20 +8527,31 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) DisasContext *dc = container_of(dcbase, DisasContext, base); CPUX86State *env = cpu->env_ptr; uint32_t flags = dc->base.tb->flags; - target_ulong cs_base = dc->base.tb->cs_base; - - dc->pe = (flags >> HF_PE_SHIFT) & 1; - dc->code32 = (flags >> HF_CS32_SHIFT) & 1; - dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; - dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; - dc->f_st = 0; - dc->vm86 = (flags >> VM_SHIFT) & 1; - dc->cpl = (flags >> HF_CPL_SHIFT) & 3; - dc->iopl = (flags >> IOPL_SHIFT) & 3; - dc->tf = (flags >> TF_SHIFT) & 1; + int cpl = (flags >> HF_CPL_SHIFT) & 3; + int iopl = (flags >> IOPL_SHIFT) & 3; + + dc->cs_base = dc->base.tb->cs_base; + dc->flags = flags; +#ifndef CONFIG_USER_ONLY + dc->cpl = cpl; + dc->iopl = iopl; +#endif + + /* We make some simplifying assumptions; validate they're correct. */ + g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0)); + g_assert(CPL(dc) == cpl); + g_assert(IOPL(dc) == iopl); + g_assert(VM86(dc) == ((flags & HF_VM_MASK) != 0)); + g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0)); + g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0)); + g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0)); + g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0)); + g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0)); + g_assert(SVME(dc) == ((flags & HF_SVME_MASK) != 0)); + g_assert(GUEST(dc) == ((flags & HF_GUEST_MASK) != 0)); + dc->cc_op = CC_OP_DYNAMIC; dc->cc_op_dirty = false; - dc->cs_base = cs_base; dc->popl_esp_hack = 0; /* select memory access functions */ dc->mem_index = 0; @@ -8503,29 +8564,14 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX]; dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX]; dc->cpuid_xsave_features = env->features[FEAT_XSAVE]; -#ifdef TARGET_X86_64 - dc->lma = (flags >> HF_LMA_SHIFT) & 1; - dc->code64 = (flags >> HF_CS64_SHIFT) & 1; -#endif - dc->flags = flags; - dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled || - (flags & HF_INHIBIT_IRQ_MASK)); - /* Do not optimize repz jumps at all in icount mode, because - rep movsS instructions are execured with different paths - in !repz_opt and repz_opt modes. The first one was used - always except single step mode. And this setting - disables jumps optimization and control paths become - equivalent in run and single step modes. - Now there will be no jump optimization for repz in - record/replay modes and there will always be an - additional step for ecx=0 when icount is enabled. + dc->jmp_opt = !(dc->base.singlestep_enabled || + (flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK))); + /* + * If jmp_opt, we want to handle each string instruction individually. + * For icount also disable repz optimization so that each iteration + * is accounted separately. */ dc->repz_opt = !dc->jmp_opt && !(tb_cflags(dc->base.tb) & CF_USE_ICOUNT); -#if 0 - /* check addseg logic */ - if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32)) - printf("ERROR addseg\n"); -#endif dc->T0 = tcg_temp_new(); dc->T1 = tcg_temp_new(); @@ -8559,8 +8605,7 @@ static bool i386_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, /* If RF is set, suppress an internally generated breakpoint. */ int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY; if (bp->flags & flags) { - gen_debug(dc, dc->base.pc_next - dc->cs_base); - dc->base.is_jmp = DISAS_NORETURN; + gen_debug(dc); /* The address covered by the breakpoint must be included in [tb->pc, tb->pc + tb->size) in order to for it to be properly cleared -- thus we increment the PC here so that @@ -8583,13 +8628,14 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) */ if ((dc->base.pc_next & TARGET_PAGE_MASK) == TARGET_VSYSCALL_PAGE) { gen_exception(dc, EXCP_VSYSCALL, dc->base.pc_next); + dc->base.pc_next = dc->pc + 1; return; } #endif pc_next = disas_insn(dc, cpu); - if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) { + if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) { /* if single step mode, we generate only one instruction and generate an exception */ /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build index 9eac0e69ca..1df6bc4343 100644 --- a/target/i386/tcg/user/meson.build +++ b/target/i386/tcg/user/meson.build @@ -1,6 +1,4 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( 'excp_helper.c', - 'misc_stubs.c', - 'svm_stubs.c', 'seg_helper.c', )) diff --git a/target/i386/tcg/user/misc_stubs.c b/target/i386/tcg/user/misc_stubs.c deleted file mode 100644 index 84df4e65ff..0000000000 --- a/target/i386/tcg/user/misc_stubs.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * x86 misc helpers - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" - -void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) -{ - g_assert_not_reached(); -} - -target_ulong helper_inb(CPUX86State *env, uint32_t port) -{ - g_assert_not_reached(); - return 0; -} - -void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) -{ - g_assert_not_reached(); -} - -target_ulong helper_inw(CPUX86State *env, uint32_t port) -{ - g_assert_not_reached(); - return 0; -} - -void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) -{ - g_assert_not_reached(); -} - -target_ulong helper_inl(CPUX86State *env, uint32_t port) -{ - g_assert_not_reached(); - return 0; -} - -target_ulong helper_read_crN(CPUX86State *env, int reg) -{ - g_assert_not_reached(); -} - -void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) -{ - g_assert_not_reached(); -} - -void helper_wrmsr(CPUX86State *env) -{ - g_assert_not_reached(); -} - -void helper_rdmsr(CPUX86State *env) -{ - g_assert_not_reached(); -} diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c deleted file mode 100644 index 97528b56ad..0000000000 --- a/target/i386/tcg/user/svm_stubs.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * x86 SVM helpers (user-mode) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "tcg/helper-tcg.h" - -void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) -{ -} - -void helper_vmmcall(CPUX86State *env) -{ -} - -void helper_vmload(CPUX86State *env, int aflag) -{ -} - -void helper_vmsave(CPUX86State *env, int aflag) -{ -} - -void helper_stgi(CPUX86State *env) -{ -} - -void helper_clgi(CPUX86State *env) -{ -} - -void helper_skinit(CPUX86State *env) -{ -} - -void helper_invlpga(CPUX86State *env, int aflag) -{ -} - -void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, - uintptr_t retaddr) -{ - assert(0); -} - -void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) -{ -} - -void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param, uintptr_t retaddr) -{ -} - -void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, - uint32_t next_eip_addend) -{ -} diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 9ab04b2c38..9210e61ef4 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -17,7 +17,6 @@ #include "elf.h" #include "sysemu/dump.h" #include "sysemu/kvm.h" -#include "exec/helper-proto.h" #ifdef TARGET_PPC64 #define ELFCLASS ELFCLASS64 @@ -176,7 +175,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) vmxregset->avr[i].u64[1] = avr->u64[1]; } } - vmxregset->vscr.u32[3] = cpu_to_dump32(s, helper_mfvscr(&cpu->env)); + vmxregset->vscr.u32[3] = cpu_to_dump32(s, ppc_get_vscr(&cpu->env)); } static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu) diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index e501a7ff6f..d957d1a687 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -20,6 +20,10 @@ #include "qemu/osdep.h" #include "cpu.h" #include "cpu-models.h" +#include "cpu-qom.h" +#include "exec/log.h" +#include "fpu/softfloat-helpers.h" +#include "mmu-hash64.h" target_ulong cpu_read_xer(CPUPPCState *env) { @@ -45,3 +49,46 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer) (1ul << XER_OV) | (1ul << XER_CA) | (1ul << XER_OV32) | (1ul << XER_CA32)); } + +void ppc_store_vscr(CPUPPCState *env, uint32_t vscr) +{ + env->vscr = vscr & ~(1u << VSCR_SAT); + /* Which bit we set is completely arbitrary, but clear the rest. */ + env->vscr_sat.u64[0] = vscr & (1u << VSCR_SAT); + env->vscr_sat.u64[1] = 0; + set_flush_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status); +} + +uint32_t ppc_get_vscr(CPUPPCState *env) +{ + uint32_t sat = (env->vscr_sat.u64[0] | env->vscr_sat.u64[1]) != 0; + return env->vscr | (sat << VSCR_SAT); +} + +#ifdef CONFIG_SOFTMMU +void ppc_store_sdr1(CPUPPCState *env, target_ulong value) +{ + PowerPCCPU *cpu = env_archcpu(env); + qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); + assert(!cpu->vhyp); +#if defined(TARGET_PPC64) + if (mmu_is_64bit(env->mmu_model)) { + target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE; + target_ulong htabsize = value & SDR_64_HTABSIZE; + + if (value & ~sdr_mask) { + error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1", + value & ~sdr_mask); + value &= sdr_mask; + } + if (htabsize > 28) { + error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1", + htabsize); + return; + } + } +#endif /* defined(TARGET_PPC64) */ + /* FIXME: Should check for valid HTABMASK values in 32-bit case */ + env->spr[SPR_SDR1] = value; +} +#endif /* CONFIG_SOFTMMU */ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 733a2168c4..cab33a3680 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -131,11 +131,7 @@ enum { POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception */ /* EOL */ POWERPC_EXCP_NB = 103, - /* QEMU exceptions: used internally during code translation */ - POWERPC_EXCP_STOP = 0x200, /* stop translation */ - POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */ /* QEMU exceptions: special cases we want to stop translation */ - POWERPC_EXCP_SYNC = 0x202, /* context synchronizing instruction */ POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only */ }; @@ -1297,6 +1293,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value); void ppc_store_ptcr(CPUPPCState *env, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr(CPUPPCState *env, target_ulong value); +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_cpu_list(void); @@ -2641,7 +2638,15 @@ static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i) return (ppc_avr_t *)((uintptr_t)env + avr_full_offset(i)); } +static inline bool ppc_has_spr(PowerPCCPU *cpu, int spr) +{ + /* We can test whether the SPR is defined by checking for a valid name */ + return cpu->env.spr_cb[spr].name != NULL; +} + void dump_mmu(CPUPPCState *env); void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len); +void ppc_store_vscr(CPUPPCState *env, uint32_t vscr); +uint32_t ppc_get_vscr(CPUPPCState *env); #endif /* PPC_CPU_H */ diff --git a/target/ppc/translate_init.c.inc b/target/ppc/cpu_init.c index 66e6a4a746..22ecbccad8 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/cpu_init.c @@ -18,6 +18,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "disas/dis-asm.h" #include "exec/gdbstub.h" #include "kvm_ppc.h" @@ -42,682 +43,19 @@ #include "fpu/softfloat.h" #include "qapi/qapi-commands-machine-target.h" +#include "exec/helper-proto.h" +#include "helper_regs.h" +#include "internal.h" +#include "spr_tcg.h" + /* #define PPC_DEBUG_SPR */ -/* #define PPC_DUMP_SPR_ACCESSES */ /* #define USE_APPLE_GDB */ -/* - * Generic callbacks: - * do nothing but store/retrieve spr value - */ -static void spr_load_dump_spr(int sprn) -{ -#ifdef PPC_DUMP_SPR_ACCESSES - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_load_dump_spr(cpu_env, t0); - tcg_temp_free_i32(t0); -#endif -} - -static void spr_read_generic(DisasContext *ctx, int gprn, int sprn) -{ - gen_load_spr(cpu_gpr[gprn], sprn); - spr_load_dump_spr(sprn); -} - -static void spr_store_dump_spr(int sprn) -{ -#ifdef PPC_DUMP_SPR_ACCESSES - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_store_dump_spr(cpu_env, t0); - tcg_temp_free_i32(t0); -#endif -} - -static void spr_write_generic(DisasContext *ctx, int sprn, int gprn) -{ - gen_store_spr(sprn, cpu_gpr[gprn]); - spr_store_dump_spr(sprn); -} - -#if !defined(CONFIG_USER_ONLY) -static void spr_write_generic32(DisasContext *ctx, int sprn, int gprn) -{ -#ifdef TARGET_PPC64 - TCGv t0 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); - spr_store_dump_spr(sprn); -#else - spr_write_generic(ctx, sprn, gprn); -#endif -} - -static void spr_write_clear(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - gen_load_spr(t0, sprn); - tcg_gen_neg_tl(t1, cpu_gpr[gprn]); - tcg_gen_and_tl(t0, t0, t1); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); - tcg_temp_free(t1); -} - -static void spr_access_nop(DisasContext *ctx, int sprn, int gprn) -{ -} - -#endif - -/* SPR common to all PowerPC */ -/* XER */ -static void spr_read_xer(DisasContext *ctx, int gprn, int sprn) -{ - gen_read_xer(ctx, cpu_gpr[gprn]); -} - -static void spr_write_xer(DisasContext *ctx, int sprn, int gprn) -{ - gen_write_xer(cpu_gpr[gprn]); -} - -/* LR */ -static void spr_read_lr(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr); -} - -static void spr_write_lr(DisasContext *ctx, int sprn, int gprn) -{ - tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]); -} - -/* CFAR */ -#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -static void spr_read_cfar(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar); -} - -static void spr_write_cfar(DisasContext *ctx, int sprn, int gprn) -{ - tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]); -} -#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */ - -/* CTR */ -static void spr_read_ctr(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr); -} - -static void spr_write_ctr(DisasContext *ctx, int sprn, int gprn) -{ - tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]); -} - -/* User read access to SPR */ -/* USPRx */ -/* UMMCRx */ -/* UPMCx */ -/* USIA */ -/* UDECR */ -static void spr_read_ureg(DisasContext *ctx, int gprn, int sprn) -{ - gen_load_spr(cpu_gpr[gprn], sprn + 0x10); -} - -#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -static void spr_write_ureg(DisasContext *ctx, int sprn, int gprn) -{ - gen_store_spr(sprn + 0x10, cpu_gpr[gprn]); -} -#endif - -/* SPR common to all non-embedded PowerPC */ -/* DECR */ -#if !defined(CONFIG_USER_ONLY) -static void spr_read_decr(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_decr(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_decr(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_decr(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} -#endif - -/* SPR common to all non-embedded PowerPC, except 601 */ -/* Time base */ -static void spr_read_tbl(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_tbl(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -static void spr_read_tbu(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_tbu(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -ATTRIBUTE_UNUSED -static void spr_read_atbl(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_load_atbl(cpu_gpr[gprn], cpu_env); -} - -ATTRIBUTE_UNUSED -static void spr_read_atbu(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_load_atbu(cpu_gpr[gprn], cpu_env); -} - -#if !defined(CONFIG_USER_ONLY) -static void spr_write_tbl(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -static void spr_write_tbu(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -ATTRIBUTE_UNUSED -static void spr_write_atbl(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]); -} - -ATTRIBUTE_UNUSED -static void spr_write_atbu(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]); -} - -#if defined(TARGET_PPC64) -ATTRIBUTE_UNUSED -static void spr_read_purr(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_purr(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_purr(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_purr(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -/* HDECR */ -static void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -static void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - gen_stop_exception(ctx); - } -} - -static void spr_read_vtb(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_vtb(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_vtb(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_vtb(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_tbu40(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -#endif -#endif - -#if !defined(CONFIG_USER_ONLY) -/* IBAT0U...IBAT0U */ -/* IBAT0L...IBAT7L */ -static void spr_read_ibat(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, - IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); -} - -static void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, - IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4])); -} - -static void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4); - gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2); - gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4); - gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -/* DBAT0U...DBAT7U */ -/* DBAT0L...DBAT7L */ -static void spr_read_dbat(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, - DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2])); -} - -static void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, - DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4])); -} - -static void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2); - gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4); - gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2); - gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4); - gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -/* SDR1 */ -static void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]); -} - -#if defined(TARGET_PPC64) -/* 64 bits PowerPC specific SPRs */ -/* PIDR */ -static void spr_write_pidr(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]); -} - -static void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]); -} - -static void spr_read_hior(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix)); -} - -static void spr_write_hior(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); - tcg_temp_free(t0); -} -static void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]); -} - -static void spr_write_pcr(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_pcr(cpu_env, cpu_gpr[gprn]); -} - -/* DPDES */ -static void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env); -} - -static void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]); -} -#endif -#endif - -/* PowerPC 601 specific registers */ -/* RTC */ -static void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env); -} - -static void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env); -} - -#if !defined(CONFIG_USER_ONLY) -static void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]); -} - -static void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]); -} - -static void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]); - /* Must stop the translation as endianness may have changed */ - gen_stop_exception(ctx); -} -#endif - -/* Unified bats */ -#if !defined(CONFIG_USER_ONLY) -static void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, - IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); -} - -static void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); - gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} -#endif - -/* PowerPC 40x specific registers */ -#if !defined(CONFIG_USER_ONLY) -static void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_store_spr(sprn, cpu_gpr[gprn]); - gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); - /* We must stop translation as we may have rebooted */ - gen_stop_exception(ctx); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} - -static void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) -{ - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]); - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } -} -#endif - -/* PowerPC 403 specific registers */ -/* PBL1 / PBU1 / PBL2 / PBU2 */ -#if !defined(CONFIG_USER_ONLY) -static void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1])); -} - -static void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1); - gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - -static void spr_write_pir(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF); - gen_store_spr(SPR_PIR, t0); - tcg_temp_free(t0); -} -#endif - -/* SPE specific registers */ -static void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); - tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0); - tcg_temp_free_i32(t0); -} - -static void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]); - tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); - tcg_temp_free_i32(t0); -} - -#if !defined(CONFIG_USER_ONLY) -/* Callback used to write the exception vector base */ -static void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask)); - tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); -} - -static void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn) -{ - int sprn_offs; - - if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) { - sprn_offs = sprn - SPR_BOOKE_IVOR0; - } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) { - sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32; - } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) { - sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38; - } else { - printf("Trying to write an unknown exception vector %d %03x\n", - sprn, sprn); - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } - - TCGv t0 = tcg_temp_new(); - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask)); - tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); - tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs])); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); -} -#endif - static inline void vscr_init(CPUPPCState *env, uint32_t val) { /* Altivec always uses round-to-nearest */ set_float_rounding_mode(float_round_nearest_even, &env->vec_status); - helper_mtvscr(env, val); + ppc_store_vscr(env, val); } /** @@ -813,7 +151,7 @@ static void _spr_register(CPUPPCState *env, int num, const char *name, oea_read, oea_write, 0, ival) /* Generic PowerPC SPRs */ -static void gen_spr_generic(CPUPPCState *env) +static void register_generic_sprs(CPUPPCState *env) { /* Integer processing */ spr_register(env, SPR_XER, "XER", @@ -858,7 +196,7 @@ static void gen_spr_generic(CPUPPCState *env) } /* SPR common to all non-embedded PowerPC, including 601 */ -static void gen_spr_ne_601(CPUPPCState *env) +static void register_ne_601_sprs(CPUPPCState *env) { /* Exception processing */ spr_register_kvm(env, SPR_DSISR, "DSISR", @@ -877,7 +215,7 @@ static void gen_spr_ne_601(CPUPPCState *env) } /* Storage Description Register 1 */ -static void gen_spr_sdr1(CPUPPCState *env) +static void register_sdr1_sprs(CPUPPCState *env) { #ifndef CONFIG_USER_ONLY if (env->has_hv_mode) { @@ -900,7 +238,7 @@ static void gen_spr_sdr1(CPUPPCState *env) } /* BATs 0-3 */ -static void gen_low_BATs(CPUPPCState *env) +static void register_low_BATs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_IBAT0U, "IBAT0U", @@ -972,7 +310,7 @@ static void gen_low_BATs(CPUPPCState *env) } /* BATs 4-7 */ -static void gen_high_BATs(CPUPPCState *env) +static void register_high_BATs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_IBAT4U, "IBAT4U", @@ -1044,7 +382,7 @@ static void gen_high_BATs(CPUPPCState *env) } /* Generic PowerPC time base */ -static void gen_tbl(CPUPPCState *env) +static void register_tbl(CPUPPCState *env) { spr_register(env, SPR_VTBL, "TBL", &spr_read_tbl, SPR_NOACCESS, @@ -1065,7 +403,7 @@ static void gen_tbl(CPUPPCState *env) } /* Softare table search registers */ -static void gen_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) +static void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) { #if !defined(CONFIG_USER_ONLY) env->nb_tlb = nb_tlbs; @@ -1104,7 +442,7 @@ static void gen_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) } /* SPR common to MPC755 and G2 */ -static void gen_spr_G2_755(CPUPPCState *env) +static void register_G2_755_sprs(CPUPPCState *env) { /* SGPRs */ spr_register(env, SPR_SPRG4, "SPRG4", @@ -1126,7 +464,7 @@ static void gen_spr_G2_755(CPUPPCState *env) } /* SPR common to all 7xx PowerPC implementations */ -static void gen_spr_7xx(CPUPPCState *env) +static void register_7xx_sprs(CPUPPCState *env) { /* Breakpoints */ /* XXX : not implemented */ @@ -1225,106 +563,7 @@ static void gen_spr_7xx(CPUPPCState *env) } #ifdef TARGET_PPC64 -#ifndef CONFIG_USER_ONLY -static void spr_write_amr(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - /* - * Note, the HV=1 PR=0 case is handled earlier by simply using - * spr_write_generic for HV mode in the SPR table - */ - - /* Build insertion mask into t1 based on context */ - if (ctx->pr) { - gen_load_spr(t1, SPR_UAMOR); - } else { - gen_load_spr(t1, SPR_AMOR); - } - - /* Mask new bits into t2 */ - tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); - - /* Load AMR and clear new bits in t0 */ - gen_load_spr(t0, SPR_AMR); - tcg_gen_andc_tl(t0, t0, t1); - - /* Or'in new bits and write it out */ - tcg_gen_or_tl(t0, t0, t2); - gen_store_spr(SPR_AMR, t0); - spr_store_dump_spr(SPR_AMR); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void spr_write_uamor(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - /* - * Note, the HV=1 case is handled earlier by simply using - * spr_write_generic for HV mode in the SPR table - */ - - /* Build insertion mask into t1 based on context */ - gen_load_spr(t1, SPR_AMOR); - - /* Mask new bits into t2 */ - tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); - - /* Load AMR and clear new bits in t0 */ - gen_load_spr(t0, SPR_UAMOR); - tcg_gen_andc_tl(t0, t0, t1); - - /* Or'in new bits and write it out */ - tcg_gen_or_tl(t0, t0, t2); - gen_store_spr(SPR_UAMOR, t0); - spr_store_dump_spr(SPR_UAMOR); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - /* - * Note, the HV=1 case is handled earlier by simply using - * spr_write_generic for HV mode in the SPR table - */ - - /* Build insertion mask into t1 based on context */ - gen_load_spr(t1, SPR_AMOR); - - /* Mask new bits into t2 */ - tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); - - /* Load AMR and clear new bits in t0 */ - gen_load_spr(t0, SPR_IAMR); - tcg_gen_andc_tl(t0, t0, t1); - - /* Or'in new bits and write it out */ - tcg_gen_or_tl(t0, t0, t2); - gen_store_spr(SPR_IAMR, t0); - spr_store_dump_spr(SPR_IAMR); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} -#endif /* CONFIG_USER_ONLY */ - -static void gen_spr_amr(CPUPPCState *env) +static void register_amr_sprs(CPUPPCState *env) { #ifndef CONFIG_USER_ONLY /* @@ -1356,7 +595,7 @@ static void gen_spr_amr(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ } -static void gen_spr_iamr(CPUPPCState *env) +static void register_iamr_sprs(CPUPPCState *env) { #ifndef CONFIG_USER_ONLY spr_register_kvm_hv(env, SPR_IAMR, "IAMR", @@ -1368,16 +607,7 @@ static void gen_spr_iamr(CPUPPCState *env) } #endif /* TARGET_PPC64 */ -#ifndef CONFIG_USER_ONLY -static void spr_read_thrm(DisasContext *ctx, int gprn, int sprn) -{ - gen_helper_fixup_thrm(cpu_env); - gen_load_spr(cpu_gpr[gprn], sprn); - spr_load_dump_spr(sprn); -} -#endif /* !CONFIG_USER_ONLY */ - -static void gen_spr_thrm(CPUPPCState *env) +static void register_thrm_sprs(CPUPPCState *env) { /* Thermal management */ /* XXX : not implemented */ @@ -1398,7 +628,7 @@ static void gen_spr_thrm(CPUPPCState *env) } /* SPR specific to PowerPC 604 implementation */ -static void gen_spr_604(CPUPPCState *env) +static void register_604_sprs(CPUPPCState *env) { /* Processor identification */ spr_register(env, SPR_PIR, "PIR", @@ -1451,7 +681,7 @@ static void gen_spr_604(CPUPPCState *env) } /* SPR specific to PowerPC 603 implementation */ -static void gen_spr_603(CPUPPCState *env) +static void register_603_sprs(CPUPPCState *env) { /* External access control */ /* XXX : not implemented */ @@ -1469,7 +699,7 @@ static void gen_spr_603(CPUPPCState *env) } /* SPR specific to PowerPC G2 implementation */ -static void gen_spr_G2(CPUPPCState *env) +static void register_G2_sprs(CPUPPCState *env) { /* Memory base address */ /* MBAR */ @@ -1521,7 +751,7 @@ static void gen_spr_G2(CPUPPCState *env) } /* SPR specific to PowerPC 602 implementation */ -static void gen_spr_602(CPUPPCState *env) +static void register_602_sprs(CPUPPCState *env) { /* ESA registers */ /* XXX : not implemented */ @@ -1569,7 +799,7 @@ static void gen_spr_602(CPUPPCState *env) } /* SPR specific to PowerPC 601 implementation */ -static void gen_spr_601(CPUPPCState *env) +static void register_601_sprs(CPUPPCState *env) { /* Multiplication/division register */ /* MQ */ @@ -1645,7 +875,7 @@ static void gen_spr_601(CPUPPCState *env) #endif } -static void gen_spr_74xx(CPUPPCState *env) +static void register_74xx_sprs(CPUPPCState *env) { /* Processor identification */ spr_register(env, SPR_PIR, "PIR", @@ -1695,7 +925,7 @@ static void gen_spr_74xx(CPUPPCState *env) 0x00000000); } -static void gen_l3_ctrl(CPUPPCState *env) +static void register_l3_ctrl(CPUPPCState *env) { /* L3CR */ /* XXX : not implemented */ @@ -1717,7 +947,7 @@ static void gen_l3_ctrl(CPUPPCState *env) 0x00000000); } -static void gen_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) +static void register_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) { #if !defined(CONFIG_USER_ONLY) env->nb_tlb = nb_tlbs; @@ -1742,58 +972,7 @@ static void gen_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) #endif } -#if !defined(CONFIG_USER_ONLY) -static void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - - tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR0_DCE | L1CSR0_CPE); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); -} - -static void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - - tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR1_ICE | L1CSR1_CPE); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); -} - -static void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn) -{ - TCGv t0 = tcg_temp_new(); - - tcg_gen_andi_tl(t0, cpu_gpr[gprn], - ~(E500_L2CSR0_L2FI | E500_L2CSR0_L2FL | E500_L2CSR0_L2LFC)); - gen_store_spr(sprn, t0); - tcg_temp_free(t0); -} - -static void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]); -} - -static void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} -static void spr_write_eplc(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]); -} -static void spr_write_epsc(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]); -} - -#endif - -static void gen_spr_usprg3(CPUPPCState *env) +static void register_usprg3_sprs(CPUPPCState *env) { spr_register(env, SPR_USPRG3, "USPRG3", &spr_read_ureg, SPR_NOACCESS, @@ -1801,7 +980,7 @@ static void gen_spr_usprg3(CPUPPCState *env) 0x00000000); } -static void gen_spr_usprgh(CPUPPCState *env) +static void register_usprgh_sprs(CPUPPCState *env) { spr_register(env, SPR_USPRG4, "USPRG4", &spr_read_ureg, SPR_NOACCESS, @@ -1822,7 +1001,7 @@ static void gen_spr_usprgh(CPUPPCState *env) } /* PowerPC BookE SPR */ -static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask) +static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask) { const char *ivor_names[64] = { "IVOR0", "IVOR1", "IVOR2", "IVOR3", @@ -1998,7 +1177,8 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask) 0x00000000); } -static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize, +#if !defined(CONFIG_USER_ONLY) +static inline uint32_t register_tlbncfg(uint32_t assoc, uint32_t minsize, uint32_t maxsize, uint32_t flags, uint32_t nentries) { @@ -2007,9 +1187,10 @@ static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize, (maxsize << TLBnCFG_MAXSIZE_SHIFT) | flags | nentries; } +#endif /* !CONFIG_USER_ONLY */ /* BookE 2.06 storage control registers */ -static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, +static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask, uint32_t *tlbncfg, uint32_t mmucfg) { #if !defined(CONFIG_USER_ONLY) @@ -2097,11 +1278,11 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, } #endif - gen_spr_usprgh(env); + register_usprgh_sprs(env); } /* SPR specific to PowerPC 440 implementation */ -static void gen_spr_440(CPUPPCState *env) +static void register_440_sprs(CPUPPCState *env) { /* Cache control */ /* XXX : not implemented */ @@ -2242,7 +1423,7 @@ static void gen_spr_440(CPUPPCState *env) } /* SPR shared between PowerPC 40x implementations */ -static void gen_spr_40x(CPUPPCState *env) +static void register_40x_sprs(CPUPPCState *env) { /* Cache */ /* not emulated, as QEMU do not emulate caches */ @@ -2297,7 +1478,7 @@ static void gen_spr_40x(CPUPPCState *env) } /* SPR specific to PowerPC 405 implementation */ -static void gen_spr_405(CPUPPCState *env) +static void register_405_sprs(CPUPPCState *env) { /* MMU */ spr_register(env, SPR_40x_PID, "PID", @@ -2399,11 +1580,11 @@ static void gen_spr_405(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, spr_read_generic, &spr_write_generic, 0x00000000); - gen_spr_usprgh(env); + register_usprgh_sprs(env); } /* SPR shared between PowerPC 401 & 403 implementations */ -static void gen_spr_401_403(CPUPPCState *env) +static void register_401_403_sprs(CPUPPCState *env) { /* Time base */ spr_register(env, SPR_403_VTBL, "TBL", @@ -2431,7 +1612,7 @@ static void gen_spr_401_403(CPUPPCState *env) } /* SPR specific to PowerPC 401 implementation */ -static void gen_spr_401(CPUPPCState *env) +static void register_401_sprs(CPUPPCState *env) { /* Debug interface */ /* XXX : not implemented */ @@ -2473,9 +1654,9 @@ static void gen_spr_401(CPUPPCState *env) 0x00000000); } -static void gen_spr_401x2(CPUPPCState *env) +static void register_401x2_sprs(CPUPPCState *env) { - gen_spr_401(env); + register_401_sprs(env); spr_register(env, SPR_40x_PID, "PID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2487,7 +1668,7 @@ static void gen_spr_401x2(CPUPPCState *env) } /* SPR specific to PowerPC 403 implementation */ -static void gen_spr_403(CPUPPCState *env) +static void register_403_sprs(CPUPPCState *env) { /* Debug interface */ /* XXX : not implemented */ @@ -2523,7 +1704,7 @@ static void gen_spr_403(CPUPPCState *env) 0x00000000); } -static void gen_spr_403_real(CPUPPCState *env) +static void register_403_real_sprs(CPUPPCState *env) { spr_register(env, SPR_403_PBL1, "PBL1", SPR_NOACCESS, SPR_NOACCESS, @@ -2543,7 +1724,7 @@ static void gen_spr_403_real(CPUPPCState *env) 0x00000000); } -static void gen_spr_403_mmu(CPUPPCState *env) +static void register_403_mmu_sprs(CPUPPCState *env) { /* MMU */ spr_register(env, SPR_40x_PID, "PID", @@ -2557,7 +1738,7 @@ static void gen_spr_403_mmu(CPUPPCState *env) } /* SPR specific to PowerPC compression coprocessor extension */ -static void gen_spr_compress(CPUPPCState *env) +static void register_compress_sprs(CPUPPCState *env) { /* XXX : not implemented */ spr_register(env, SPR_401_SKR, "SKR", @@ -2566,7 +1747,7 @@ static void gen_spr_compress(CPUPPCState *env) 0x00000000); } -static void gen_spr_5xx_8xx(CPUPPCState *env) +static void register_5xx_8xx_sprs(CPUPPCState *env) { /* Exception processing */ spr_register_kvm(env, SPR_DSISR, "DSISR", @@ -2684,7 +1865,7 @@ static void gen_spr_5xx_8xx(CPUPPCState *env) 0x00000000); } -static void gen_spr_5xx(CPUPPCState *env) +static void register_5xx_sprs(CPUPPCState *env) { /* XXX : not implemented */ spr_register(env, SPR_RCPU_MI_GRA, "MI_GRA", @@ -2793,7 +1974,7 @@ static void gen_spr_5xx(CPUPPCState *env) 0x00000000); } -static void gen_spr_8xx(CPUPPCState *env) +static void register_8xx_sprs(CPUPPCState *env) { /* XXX : not implemented */ spr_register(env, SPR_MPC_IC_CST, "IC_CST", @@ -3528,9 +2709,9 @@ static bool ppc_cpu_interrupts_big_endian_lpcr(PowerPCCPU *cpu) static void init_proc_401(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_401_sprs(env); init_excp_4xx_real(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3574,10 +2755,10 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) static void init_proc_401x2(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401x2(env); - gen_spr_compress(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_401x2_sprs(env); + register_compress_sprs(env); /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; @@ -3632,11 +2813,11 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) static void init_proc_401x3(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401(env); - gen_spr_401x2(env); - gen_spr_compress(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_401_sprs(env); + register_401x2_sprs(env); + register_compress_sprs(env); init_excp_4xx_softmmu(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3685,10 +2866,10 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) static void init_proc_IOP480(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401x2(env); - gen_spr_compress(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_401x2_sprs(env); + register_compress_sprs(env); /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; @@ -3743,10 +2924,10 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) static void init_proc_403(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_403(env); - gen_spr_403_real(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_403_sprs(env); + register_403_real_sprs(env); init_excp_4xx_real(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3790,11 +2971,11 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) static void init_proc_403GCX(CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_403(env); - gen_spr_403_real(env); - gen_spr_403_mmu(env); + register_40x_sprs(env); + register_401_403_sprs(env); + register_403_sprs(env); + register_403_real_sprs(env); + register_403_mmu_sprs(env); /* Bus access control */ /* not emulated, as QEMU never does speculative access */ spr_register(env, SPR_40x_SGR, "SGR", @@ -3858,9 +3039,9 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) static void init_proc_405(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_40x(env); - gen_spr_405(env); + register_tbl(env); + register_40x_sprs(env); + register_405_sprs(env); /* Bus access control */ /* not emulated, as QEMU never does speculative access */ spr_register(env, SPR_40x_SGR, "SGR", @@ -3924,10 +3105,10 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) static void init_proc_440EP(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_BookE(env, 0x000000000000FFFFULL); - gen_spr_440(env); - gen_spr_usprgh(env); + register_tbl(env); + register_BookE_sprs(env, 0x000000000000FFFFULL); + register_440_sprs(env); + register_usprgh_sprs(env); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, @@ -4066,10 +3247,10 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data) static void init_proc_440GP(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_BookE(env, 0x000000000000FFFFULL); - gen_spr_440(env); - gen_spr_usprgh(env); + register_tbl(env); + register_BookE_sprs(env, 0x000000000000FFFFULL); + register_440_sprs(env); + register_usprgh_sprs(env); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, @@ -4149,10 +3330,10 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) static void init_proc_440x4(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_BookE(env, 0x000000000000FFFFULL); - gen_spr_440(env); - gen_spr_usprgh(env); + register_tbl(env); + register_BookE_sprs(env, 0x000000000000FFFFULL); + register_440_sprs(env); + register_usprgh_sprs(env); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, @@ -4232,10 +3413,10 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) static void init_proc_440x5(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_BookE(env, 0x000000000000FFFFULL); - gen_spr_440(env); - gen_spr_usprgh(env); + register_tbl(env); + register_BookE_sprs(env, 0x000000000000FFFFULL); + register_440_sprs(env); + register_usprgh_sprs(env); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, @@ -4371,9 +3552,9 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data) static void init_proc_MPC5xx(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_5xx_8xx(env); - gen_spr_5xx(env); + register_tbl(env); + register_5xx_8xx_sprs(env); + register_5xx_sprs(env); init_excp_MPC5xx(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -4415,9 +3596,9 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) static void init_proc_MPC8xx(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_5xx_8xx(env); - gen_spr_8xx(env); + register_tbl(env); + register_5xx_8xx_sprs(env); + register_8xx_sprs(env); init_excp_MPC8xx(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -4459,12 +3640,12 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) static void init_proc_G2(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_G2_755(env); - gen_spr_G2(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_G2_755_sprs(env); + register_G2_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* External access control */ /* XXX : not implemented */ spr_register(env, SPR_EAR, "EAR", @@ -4488,9 +3669,9 @@ static void init_proc_G2(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_high_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_G2(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -4538,12 +3719,12 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) static void init_proc_G2LE(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_G2_755(env); - gen_spr_G2(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_G2_755_sprs(env); + register_G2_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* External access control */ /* XXX : not implemented */ spr_register(env, SPR_EAR, "EAR", @@ -4568,9 +3749,9 @@ static void init_proc_G2LE(CPUPPCState *env) 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_high_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_G2(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -4621,15 +3802,15 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) static void init_proc_e200(CPUPPCState *env) { /* Time base */ - gen_tbl(env); - gen_spr_BookE(env, 0x000000070000FFFFULL); + register_tbl(env); + register_BookE_sprs(env, 0x000000070000FFFFULL); /* XXX : not implemented */ spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR", &spr_read_spefscr, &spr_write_spefscr, &spr_read_spefscr, &spr_write_spefscr, 0x00000000); /* Memory management */ - gen_spr_BookE206(env, 0x0000005D, NULL, 0); + register_BookE206_sprs(env, 0x0000005D, NULL, 0); /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, @@ -4775,11 +3956,11 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) static void init_proc_e300(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_603(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_603_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -4823,9 +4004,9 @@ static void init_proc_e300(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_high_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_603(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -4873,31 +4054,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -#if !defined(CONFIG_USER_ONLY) -static void spr_write_mas73(DisasContext *ctx, int sprn, int gprn) -{ - TCGv val = tcg_temp_new(); - tcg_gen_ext32u_tl(val, cpu_gpr[gprn]); - gen_store_spr(SPR_BOOKE_MAS3, val); - tcg_gen_shri_tl(val, cpu_gpr[gprn], 32); - gen_store_spr(SPR_BOOKE_MAS7, val); - tcg_temp_free(val); -} - -static void spr_read_mas73(DisasContext *ctx, int gprn, int sprn) -{ - TCGv mas7 = tcg_temp_new(); - TCGv mas3 = tcg_temp_new(); - gen_load_spr(mas7, SPR_BOOKE_MAS7); - tcg_gen_shli_tl(mas7, mas7, 32); - gen_load_spr(mas3, SPR_BOOKE_MAS3); - tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7); - tcg_temp_free(mas3); - tcg_temp_free(mas7); -} - -#endif - enum fsl_e500_version { fsl_e500v1, fsl_e500v2, @@ -4921,11 +4077,11 @@ static void init_proc_e500(CPUPPCState *env, int version) #endif /* Time base */ - gen_tbl(env); + register_tbl(env); /* * XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't * complain when accessing them. - * gen_spr_BookE(env, 0x0000000F0000FD7FULL); + * register_BookE_sprs(env, 0x0000000F0000FD7FULL); */ switch (version) { case fsl_e500v1: @@ -4941,8 +4097,8 @@ static void init_proc_e500(CPUPPCState *env, int version) ivor_mask = 0x000003FF0000FFFFULL; break; } - gen_spr_BookE(env, ivor_mask); - gen_spr_usprg3(env); + register_BookE_sprs(env, ivor_mask); + register_usprg3_sprs(env); /* Processor identification */ spr_register(env, SPR_BOOKE_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, @@ -4960,17 +4116,17 @@ static void init_proc_e500(CPUPPCState *env, int version) env->id_tlbs = 0; switch (version) { case fsl_e500v1: - tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256); - tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); + tlbncfg[0] = register_tlbncfg(2, 1, 1, 0, 256); + tlbncfg[1] = register_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); break; case fsl_e500v2: - tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); - tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); + tlbncfg[0] = register_tlbncfg(4, 1, 1, 0, 512); + tlbncfg[1] = register_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); break; case fsl_e500mc: case fsl_e5500: - tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); - tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); + tlbncfg[0] = register_tlbncfg(4, 1, 1, 0, 512); + tlbncfg[1] = register_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64); break; case fsl_e6500: mmucfg = 0x6510B45; @@ -5007,7 +4163,7 @@ static void init_proc_e500(CPUPPCState *env, int version) cpu_abort(env_cpu(env), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); } - gen_spr_BookE206(env, 0x000000DF, tlbncfg, mmucfg); + register_BookE206_sprs(env, 0x000000DF, tlbncfg, mmucfg); /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, @@ -5365,9 +4521,9 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) static void init_proc_601(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_601(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_601_sprs(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5481,11 +4637,11 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) static void init_proc_602(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_602(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_602_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5498,8 +4654,8 @@ static void init_proc_602(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_602(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5551,11 +4707,11 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) static void init_proc_603(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_603(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_603_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5568,8 +4724,8 @@ static void init_proc_603(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_603(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5618,11 +4774,11 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) static void init_proc_603E(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_603(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_603_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5635,8 +4791,8 @@ static void init_proc_603E(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_603(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5685,11 +4841,11 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) static void init_proc_604(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_604(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_604_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5697,7 +4853,7 @@ static void init_proc_604(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); init_excp_604(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5749,9 +4905,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) static void init_proc_604E(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_604(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_604_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_7XX_MMCR1, "MMCR1", SPR_NOACCESS, SPR_NOACCESS, @@ -5768,7 +4924,7 @@ static void init_proc_604E(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5781,7 +4937,7 @@ static void init_proc_604E(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); init_excp_604(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5833,13 +4989,13 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) static void init_proc_740(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5852,7 +5008,7 @@ static void init_proc_740(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); init_excp_7x0(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5904,18 +5060,18 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) static void init_proc_750(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -5928,7 +5084,7 @@ static void init_proc_750(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); /* * XXX: high BATs are also present but are known to be bugged on * die version 1.x @@ -5984,16 +5140,16 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) static void init_proc_750cl(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ /* Those registers are fake on 750CL */ spr_register(env, SPR_THRM1, "THRM1", @@ -6094,9 +5250,9 @@ static void init_proc_750cl(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); /* PowerPC 750cl has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); + register_high_BATs(env); init_excp_750cl(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6187,18 +5343,18 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) static void init_proc_750cx(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* This register is not implemented but is present for compatibility */ spr_register(env, SPR_SDA, "SDA", SPR_NOACCESS, SPR_NOACCESS, @@ -6216,9 +5372,9 @@ static void init_proc_750cx(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); /* PowerPC 750cx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); + register_high_BATs(env); init_excp_750cx(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6270,18 +5426,18 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) static void init_proc_750fx(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_750_THRM4, "THRM4", SPR_NOACCESS, SPR_NOACCESS, @@ -6304,9 +5460,9 @@ static void init_proc_750fx(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); + register_high_BATs(env); init_excp_7x0(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6358,18 +5514,18 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) static void init_proc_750gx(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* XXX : not implemented (XXX: different from 750fx) */ spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* XXX : not implemented */ spr_register(env, SPR_750_THRM4, "THRM4", SPR_NOACCESS, SPR_NOACCESS, @@ -6392,9 +5548,9 @@ static void init_proc_750gx(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); + register_high_BATs(env); init_excp_7x0(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6446,14 +5602,14 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) static void init_proc_745(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); - gen_spr_G2_755(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); + register_G2_755_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -6471,9 +5627,9 @@ static void init_proc_745(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_high_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_7x5(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6522,12 +5678,12 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) static void init_proc_755(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); - gen_spr_G2_755(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); + register_G2_755_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* L2 cache control */ /* XXX : not implemented */ spr_register(env, SPR_L2CR, "L2CR", @@ -6540,7 +5696,7 @@ static void init_proc_755(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -6558,9 +5714,9 @@ static void init_proc_755(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); + register_low_BATs(env); + register_high_BATs(env); + register_6xx_7xx_soft_tlb(env, 64, 2); init_excp_7x5(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6609,13 +5765,13 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) static void init_proc_7400(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", @@ -6629,9 +5785,9 @@ static void init_proc_7400(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); init_excp_7400(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6689,13 +5845,13 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) static void init_proc_7410(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", @@ -6703,7 +5859,7 @@ static void init_proc_7410(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Thermal management */ - gen_spr_thrm(env); + register_thrm_sprs(env); /* L2PMCR */ /* XXX : not implemented */ spr_register(env, SPR_L2PMCR, "L2PMCR", @@ -6717,7 +5873,7 @@ static void init_proc_7410(CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ - gen_low_BATs(env); + register_low_BATs(env); init_excp_7400(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6775,13 +5931,13 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) static void init_proc_7440(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", @@ -6828,8 +5984,8 @@ static void init_proc_7440(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -6884,16 +6040,16 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) static void init_proc_7450(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ - gen_l3_ctrl(env); + register_l3_ctrl(env); /* L3ITCR1 */ /* XXX : not implemented */ spr_register(env, SPR_L3ITCR1, "L3ITCR1", @@ -6963,8 +6119,8 @@ static void init_proc_7450(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -7019,13 +6175,13 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) static void init_proc_7445(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* LDSTCR */ /* XXX : not implemented */ @@ -7100,9 +6256,9 @@ static void init_proc_7445(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_high_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -7157,16 +6313,16 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) static void init_proc_7455(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ - gen_l3_ctrl(env); + register_l3_ctrl(env); /* LDSTCR */ /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", @@ -7240,9 +6396,9 @@ static void init_proc_7455(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_high_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -7297,16 +6453,16 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) static void init_proc_7457(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* Level 3 cache control */ - gen_l3_ctrl(env); + register_l3_ctrl(env); /* L3ITCR1 */ /* XXX : not implemented */ spr_register(env, SPR_L3ITCR1, "L3ITCR1", @@ -7404,9 +6560,9 @@ static void init_proc_7457(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_high_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -7461,13 +6617,13 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) static void init_proc_e600(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_sdr1(env); - gen_spr_7xx(env); + register_ne_601_sprs(env); + register_sdr1_sprs(env); + register_7xx_sprs(env); /* Time base */ - gen_tbl(env); + register_tbl(env); /* 74xx specific SPR */ - gen_spr_74xx(env); + register_74xx_sprs(env); vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", @@ -7543,9 +6699,9 @@ static void init_proc_e600(CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_74xx_soft_tlb(env, 128, 2); + register_low_BATs(env); + register_high_BATs(env); + register_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -7609,58 +6765,6 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data) #define POWERPC970_HID5_INIT 0x00000000 #endif -static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn, - int bit, int sprn, int cause) -{ - TCGv_i32 t1 = tcg_const_i32(bit); - TCGv_i32 t2 = tcg_const_i32(sprn); - TCGv_i32 t3 = tcg_const_i32(cause); - - gen_helper_fscr_facility_check(cpu_env, t1, t2, t3); - - tcg_temp_free_i32(t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); -} - -static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn, - int bit, int sprn, int cause) -{ - TCGv_i32 t1 = tcg_const_i32(bit); - TCGv_i32 t2 = tcg_const_i32(sprn); - TCGv_i32 t3 = tcg_const_i32(cause); - - gen_helper_msr_facility_check(cpu_env, t1, t2, t3); - - tcg_temp_free_i32(t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t1); -} - -static void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn) -{ - TCGv spr_up = tcg_temp_new(); - TCGv spr = tcg_temp_new(); - - gen_load_spr(spr, sprn - 1); - tcg_gen_shri_tl(spr_up, spr, 32); - tcg_gen_ext32u_tl(cpu_gpr[gprn], spr_up); - - tcg_temp_free(spr); - tcg_temp_free(spr_up); -} - -static void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn) -{ - TCGv spr = tcg_temp_new(); - - gen_load_spr(spr, sprn - 1); - tcg_gen_deposit_tl(spr, spr, cpu_gpr[gprn], 32, 32); - gen_store_spr(sprn - 1, spr); - - tcg_temp_free(spr); -} - static int check_pow_970(CPUPPCState *env) { if (env->spr[SPR_HID0] & (HID0_DEEPNAP | HID0_DOZE | HID0_NAP)) { @@ -7670,7 +6774,7 @@ static int check_pow_970(CPUPPCState *env) return 0; } -static void gen_spr_970_hid(CPUPPCState *env) +static void register_970_hid_sprs(CPUPPCState *env) { /* Hardware implementation registers */ /* XXX : not implemented */ @@ -7688,7 +6792,7 @@ static void gen_spr_970_hid(CPUPPCState *env) POWERPC970_HID5_INIT); } -static void gen_spr_970_hior(CPUPPCState *env) +static void register_970_hior_sprs(CPUPPCState *env) { spr_register(env, SPR_HIOR, "SPR_HIOR", SPR_NOACCESS, SPR_NOACCESS, @@ -7696,7 +6800,7 @@ static void gen_spr_970_hior(CPUPPCState *env) 0x00000000); } -static void gen_spr_book3s_ctrl(CPUPPCState *env) +static void register_book3s_ctrl_sprs(CPUPPCState *env) { spr_register(env, SPR_CTRL, "SPR_CTRL", SPR_NOACCESS, SPR_NOACCESS, @@ -7708,7 +6812,7 @@ static void gen_spr_book3s_ctrl(CPUPPCState *env) 0x00000000); } -static void gen_spr_book3s_altivec(CPUPPCState *env) +static void register_book3s_altivec_sprs(CPUPPCState *env) { if (!(env->insns_flags & PPC_ALTIVEC)) { return; @@ -7721,7 +6825,7 @@ static void gen_spr_book3s_altivec(CPUPPCState *env) } -static void gen_spr_book3s_dbg(CPUPPCState *env) +static void register_book3s_dbg_sprs(CPUPPCState *env) { /* * TODO: different specs define different scopes for these, @@ -7740,7 +6844,7 @@ static void gen_spr_book3s_dbg(CPUPPCState *env) KVM_REG_PPC_DABRX, 0x00000000); } -static void gen_spr_book3s_207_dbg(CPUPPCState *env) +static void register_book3s_207_dbg_sprs(CPUPPCState *env) { spr_register_kvm_hv(env, SPR_DAWR0, "DAWR0", SPR_NOACCESS, SPR_NOACCESS, @@ -7759,7 +6863,7 @@ static void gen_spr_book3s_207_dbg(CPUPPCState *env) KVM_REG_PPC_CIABR, 0x00000000); } -static void gen_spr_970_dbg(CPUPPCState *env) +static void register_970_dbg_sprs(CPUPPCState *env) { /* Breakpoints */ spr_register(env, SPR_IABR, "IABR", @@ -7768,7 +6872,7 @@ static void gen_spr_970_dbg(CPUPPCState *env) 0x00000000); } -static void gen_spr_book3s_pmu_sup(CPUPPCState *env) +static void register_book3s_pmu_sup_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0", SPR_NOACCESS, SPR_NOACCESS, @@ -7816,7 +6920,7 @@ static void gen_spr_book3s_pmu_sup(CPUPPCState *env) KVM_REG_PPC_SDAR, 0x00000000); } -static void gen_spr_book3s_pmu_user(CPUPPCState *env) +static void register_book3s_pmu_user_sprs(CPUPPCState *env) { spr_register(env, SPR_POWER_UMMCR0, "UMMCR0", &spr_read_ureg, SPR_NOACCESS, @@ -7864,7 +6968,7 @@ static void gen_spr_book3s_pmu_user(CPUPPCState *env) 0x00000000); } -static void gen_spr_970_pmu_sup(CPUPPCState *env) +static void register_970_pmu_sup_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_970_PMC7, "PMC7", SPR_NOACCESS, SPR_NOACCESS, @@ -7876,7 +6980,7 @@ static void gen_spr_970_pmu_sup(CPUPPCState *env) KVM_REG_PPC_PMC8, 0x00000000); } -static void gen_spr_970_pmu_user(CPUPPCState *env) +static void register_970_pmu_user_sprs(CPUPPCState *env) { spr_register(env, SPR_970_UPMC7, "UPMC7", &spr_read_ureg, SPR_NOACCESS, @@ -7888,7 +6992,7 @@ static void gen_spr_970_pmu_user(CPUPPCState *env) 0x00000000); } -static void gen_spr_power8_pmu_sup(CPUPPCState *env) +static void register_power8_pmu_sup_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2", SPR_NOACCESS, SPR_NOACCESS, @@ -7924,7 +7028,7 @@ static void gen_spr_power8_pmu_sup(CPUPPCState *env) KVM_REG_PPC_CSIGR, 0x00000000); } -static void gen_spr_power8_pmu_user(CPUPPCState *env) +static void register_power8_pmu_user_sprs(CPUPPCState *env) { spr_register(env, SPR_POWER_UMMCR2, "UMMCR2", &spr_read_ureg, SPR_NOACCESS, @@ -7936,7 +7040,7 @@ static void gen_spr_power8_pmu_user(CPUPPCState *env) 0x00000000); } -static void gen_spr_power5p_ear(CPUPPCState *env) +static void register_power5p_ear_sprs(CPUPPCState *env) { /* External access control */ spr_register(env, SPR_EAR, "EAR", @@ -7945,7 +7049,7 @@ static void gen_spr_power5p_ear(CPUPPCState *env) 0x00000000); } -static void gen_spr_power5p_tb(CPUPPCState *env) +static void register_power5p_tb_sprs(CPUPPCState *env) { /* TBU40 (High 40 bits of the Timebase register */ spr_register_hv(env, SPR_TBU40, "TBU40", @@ -7955,25 +7059,7 @@ static void gen_spr_power5p_tb(CPUPPCState *env) 0x00000000); } -#if !defined(CONFIG_USER_ONLY) -static void spr_write_hmer(DisasContext *ctx, int sprn, int gprn) -{ - TCGv hmer = tcg_temp_new(); - - gen_load_spr(hmer, sprn); - tcg_gen_and_tl(hmer, cpu_gpr[gprn], hmer); - gen_store_spr(sprn, hmer); - spr_store_dump_spr(sprn); - tcg_temp_free(hmer); -} - -static void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn) -{ - gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]); -} -#endif /* !defined(CONFIG_USER_ONLY) */ - -static void gen_spr_970_lpar(CPUPPCState *env) +static void register_970_lpar_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* @@ -7990,7 +7076,7 @@ static void gen_spr_970_lpar(CPUPPCState *env) #endif } -static void gen_spr_power5p_lpar(CPUPPCState *env) +static void register_power5p_lpar_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Logical partitionning */ @@ -8006,7 +7092,7 @@ static void gen_spr_power5p_lpar(CPUPPCState *env) #endif } -static void gen_spr_book3s_ids(CPUPPCState *env) +static void register_book3s_ids_sprs(CPUPPCState *env) { /* FIXME: Will need to deal with thread vs core only SPRs */ @@ -8098,7 +7184,7 @@ static void gen_spr_book3s_ids(CPUPPCState *env) 0x00000000); } -static void gen_spr_rmor(CPUPPCState *env) +static void register_rmor_sprs(CPUPPCState *env) { spr_register_hv(env, SPR_RMOR, "RMOR", SPR_NOACCESS, SPR_NOACCESS, @@ -8107,7 +7193,7 @@ static void gen_spr_rmor(CPUPPCState *env) 0x00000000); } -static void gen_spr_power8_ids(CPUPPCState *env) +static void register_power8_ids_sprs(CPUPPCState *env) { /* Thread identification */ spr_register(env, SPR_TIR, "TIR", @@ -8116,7 +7202,7 @@ static void gen_spr_power8_ids(CPUPPCState *env) 0x00000000); } -static void gen_spr_book3s_purr(CPUPPCState *env) +static void register_book3s_purr_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ @@ -8133,7 +7219,7 @@ static void gen_spr_book3s_purr(CPUPPCState *env) #endif } -static void gen_spr_power6_dbg(CPUPPCState *env) +static void register_power6_dbg_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_CFAR, "SPR_CFAR", @@ -8143,7 +7229,7 @@ static void gen_spr_power6_dbg(CPUPPCState *env) #endif } -static void gen_spr_power5p_common(CPUPPCState *env) +static void register_power5p_common_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_PPR, "PPR", &spr_read_generic, &spr_write_generic, @@ -8151,7 +7237,7 @@ static void gen_spr_power5p_common(CPUPPCState *env) KVM_REG_PPC_PPR, 0x00000000); } -static void gen_spr_power6_common(CPUPPCState *env) +static void register_power6_common_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register_kvm(env, SPR_DSCR, "SPR_DSCR", @@ -8170,19 +7256,7 @@ static void gen_spr_power6_common(CPUPPCState *env) 0x00000000); } -static void spr_read_tar(DisasContext *ctx, int gprn, int sprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); - spr_read_generic(ctx, gprn, sprn); -} - -static void spr_write_tar(DisasContext *ctx, int sprn, int gprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); - spr_write_generic(ctx, sprn, gprn); -} - -static void gen_spr_power8_tce_address_control(CPUPPCState *env) +static void register_power8_tce_address_control_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_TAR, "TAR", &spr_read_tar, &spr_write_tar, @@ -8190,31 +7264,7 @@ static void gen_spr_power8_tce_address_control(CPUPPCState *env) KVM_REG_PPC_TAR, 0x00000000); } -static void spr_read_tm(DisasContext *ctx, int gprn, int sprn) -{ - gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); - spr_read_generic(ctx, gprn, sprn); -} - -static void spr_write_tm(DisasContext *ctx, int sprn, int gprn) -{ - gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); - spr_write_generic(ctx, sprn, gprn); -} - -static void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn) -{ - gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); - spr_read_prev_upper32(ctx, gprn, sprn); -} - -static void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn) -{ - gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); - spr_write_prev_upper32(ctx, sprn, gprn); -} - -static void gen_spr_power8_tm(CPUPPCState *env) +static void register_power8_tm_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_TFHAR, "TFHAR", &spr_read_tm, &spr_write_tm, @@ -8234,31 +7284,7 @@ static void gen_spr_power8_tm(CPUPPCState *env) 0x00000000); } -static void spr_read_ebb(DisasContext *ctx, int gprn, int sprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); - spr_read_generic(ctx, gprn, sprn); -} - -static void spr_write_ebb(DisasContext *ctx, int sprn, int gprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); - spr_write_generic(ctx, sprn, gprn); -} - -static void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); - spr_read_prev_upper32(ctx, gprn, sprn); -} - -static void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn) -{ - gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); - spr_write_prev_upper32(ctx, sprn, gprn); -} - -static void gen_spr_power8_ebb(CPUPPCState *env) +static void register_power8_ebb_sprs(CPUPPCState *env) { spr_register(env, SPR_BESCRS, "BESCRS", &spr_read_ebb, &spr_write_ebb, @@ -8291,7 +7317,7 @@ static void gen_spr_power8_ebb(CPUPPCState *env) } /* Virtual Time Base */ -static void gen_spr_vtb(CPUPPCState *env) +static void register_vtb_sprs(CPUPPCState *env) { spr_register_kvm_hv(env, SPR_VTB, "VTB", SPR_NOACCESS, SPR_NOACCESS, @@ -8300,7 +7326,7 @@ static void gen_spr_vtb(CPUPPCState *env) KVM_REG_PPC_VTB, 0x00000000); } -static void gen_spr_power8_fscr(CPUPPCState *env) +static void register_power8_fscr_sprs(CPUPPCState *env) { #if defined(CONFIG_USER_ONLY) target_ulong initval = 1ULL << FSCR_TAR; @@ -8313,7 +7339,7 @@ static void gen_spr_power8_fscr(CPUPPCState *env) KVM_REG_PPC_FSCR, initval); } -static void gen_spr_power8_pspb(CPUPPCState *env) +static void register_power8_pspb_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_PSPB, "PSPB", SPR_NOACCESS, SPR_NOACCESS, @@ -8321,7 +7347,7 @@ static void gen_spr_power8_pspb(CPUPPCState *env) KVM_REG_PPC_PSPB, 0); } -static void gen_spr_power8_dpdes(CPUPPCState *env) +static void register_power8_dpdes_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Directed Privileged Door-bell Exception State, used for IPI */ @@ -8333,7 +7359,7 @@ static void gen_spr_power8_dpdes(CPUPPCState *env) #endif } -static void gen_spr_power8_ic(CPUPPCState *env) +static void register_power8_ic_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register_hv(env, SPR_IC, "IC", @@ -8344,7 +7370,7 @@ static void gen_spr_power8_ic(CPUPPCState *env) #endif } -static void gen_spr_power8_book4(CPUPPCState *env) +static void register_power8_book4_sprs(CPUPPCState *env) { /* Add a number of P8 book4 registers */ #if !defined(CONFIG_USER_ONLY) @@ -8363,7 +7389,7 @@ static void gen_spr_power8_book4(CPUPPCState *env) #endif } -static void gen_spr_power7_book4(CPUPPCState *env) +static void register_power7_book4_sprs(CPUPPCState *env) { /* Add a number of P7 book4 registers */ #if !defined(CONFIG_USER_ONLY) @@ -8378,7 +7404,7 @@ static void gen_spr_power7_book4(CPUPPCState *env) #endif } -static void gen_spr_power8_rpr(CPUPPCState *env) +static void register_power8_rpr_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) spr_register_hv(env, SPR_RPR, "RPR", @@ -8389,7 +7415,7 @@ static void gen_spr_power8_rpr(CPUPPCState *env) #endif } -static void gen_spr_power9_mmu(CPUPPCState *env) +static void register_power9_mmu_sprs(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Partition Table Control */ @@ -8409,13 +7435,13 @@ static void gen_spr_power9_mmu(CPUPPCState *env) static void init_proc_book3s_common(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_tbl(env); - gen_spr_usprg3(env); - gen_spr_book3s_altivec(env); - gen_spr_book3s_pmu_sup(env); - gen_spr_book3s_pmu_user(env); - gen_spr_book3s_ctrl(env); + register_ne_601_sprs(env); + register_tbl(env); + register_usprg3_sprs(env); + register_book3s_altivec_sprs(env); + register_book3s_pmu_sup_sprs(env); + register_book3s_pmu_user_sprs(env); + register_book3s_ctrl_sprs(env); /* * Can't find information on what this should be on reset. This * value is the one used by 74xx processors. @@ -8427,17 +7453,17 @@ static void init_proc_970(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_sdr1(env); - gen_spr_book3s_dbg(env); + register_sdr1_sprs(env); + register_book3s_dbg_sprs(env); /* 970 Specific Registers */ - gen_spr_970_hid(env); - gen_spr_970_hior(env); - gen_low_BATs(env); - gen_spr_970_pmu_sup(env); - gen_spr_970_pmu_user(env); - gen_spr_970_lpar(env); - gen_spr_970_dbg(env); + register_970_hid_sprs(env); + register_970_hior_sprs(env); + register_low_BATs(env); + register_970_pmu_sup_sprs(env); + register_970_pmu_user_sprs(env); + register_970_lpar_sprs(env); + register_970_dbg_sprs(env); /* env variables */ env->dcache_line_size = 128; @@ -8500,19 +7526,19 @@ static void init_proc_power5plus(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_sdr1(env); - gen_spr_book3s_dbg(env); + register_sdr1_sprs(env); + register_book3s_dbg_sprs(env); /* POWER5+ Specific Registers */ - gen_spr_970_hid(env); - gen_spr_970_hior(env); - gen_low_BATs(env); - gen_spr_970_pmu_sup(env); - gen_spr_970_pmu_user(env); - gen_spr_power5p_common(env); - gen_spr_power5p_lpar(env); - gen_spr_power5p_ear(env); - gen_spr_power5p_tb(env); + register_970_hid_sprs(env); + register_970_hior_sprs(env); + register_low_BATs(env); + register_970_pmu_sup_sprs(env); + register_970_pmu_user_sprs(env); + register_power5p_common_sprs(env); + register_power5p_lpar_sprs(env); + register_power5p_ear_sprs(env); + register_power5p_tb_sprs(env); /* env variables */ env->dcache_line_size = 128; @@ -8579,21 +7605,21 @@ static void init_proc_POWER7(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_sdr1(env); - gen_spr_book3s_dbg(env); + register_sdr1_sprs(env); + register_book3s_dbg_sprs(env); /* POWER7 Specific Registers */ - gen_spr_book3s_ids(env); - gen_spr_rmor(env); - gen_spr_amr(env); - gen_spr_book3s_purr(env); - gen_spr_power5p_common(env); - gen_spr_power5p_lpar(env); - gen_spr_power5p_ear(env); - gen_spr_power5p_tb(env); - gen_spr_power6_common(env); - gen_spr_power6_dbg(env); - gen_spr_power7_book4(env); + register_book3s_ids_sprs(env); + register_rmor_sprs(env); + register_amr_sprs(env); + register_book3s_purr_sprs(env); + register_power5p_common_sprs(env); + register_power5p_lpar_sprs(env); + register_power5p_ear_sprs(env); + register_power5p_tb_sprs(env); + register_power6_common_sprs(env); + register_power6_dbg_sprs(env); + register_power7_book4_sprs(env); /* env variables */ env->dcache_line_size = 128; @@ -8725,34 +7751,34 @@ static void init_proc_POWER8(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_sdr1(env); - gen_spr_book3s_207_dbg(env); + register_sdr1_sprs(env); + register_book3s_207_dbg_sprs(env); /* POWER8 Specific Registers */ - gen_spr_book3s_ids(env); - gen_spr_rmor(env); - gen_spr_amr(env); - gen_spr_iamr(env); - gen_spr_book3s_purr(env); - gen_spr_power5p_common(env); - gen_spr_power5p_lpar(env); - gen_spr_power5p_ear(env); - gen_spr_power5p_tb(env); - gen_spr_power6_common(env); - gen_spr_power6_dbg(env); - gen_spr_power8_tce_address_control(env); - gen_spr_power8_ids(env); - gen_spr_power8_ebb(env); - gen_spr_power8_fscr(env); - gen_spr_power8_pmu_sup(env); - gen_spr_power8_pmu_user(env); - gen_spr_power8_tm(env); - gen_spr_power8_pspb(env); - gen_spr_power8_dpdes(env); - gen_spr_vtb(env); - gen_spr_power8_ic(env); - gen_spr_power8_book4(env); - gen_spr_power8_rpr(env); + register_book3s_ids_sprs(env); + register_rmor_sprs(env); + register_amr_sprs(env); + register_iamr_sprs(env); + register_book3s_purr_sprs(env); + register_power5p_common_sprs(env); + register_power5p_lpar_sprs(env); + register_power5p_ear_sprs(env); + register_power5p_tb_sprs(env); + register_power6_common_sprs(env); + register_power6_dbg_sprs(env); + register_power8_tce_address_control_sprs(env); + register_power8_ids_sprs(env); + register_power8_ebb_sprs(env); + register_power8_fscr_sprs(env); + register_power8_pmu_sup_sprs(env); + register_power8_pmu_user_sprs(env); + register_power8_tm_sprs(env); + register_power8_pspb_sprs(env); + register_power8_dpdes_sprs(env); + register_vtb_sprs(env); + register_power8_ic_sprs(env); + register_power8_book4_sprs(env); + register_power8_rpr_sprs(env); /* env variables */ env->dcache_line_size = 128; @@ -8922,33 +7948,33 @@ static void init_proc_POWER9(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_book3s_207_dbg(env); + register_book3s_207_dbg_sprs(env); /* POWER8 Specific Registers */ - gen_spr_book3s_ids(env); - gen_spr_amr(env); - gen_spr_iamr(env); - gen_spr_book3s_purr(env); - gen_spr_power5p_common(env); - gen_spr_power5p_lpar(env); - gen_spr_power5p_ear(env); - gen_spr_power5p_tb(env); - gen_spr_power6_common(env); - gen_spr_power6_dbg(env); - gen_spr_power8_tce_address_control(env); - gen_spr_power8_ids(env); - gen_spr_power8_ebb(env); - gen_spr_power8_fscr(env); - gen_spr_power8_pmu_sup(env); - gen_spr_power8_pmu_user(env); - gen_spr_power8_tm(env); - gen_spr_power8_pspb(env); - gen_spr_power8_dpdes(env); - gen_spr_vtb(env); - gen_spr_power8_ic(env); - gen_spr_power8_book4(env); - gen_spr_power8_rpr(env); - gen_spr_power9_mmu(env); + register_book3s_ids_sprs(env); + register_amr_sprs(env); + register_iamr_sprs(env); + register_book3s_purr_sprs(env); + register_power5p_common_sprs(env); + register_power5p_lpar_sprs(env); + register_power5p_ear_sprs(env); + register_power5p_tb_sprs(env); + register_power6_common_sprs(env); + register_power6_dbg_sprs(env); + register_power8_tce_address_control_sprs(env); + register_power8_ids_sprs(env); + register_power8_ebb_sprs(env); + register_power8_fscr_sprs(env); + register_power8_pmu_sup_sprs(env); + register_power8_pmu_user_sprs(env); + register_power8_tm_sprs(env); + register_power8_pspb_sprs(env); + register_power8_dpdes_sprs(env); + register_vtb_sprs(env); + register_power8_ic_sprs(env); + register_power8_book4_sprs(env); + register_power8_rpr_sprs(env); + register_power9_mmu_sprs(env); /* POWER9 Specific registers */ spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL, @@ -9140,31 +8166,31 @@ static void init_proc_POWER10(CPUPPCState *env) { /* Common Registers */ init_proc_book3s_common(env); - gen_spr_book3s_207_dbg(env); + register_book3s_207_dbg_sprs(env); /* POWER8 Specific Registers */ - gen_spr_book3s_ids(env); - gen_spr_amr(env); - gen_spr_iamr(env); - gen_spr_book3s_purr(env); - gen_spr_power5p_common(env); - gen_spr_power5p_lpar(env); - gen_spr_power5p_ear(env); - gen_spr_power6_common(env); - gen_spr_power6_dbg(env); - gen_spr_power8_tce_address_control(env); - gen_spr_power8_ids(env); - gen_spr_power8_ebb(env); - gen_spr_power8_fscr(env); - gen_spr_power8_pmu_sup(env); - gen_spr_power8_pmu_user(env); - gen_spr_power8_tm(env); - gen_spr_power8_pspb(env); - gen_spr_vtb(env); - gen_spr_power8_ic(env); - gen_spr_power8_book4(env); - gen_spr_power8_rpr(env); - gen_spr_power9_mmu(env); + register_book3s_ids_sprs(env); + register_amr_sprs(env); + register_iamr_sprs(env); + register_book3s_purr_sprs(env); + register_power5p_common_sprs(env); + register_power5p_lpar_sprs(env); + register_power5p_ear_sprs(env); + register_power6_common_sprs(env); + register_power6_dbg_sprs(env); + register_power8_tce_address_control_sprs(env); + register_power8_ids_sprs(env); + register_power8_ebb_sprs(env); + register_power8_fscr_sprs(env); + register_power8_pmu_sup_sprs(env); + register_power8_pmu_user_sprs(env); + register_power8_tm_sprs(env); + register_power8_pspb_sprs(env); + register_vtb_sprs(env); + register_power8_ic_sprs(env); + register_power8_book4_sprs(env); + register_power8_rpr_sprs(env); + register_power9_mmu_sprs(env); /* FIXME: Filter fields properly based on privilege level */ spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL, @@ -9369,7 +8395,7 @@ static void init_ppc_proc(PowerPCCPU *cpu) env->tlb_type = TLB_NONE; #endif /* Register SPR common to all PowerPC implementations */ - gen_spr_generic(env); + register_generic_sprs(env); spr_register(env, SPR_PVR, "PVR", /* Linux permits userspace to read PVR */ #if defined(CONFIG_LINUX_USER) @@ -10342,4 +9368,186 @@ static void ppc_cpu_register_types(void) #endif } +void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ +#define RGPL 4 +#define RFPL 4 + + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + int i; + + qemu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " + TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n", + env->nip, env->lr, env->ctr, cpu_read_xer(env), + cs->cpu_index); + qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " + "%08x iidx %d didx %d\n", + env->msr, env->spr[SPR_HID0], env->hflags, + cpu_mmu_index(env, true), cpu_mmu_index(env, false)); +#if !defined(NO_TIMER_DUMP) + qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 +#if !defined(CONFIG_USER_ONLY) + " DECR " TARGET_FMT_lu +#endif + "\n", + cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) +#if !defined(CONFIG_USER_ONLY) + , cpu_ppc_load_decr(env) +#endif + ); +#endif + for (i = 0; i < 32; i++) { + if ((i & (RGPL - 1)) == 0) { + qemu_fprintf(f, "GPR%02d", i); + } + qemu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i)); + if ((i & (RGPL - 1)) == (RGPL - 1)) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "CR "); + for (i = 0; i < 8; i++) + qemu_fprintf(f, "%01x", env->crf[i]); + qemu_fprintf(f, " ["); + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) { + a = 'L'; + } else if (env->crf[i] & 0x04) { + a = 'G'; + } else if (env->crf[i] & 0x02) { + a = 'E'; + } + qemu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + } + qemu_fprintf(f, " ] RES " TARGET_FMT_lx "\n", + env->reserve_addr); + + if (flags & CPU_DUMP_FPU) { + for (i = 0; i < 32; i++) { + if ((i & (RFPL - 1)) == 0) { + qemu_fprintf(f, "FPR%02d", i); + } + qemu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i)); + if ((i & (RFPL - 1)) == (RFPL - 1)) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr); + } + +#if !defined(CONFIG_USER_ONLY) + qemu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx + " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n", + env->spr[SPR_SRR0], env->spr[SPR_SRR1], + env->spr[SPR_PVR], env->spr[SPR_VRSAVE]); + + qemu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx + " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n", + env->spr[SPR_SPRG0], env->spr[SPR_SPRG1], + env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]); + + qemu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx + " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n", + env->spr[SPR_SPRG4], env->spr[SPR_SPRG5], + env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]); + +#if defined(TARGET_PPC64) + if (env->excp_model == POWERPC_EXCP_POWER7 || + env->excp_model == POWERPC_EXCP_POWER8 || + env->excp_model == POWERPC_EXCP_POWER9 || + env->excp_model == POWERPC_EXCP_POWER10) { + qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); + } +#endif + if (env->excp_model == POWERPC_EXCP_BOOKE) { + qemu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx + " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], + env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); + + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx + " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR], + env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]); + + qemu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx + " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR], + env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]); + + qemu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx + " EPR " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8], + env->spr[SPR_BOOKE_EPR]); + + /* FSL-specific */ + qemu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx + " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n", + env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1], + env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]); + + /* + * IVORs are left out as they are large and do not change often -- + * they can be read with "p $ivor0", "p $ivor1", etc. + */ + } + +#if defined(TARGET_PPC64) + if (env->flags & POWERPC_FLAG_CFAR) { + qemu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar); + } +#endif + + if (env->spr_cb[SPR_LPCR].name) { + qemu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); + } + + switch (env->mmu_model) { + case POWERPC_MMU_32B: + case POWERPC_MMU_601: + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: +#if defined(TARGET_PPC64) + case POWERPC_MMU_64B: + case POWERPC_MMU_2_03: + case POWERPC_MMU_2_06: + case POWERPC_MMU_2_07: + case POWERPC_MMU_3_00: +#endif + if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */ + qemu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]); + } + if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */ + qemu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]); + } + qemu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n", + env->spr[SPR_DAR], env->spr[SPR_DSISR]); + break; + case POWERPC_MMU_BOOKE206: + qemu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx + " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], + env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]); + + qemu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx + " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n", + env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6], + env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]); + + qemu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx + " TLB1CFG " TARGET_FMT_lx "\n", + env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG], + env->spr[SPR_BOOKE_TLB1CFG]); + break; + default: + break; + } +#endif + +#undef RGPL +#undef RFPL +} type_init(ppc_cpu_register_types) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 94a7273ee0..9339e7eafe 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -498,7 +498,7 @@ static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n) return 16; } if (n == 32) { - gdb_get_reg32(buf, helper_mfvscr(env)); + gdb_get_reg32(buf, ppc_get_vscr(env)); mem_buf = gdb_get_reg_ptr(buf, 4); ppc_maybe_bswap_register(env, mem_buf, 4); return 4; @@ -529,7 +529,7 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) } if (n == 32) { ppc_maybe_bswap_register(env, mem_buf, 4); - helper_mtvscr(env, ldl_p(mem_buf)); + ppc_store_vscr(env, ldl_p(mem_buf)); return 4; } if (n == 33) { diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 513066d54d..ea9f2a236c 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -1,5 +1,5 @@ -DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, void, env, i32, i32) -DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, void, env, i32) +DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, noreturn, env, i32, i32) +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32) DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index a44c2d90ea..41f8477d4b 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -462,17 +462,12 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX) void helper_mtvscr(CPUPPCState *env, uint32_t vscr) { - env->vscr = vscr & ~(1u << VSCR_SAT); - /* Which bit we set is completely arbitrary, but clear the rest. */ - env->vscr_sat.u64[0] = vscr & (1u << VSCR_SAT); - env->vscr_sat.u64[1] = 0; - set_flush_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status); + ppc_store_vscr(env, vscr); } uint32_t helper_mfvscr(CPUPPCState *env) { - uint32_t sat = (env->vscr_sat.u64[0] | env->vscr_sat.u64[1]) != 0; - return env->vscr | (sat << VSCR_SAT); + return ppc_get_vscr(env); } static inline void set_vscr_sat(CPUPPCState *env) diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 184ba6d6b3..2b4b06eb76 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -228,4 +228,23 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu); void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); gchar *ppc_gdb_arch_name(CPUState *cs); +/** + * prot_for_access_type: + * @access_type: Access type + * + * Return the protection bit required for the given access type. + */ +static inline int prot_for_access_type(MMUAccessType access_type) +{ + switch (access_type) { + case MMU_INST_FETCH: + return PAGE_EXEC; + case MMU_DATA_LOAD: + return PAGE_READ; + case MMU_DATA_STORE: + return PAGE_WRITE; + } + g_assert_not_reached(); +} + #endif /* PPC_INTERNAL_H */ diff --git a/target/ppc/machine.c b/target/ppc/machine.c index e5bffbe365..93972df58e 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -8,7 +8,6 @@ #include "qapi/error.h" #include "qemu/main-loop.h" #include "kvm_ppc.h" -#include "exec/helper-proto.h" static void post_load_update_msr(CPUPPCState *env) { @@ -107,7 +106,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) ppc_store_sdr1(env, sdr1); } qemu_get_be32s(f, &vscr); - helper_mtvscr(env, vscr); + ppc_store_vscr(env, vscr); qemu_get_be64s(f, &env->spe_acc); qemu_get_be32s(f, &env->spe_fscr); qemu_get_betls(f, &env->msr_mask); @@ -456,7 +455,7 @@ static int get_vscr(QEMUFile *f, void *opaque, size_t size, const VMStateField *field) { PowerPCCPU *cpu = opaque; - helper_mtvscr(&cpu->env, qemu_get_be32(f)); + ppc_store_vscr(&cpu->env, qemu_get_be32(f)); return 0; } @@ -464,7 +463,7 @@ static int put_vscr(QEMUFile *f, void *opaque, size_t size, const VMStateField *field, JSONWriter *vmdesc) { PowerPCCPU *cpu = opaque; - qemu_put_be32(f, helper_mfvscr(&cpu->env)); + qemu_put_be32(f, ppc_get_vscr(&cpu->env)); return 0; } diff --git a/target/ppc/meson.build b/target/ppc/meson.build index 4079d01ee3..d1aa7d5d39 100644 --- a/target/ppc/meson.build +++ b/target/ppc/meson.build @@ -2,6 +2,7 @@ ppc_ss = ss.source_set() ppc_ss.add(files( 'cpu-models.c', 'cpu.c', + 'cpu_init.c', 'dfp_helper.c', 'excp_helper.c', 'fpu_helper.c', diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 002958be26..08a31da289 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -261,6 +261,16 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) hreg_store_msr(env, value, 0); } +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + + env->spr[SPR_LPCR] = val & pcc->lpcr_mask; + /* The gtse bit affects hflags */ + hreg_compute_hflags(env); +} + /* * This code is lifted from MacOnLinux. It is called whenever THRM1,2 * or 3 is read an fixes up the values in such a way that will make diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 178cf090b7..744a763f44 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" +#include "internal.h" #include "mmu-hash32.h" #include "exec/log.h" @@ -152,16 +153,17 @@ static int hash32_bat_601_prot(PowerPCCPU *cpu, return ppc_hash32_pp_prot(key, pp, 0); } -static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx, - int *prot) +static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, + MMUAccessType access_type, int *prot) { CPUPPCState *env = &cpu->env; target_ulong *BATlt, *BATut; + bool ifetch = access_type == MMU_INST_FETCH; int i; LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, - rwx == 2 ? 'I' : 'D', ea); - if (rwx == 2) { + ifetch ? 'I' : 'D', ea); + if (ifetch) { BATlt = env->IBAT[1]; BATut = env->IBAT[0]; } else { @@ -180,7 +182,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx, } LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl); + ifetch ? 'I' : 'D', i, ea, batu, batl); if (mask && ((ea & mask) == (batu & BATU32_BEPI))) { hwaddr raddr = (batl & mask) | (ea & ~mask); @@ -208,7 +210,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx, LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx "\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea, + __func__, ifetch ? 'I' : 'D', i, ea, *BATu, *BATl, BEPIu, BEPIl, bl); } } @@ -218,7 +220,8 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx, } static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, - target_ulong eaddr, int rwx, + target_ulong eaddr, + MMUAccessType access_type, hwaddr *raddr, int *prot) { CPUState *cs = CPU(cpu); @@ -239,7 +242,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, return 0; } - if (rwx == 2) { + if (access_type == MMU_INST_FETCH) { /* No code fetch is allowed in direct-store areas */ cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x10000000; @@ -260,7 +263,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, /* lwarx, ldarx or srwcx. */ env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x06000000; } else { env->spr[SPR_DSISR] = 0x04000000; @@ -280,7 +283,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x06100000; } else { env->spr[SPR_DSISR] = 0x04100000; @@ -290,14 +293,15 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr, cpu_abort(cs, "ERROR: instruction should not need " "address translation\n"); } - if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) { + if ((access_type == MMU_DATA_STORE || key != 1) && + (access_type == MMU_DATA_LOAD || key != 0)) { *raddr = eaddr; return 0; } else { cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x0a000000; } else { env->spr[SPR_DSISR] = 0x08000000; @@ -421,13 +425,16 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, hwaddr pte_offset; ppc_hash_pte32_t pte; int prot; - const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; + int need_prot; + MMUAccessType access_type; hwaddr raddr; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + access_type = rwx; + need_prot = prot_for_access_type(access_type); /* 1. Handle real mode accesses */ - if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + if (access_type == MMU_INST_FETCH ? !msr_ir : !msr_dr) { /* Translation is off */ raddr = eaddr; tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, @@ -438,17 +445,17 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* 2. Check Block Address Translation entries (BATs) */ if (env->nb_BATs != 0) { - raddr = ppc_hash32_bat_lookup(cpu, eaddr, rwx, &prot); + raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, &prot); if (raddr != -1) { - if (need_prot[rwx] & ~prot) { - if (rwx == 2) { + if (need_prot & ~prot) { + if (access_type == MMU_INST_FETCH) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x08000000; } else { cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x0a000000; } else { env->spr[SPR_DSISR] = 0x08000000; @@ -469,7 +476,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* 4. Handle direct store segments */ if (sr & SR32_T) { - if (ppc_hash32_direct_store(cpu, sr, eaddr, rwx, + if (ppc_hash32_direct_store(cpu, sr, eaddr, access_type, &raddr, &prot) == 0) { tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, prot, mmu_idx, @@ -481,7 +488,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, } /* 5. Check for segment level no-execute violation */ - if ((rwx == 2) && (sr & SR32_NX)) { + if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x10000000; return 1; @@ -490,14 +497,14 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* 6. Locate the PTE in the hash table */ pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte); if (pte_offset == -1) { - if (rwx == 2) { + if (access_type == MMU_INST_FETCH) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; } else { cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x42000000; } else { env->spr[SPR_DSISR] = 0x40000000; @@ -513,17 +520,17 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, prot = ppc_hash32_pte_prot(cpu, sr, pte); - if (need_prot[rwx] & ~prot) { + if (need_prot & ~prot) { /* Access right violation */ qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); - if (rwx == 2) { + if (access_type == MMU_INST_FETCH) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x08000000; } else { cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = eaddr; - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x0a000000; } else { env->spr[SPR_DSISR] = 0x08000000; @@ -540,7 +547,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, ppc_hash32_set_r(cpu, pte_offset, pte.pte1); } if (!(pte.pte1 & HPTE32_R_C)) { - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { ppc_hash32_set_c(cpu, pte_offset, pte.pte1); } else { /* diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index d517a99832..f48b625f48 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -29,6 +29,7 @@ #include "mmu-hash64.h" #include "exec/log.h" #include "hw/hw.h" +#include "internal.h" #include "mmu-book3s-v3.h" #include "helper_regs.h" @@ -876,10 +877,12 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, hwaddr ptex; ppc_hash_pte64_t pte; int exec_prot, pp_prot, amr_prot, prot; - const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; + MMUAccessType access_type; + int need_prot; hwaddr raddr; assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + access_type = rwx; /* * Note on LPCR usage: 970 uses HID4, but our special variant of @@ -890,7 +893,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, */ /* 1. Handle real mode accesses */ - if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + if (access_type == MMU_INST_FETCH ? !msr_ir : !msr_dr) { /* * Translation is supposedly "off", but in real mode the top 4 * effective address bits are (mostly) ignored @@ -923,14 +926,19 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, /* Emulated old-style RMO mode, bounds check against RMLS */ if (raddr >= limit) { - if (rwx == 2) { + switch (access_type) { + case MMU_INST_FETCH: ppc_hash64_set_isi(cs, SRR1_PROTFAULT); - } else { - int dsisr = DSISR_PROTFAULT; - if (rwx == 1) { - dsisr |= DSISR_ISSTORE; - } - ppc_hash64_set_dsi(cs, eaddr, dsisr); + break; + case MMU_DATA_LOAD: + ppc_hash64_set_dsi(cs, eaddr, DSISR_PROTFAULT); + break; + case MMU_DATA_STORE: + ppc_hash64_set_dsi(cs, eaddr, + DSISR_PROTFAULT | DSISR_ISSTORE); + break; + default: + g_assert_not_reached(); } return 1; } @@ -953,13 +961,19 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, exit(1); } /* Segment still not found, generate the appropriate interrupt */ - if (rwx == 2) { + switch (access_type) { + case MMU_INST_FETCH: cs->exception_index = POWERPC_EXCP_ISEG; env->error_code = 0; - } else { + break; + case MMU_DATA_LOAD: + case MMU_DATA_STORE: cs->exception_index = POWERPC_EXCP_DSEG; env->error_code = 0; env->spr[SPR_DAR] = eaddr; + break; + default: + g_assert_not_reached(); } return 1; } @@ -967,7 +981,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, skip_slb_search: /* 3. Check for segment level no-execute violation */ - if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) { + if (access_type == MMU_INST_FETCH && (slb->vsid & SLB_VSID_N)) { ppc_hash64_set_isi(cs, SRR1_NOEXEC_GUARD); return 1; } @@ -975,14 +989,18 @@ skip_slb_search: /* 4. Locate the PTE in the hash table */ ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift); if (ptex == -1) { - if (rwx == 2) { + switch (access_type) { + case MMU_INST_FETCH: ppc_hash64_set_isi(cs, SRR1_NOPTE); - } else { - int dsisr = DSISR_NOPTE; - if (rwx == 1) { - dsisr |= DSISR_ISSTORE; - } - ppc_hash64_set_dsi(cs, eaddr, dsisr); + break; + case MMU_DATA_LOAD: + ppc_hash64_set_dsi(cs, eaddr, DSISR_NOPTE); + break; + case MMU_DATA_STORE: + ppc_hash64_set_dsi(cs, eaddr, DSISR_NOPTE | DSISR_ISSTORE); + break; + default: + g_assert_not_reached(); } return 1; } @@ -996,10 +1014,11 @@ skip_slb_search: amr_prot = ppc_hash64_amr_prot(cpu, pte); prot = exec_prot & pp_prot & amr_prot; - if ((need_prot[rwx] & ~prot) != 0) { + need_prot = prot_for_access_type(access_type); + if (need_prot & ~prot) { /* Access right violation */ qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); - if (rwx == 2) { + if (access_type == MMU_INST_FETCH) { int srr1 = 0; if (PAGE_EXEC & ~exec_prot) { srr1 |= SRR1_NOEXEC_GUARD; /* Access violates noexec or guard */ @@ -1012,13 +1031,13 @@ skip_slb_search: ppc_hash64_set_isi(cs, srr1); } else { int dsisr = 0; - if (need_prot[rwx] & ~pp_prot) { + if (need_prot & ~pp_prot) { dsisr |= DSISR_PROTFAULT; } - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { dsisr |= DSISR_ISSTORE; } - if (need_prot[rwx] & ~amr_prot) { + if (need_prot & ~amr_prot) { dsisr |= DSISR_AMR; } ppc_hash64_set_dsi(cs, eaddr, dsisr); @@ -1034,7 +1053,7 @@ skip_slb_search: ppc_hash64_set_r(cpu, ptex, pte.pte1); } if (!(pte.pte1 & HPTE64_R_C)) { - if (rwx == 1) { + if (access_type == MMU_DATA_STORE) { ppc_hash64_set_c(cpu, ptex, pte.pte1); } else { /* @@ -1120,16 +1139,6 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex, cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH; } -void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) -{ - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUPPCState *env = &cpu->env; - - env->spr[SPR_LPCR] = val & pcc->lpcr_mask; - /* The gtse bit affects hflags */ - hreg_compute_hflags(env); -} - void helper_store_lpcr(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = env_archcpu(env); @@ -1200,61 +1209,4 @@ const PPCHash64Options ppc_hash64_opts_POWER7 = { } }; -void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, - bool (*cb)(void *, uint32_t, uint32_t), - void *opaque) -{ - PPCHash64Options *opts = cpu->hash64_opts; - int i; - int n = 0; - bool ci_largepage = false; - - assert(opts); - - n = 0; - for (i = 0; i < ARRAY_SIZE(opts->sps); i++) { - PPCHash64SegmentPageSizes *sps = &opts->sps[i]; - int j; - int m = 0; - assert(n <= i); - - if (!sps->page_shift) { - break; - } - - for (j = 0; j < ARRAY_SIZE(sps->enc); j++) { - PPCHash64PageSize *ps = &sps->enc[j]; - - assert(m <= j); - if (!ps->page_shift) { - break; - } - - if (cb(opaque, sps->page_shift, ps->page_shift)) { - if (ps->page_shift >= 16) { - ci_largepage = true; - } - sps->enc[m++] = *ps; - } - } - - /* Clear rest of the row */ - for (j = m; j < ARRAY_SIZE(sps->enc); j++) { - memset(&sps->enc[j], 0, sizeof(sps->enc[j])); - } - - if (m) { - n++; - } - } - - /* Clear the rest of the table */ - for (i = n; i < ARRAY_SIZE(opts->sps); i++) { - memset(&opts->sps[i], 0, sizeof(opts->sps[i])); - } - - if (!ci_largepage) { - opts->flags &= ~PPC_HASH64_CI_LARGEPAGE; - } -} diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index 87729d48b3..4b8b8e7950 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -15,12 +15,8 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong pte0, target_ulong pte1); unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu, uint64_t pte0, uint64_t pte1); -void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_hash64_init(PowerPCCPU *cpu); void ppc_hash64_finalize(PowerPCCPU *cpu); -void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu, - bool (*cb)(void *, uint32_t, uint32_t), - void *opaque); #endif /* diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 30fcfcf11f..7972153f23 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -25,6 +25,7 @@ #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "exec/log.h" +#include "internal.h" #include "mmu-radix64.h" #include "mmu-book3s-v3.h" @@ -74,71 +75,94 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env, return true; } -static void ppc_radix64_raise_segi(PowerPCCPU *cpu, int rwx, vaddr eaddr) +static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type, + vaddr eaddr) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - if (rwx == 2) { /* Instruction Segment Interrupt */ + switch (access_type) { + case MMU_INST_FETCH: + /* Instruction Segment Interrupt */ cs->exception_index = POWERPC_EXCP_ISEG; - } else { /* Data Segment Interrupt */ + break; + case MMU_DATA_STORE: + case MMU_DATA_LOAD: + /* Data Segment Interrupt */ cs->exception_index = POWERPC_EXCP_DSEG; env->spr[SPR_DAR] = eaddr; + break; + default: + g_assert_not_reached(); } env->error_code = 0; } -static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, - uint32_t cause) +static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type, + vaddr eaddr, uint32_t cause) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - if (rwx == 2) { /* Instruction Storage Interrupt */ + switch (access_type) { + case MMU_INST_FETCH: + /* Instruction Storage Interrupt */ cs->exception_index = POWERPC_EXCP_ISI; env->error_code = cause; - } else { /* Data Storage Interrupt */ + break; + case MMU_DATA_STORE: + cause |= DSISR_ISSTORE; + /* fall through */ + case MMU_DATA_LOAD: + /* Data Storage Interrupt */ cs->exception_index = POWERPC_EXCP_DSI; - if (rwx == 1) { /* Write -> Store */ - cause |= DSISR_ISSTORE; - } env->spr[SPR_DSISR] = cause; env->spr[SPR_DAR] = eaddr; env->error_code = 0; + break; + default: + g_assert_not_reached(); } } -static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr, - hwaddr g_raddr, uint32_t cause) +static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type, + vaddr eaddr, hwaddr g_raddr, uint32_t cause) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - if (rwx == 2) { /* H Instruction Storage Interrupt */ + switch (access_type) { + case MMU_INST_FETCH: + /* H Instruction Storage Interrupt */ cs->exception_index = POWERPC_EXCP_HISI; env->spr[SPR_ASDR] = g_raddr; env->error_code = cause; - } else { /* H Data Storage Interrupt */ + break; + case MMU_DATA_STORE: + cause |= DSISR_ISSTORE; + /* fall through */ + case MMU_DATA_LOAD: + /* H Data Storage Interrupt */ cs->exception_index = POWERPC_EXCP_HDSI; - if (rwx == 1) { /* Write -> Store */ - cause |= DSISR_ISSTORE; - } env->spr[SPR_HDSISR] = cause; env->spr[SPR_HDAR] = eaddr; env->spr[SPR_ASDR] = g_raddr; env->error_code = 0; + break; + default: + g_assert_not_reached(); } } -static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, - int *fault_cause, int *prot, +static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type, + uint64_t pte, int *fault_cause, int *prot, bool partition_scoped) { CPUPPCState *env = &cpu->env; - const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC }; + int need_prot; /* Check Page Attributes (pte58:59) */ - if (((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO) && (rwx == 2)) { + if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) { /* * Radix PTE entries with the non-idempotent I/O attribute are treated * as guarded storage @@ -158,7 +182,8 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, } /* Check if requested access type is allowed */ - if (need_prot[rwx] & ~(*prot)) { /* Page Protected for that Access */ + need_prot = prot_for_access_type(access_type); + if (need_prot & ~*prot) { /* Page Protected for that Access */ *fault_cause |= DSISR_PROTFAULT; return true; } @@ -166,15 +191,15 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, return false; } -static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte, - hwaddr pte_addr, int *prot) +static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type, + uint64_t pte, hwaddr pte_addr, int *prot) { CPUState *cs = CPU(cpu); uint64_t npte; npte = pte | R_PTE_R; /* Always set reference bit */ - if (rwx == 1) { /* Store/Write */ + if (access_type == MMU_DATA_STORE) { /* Store/Write */ npte |= R_PTE_C; /* Set change bit */ } else { /* @@ -269,7 +294,8 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) return true; } -static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, +static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, + MMUAccessType access_type, vaddr eaddr, hwaddr g_raddr, ppc_v3_pate_t pate, hwaddr *h_raddr, int *h_prot, @@ -285,24 +311,25 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx, if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB, pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size, &pte, &fault_cause, &pte_addr) || - ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) { + ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, h_prot, true)) { if (pde_addr) { /* address being translated was that of a guest pde */ fault_cause |= DSISR_PRTABLE_FAULT; } if (guest_visible) { - ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause); + ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause); } return 1; } if (guest_visible) { - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot); + ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot); } return 0; } -static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, +static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, + MMUAccessType access_type, vaddr eaddr, uint64_t pid, ppc_v3_pate_t pate, hwaddr *g_raddr, int *g_prot, int *g_page_size, @@ -321,7 +348,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, if (offset >= size) { /* offset exceeds size of the process table */ if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE); } return 1; } @@ -362,7 +389,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, if (ret) { /* No valid PTE */ if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause); } return ret; } @@ -391,7 +418,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, if (ret) { /* No valid pte */ if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause); } return ret; } @@ -405,16 +432,16 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, *g_raddr = (rpn & ~mask) | (eaddr & mask); } - if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) { + if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, g_prot, false)) { /* Access denied due to protection */ if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause); } return 1; } if (guest_visible) { - ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot); + ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot); } return 0; @@ -437,7 +464,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx, * | = On | Process Scoped | Scoped | * +-------------+----------------+---------------+ */ -static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, +static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, + MMUAccessType access_type, bool relocation, hwaddr *raddr, int *psizep, int *protp, bool guest_visible) @@ -451,7 +479,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, /* Virtual Mode Access - get the fully qualified address */ if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) { if (guest_visible) { - ppc_radix64_raise_segi(cpu, rwx, eaddr); + ppc_radix64_raise_segi(cpu, access_type, eaddr); } return 1; } @@ -464,13 +492,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, } else { if (!ppc64_v3_get_pate(cpu, lpid, &pate)) { if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE); } return 1; } if (!validate_pate(cpu, lpid, &pate)) { if (guest_visible) { - ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG); + ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG); } return 1; } @@ -488,7 +516,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, * - Translates an effective address to a guest real address. */ if (relocation) { - int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid, + int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid, pate, &g_raddr, &prot, &psize, guest_visible); if (ret) { @@ -511,9 +539,10 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx, if (lpid || !msr_hv) { int ret; - ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr, - pate, raddr, &prot, &psize, - false, guest_visible); + ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr, + g_raddr, pate, raddr, + &prot, &psize, false, + guest_visible); if (ret) { return ret; } @@ -534,12 +563,14 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, CPUPPCState *env = &cpu->env; int page_size, prot; bool relocation; + MMUAccessType access_type; hwaddr raddr; assert(!(msr_hv && cpu->vhyp)); assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + access_type = rwx; - relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1)); + relocation = (access_type == MMU_INST_FETCH ? msr_ir : msr_dr); /* HV or virtual hypervisor Real Mode Access */ if (!relocation && (msr_hv || cpu->vhyp)) { /* In real mode top 4 effective addr bits (mostly) ignored */ @@ -568,7 +599,7 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, } /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */ - if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr, + if (ppc_radix64_xlate(cpu, eaddr, access_type, relocation, &raddr, &page_size, &prot, true)) { return 1; } diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index ca88658cba..37986c59ba 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -32,6 +32,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/qemu-print.h" +#include "internal.h" #include "mmu-book3s-v3.h" #include "mmu-radix64.h" @@ -126,36 +127,14 @@ static int pp_check(int key, int pp, int nx) return access; } -static int check_prot(int prot, int rw, int access_type) +static int check_prot(int prot, MMUAccessType access_type) { - int ret; - - if (access_type == ACCESS_CODE) { - if (prot & PAGE_EXEC) { - ret = 0; - } else { - ret = -2; - } - } else if (rw) { - if (prot & PAGE_WRITE) { - ret = 0; - } else { - ret = -2; - } - } else { - if (prot & PAGE_READ) { - ret = 0; - } else { - ret = -2; - } - } - - return ret; + return prot & prot_for_access_type(access_type) ? 0 : -2; } -static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, - int rw, int type) +static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, + MMUAccessType access_type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; @@ -182,7 +161,7 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, /* Keep the matching PTE information */ ctx->raddr = pte1; ctx->prot = access; - ret = check_prot(ctx->prot, rw, type); + ret = check_prot(ctx->prot, access_type); if (ret == 0) { /* Access granted */ qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); @@ -197,7 +176,7 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, } static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, - int ret, int rw) + int ret, MMUAccessType access_type) { int store = 0; @@ -208,7 +187,7 @@ static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, store = 1; } if (!(*pte1p & 0x00000080)) { - if (rw == 1 && ret == 0) { + if (access_type == MMU_DATA_STORE && ret == 0) { /* Update changed flag */ *pte1p |= 0x00000080; store = 1; @@ -308,8 +287,8 @@ static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, env->last_way = way; } -static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) +static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, MMUAccessType access_type) { ppc6xx_tlb_t *tlb; int nr, best, way; @@ -318,8 +297,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, best = -1; ret = -1; /* No TLB found */ for (way = 0; way < env->nb_ways; way++) { - nr = ppc6xx_tlb_getnum(env, eaddr, way, - access_type == ACCESS_CODE ? 1 : 0); + nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH); tlb = &env->tlb.tlb6[nr]; /* This test "emulates" the PTE index match for hardware TLBs */ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { @@ -333,9 +311,10 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb, pte_is_valid(tlb->pte0) ? "valid" : "inval", tlb->EPN, eaddr, tlb->pte1, - rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); + access_type == MMU_DATA_STORE ? 'S' : 'L', + access_type == MMU_INST_FETCH ? 'I' : 'D'); switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, - 0, rw, access_type)) { + 0, access_type)) { case -3: /* TLB inconsistency */ return -1; @@ -366,7 +345,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx, LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); /* Update page flags */ - pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw); + pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type); } return ret; @@ -400,24 +379,22 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, } static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong virtual, int rw, int type) + target_ulong virtual, MMUAccessType access_type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong BEPIl, BEPIu, bl; int i, valid, prot; int ret = -1; + bool ifetch = access_type == MMU_INST_FETCH; LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); - switch (type) { - case ACCESS_CODE: + ifetch ? 'I' : 'D', virtual); + if (ifetch) { BATlt = env->IBAT[1]; BATut = env->IBAT[0]; - break; - default: + } else { BATlt = env->DBAT[1]; BATut = env->DBAT[0]; - break; } for (i = 0; i < env->nb_BATs; i++) { BATu = &BATut[i]; @@ -427,7 +404,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); + ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl); if ((virtual & 0xF0000000) == BEPIu && ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { /* BAT matches */ @@ -438,7 +415,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, (virtual & 0x0001F000); /* Compute access rights */ ctx->prot = prot; - ret = check_prot(ctx->prot, rw, type); + ret = check_prot(ctx->prot, access_type); if (ret == 0) { LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', @@ -461,7 +438,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx "\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + __func__, ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl); } } @@ -472,8 +449,9 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, } /* Perform segment based translation */ -static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int type) +static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, MMUAccessType access_type, + int type) { PowerPCCPU *cpu = env_archcpu(env); hwaddr hash; @@ -497,7 +475,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, - (int)msr_dr, pr != 0 ? 1 : 0, rw, type); + (int)msr_dr, pr != 0 ? 1 : 0, access_type == MMU_DATA_STORE, type); pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; hash = vsid ^ pgidx; ctx->ptem = (vsid << 7) | (pgidx >> 10); @@ -520,7 +498,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, /* Initialize real address with an invalid value */ ctx->raddr = (hwaddr)-1ULL; /* Software TLB search */ - ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); + ret = ppc6xx_tlb_check(env, ctx, eaddr, access_type); #if defined(DUMP_PAGE_TABLES) if (qemu_loglevel_mask(CPU_LOG_MMU)) { CPUState *cs = env_cpu(env); @@ -603,7 +581,8 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, "address translation\n"); return -4; } - if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) { + if ((access_type == MMU_DATA_STORE || ctx->key != 1) && + (access_type == MMU_DATA_LOAD || ctx->key != 0)) { ctx->raddr = eaddr; ret = 2; } else { @@ -682,8 +661,8 @@ static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env) } static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) + target_ulong address, + MMUAccessType access_type) { ppcemb_tlb_t *tlb; hwaddr raddr; @@ -700,8 +679,8 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, } zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3; - LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", - __func__, i, zsel, zpr, rw, tlb->attr); + LOG_SWTLB("%s: TLB %d zsel %d zpr %d ty %d attr %08x\n", + __func__, i, zsel, zpr, access_type, tlb->attr); /* Check execute enable bit */ switch (zpr) { case 0x2: @@ -727,7 +706,7 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, check_perms: /* Check from TLB entry */ ctx->prot = tlb->prot; - ret = check_prot(ctx->prot, rw, access_type); + ret = check_prot(ctx->prot, access_type); if (ret == -2) { env->spr[SPR_40x_ESR] = 0; } @@ -757,12 +736,11 @@ void store_40x_sler(CPUPPCState *env, uint32_t val) env->spr[SPR_405_SLER] = val; } -static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, - hwaddr *raddr, int *prot, - target_ulong address, int rw, - int access_type, int i) +static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb, + hwaddr *raddr, int *prot, target_ulong address, + MMUAccessType access_type, int i) { - int ret, prot2; + int prot2; if (ppcemb_tlb_check(env, tlb, raddr, address, env->spr[SPR_BOOKE_PID], @@ -794,42 +772,24 @@ found_tlb: } /* Check the address space */ - if (access_type == ACCESS_CODE) { - if (msr_ir != (tlb->attr & 1)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if (prot2 & PAGE_EXEC) { - LOG_SWTLB("%s: good TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); - ret = -3; - } else { - if (msr_dr != (tlb->attr & 1)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { - LOG_SWTLB("%s: found TLB!\n", __func__); - return 0; - } + if ((access_type == MMU_INST_FETCH ? msr_ir : msr_dr) != (tlb->attr & 1)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); - ret = -2; + *prot = prot2; + if (prot2 & prot_for_access_type(access_type)) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; } - return ret; + LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2); + return access_type == MMU_INST_FETCH ? -3 : -2; } static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) + target_ulong address, + MMUAccessType access_type) { ppcemb_tlb_t *tlb; hwaddr raddr; @@ -839,7 +799,7 @@ static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, raddr = (hwaddr)-1ULL; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb.tlbe[i]; - ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, + ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, access_type, i); if (ret != -1) { break; @@ -938,10 +898,10 @@ static bool is_epid_mmu(int mmu_idx) return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD; } -static uint32_t mmubooke206_esr(int mmu_idx, bool rw) +static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type) { uint32_t esr = 0; - if (rw) { + if (access_type == MMU_DATA_STORE) { esr |= ESR_ST; } if (is_epid_mmu(mmu_idx)) { @@ -983,10 +943,9 @@ static bool mmubooke206_get_as(CPUPPCState *env, /* Check if the tlb found by hashing really matches */ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddr, int *prot, - target_ulong address, int rw, - int access_type, int mmu_idx) + target_ulong address, + MMUAccessType access_type, int mmu_idx) { - int ret; int prot2 = 0; uint32_t epid; bool as, pr; @@ -1043,44 +1002,31 @@ found_tlb: } /* Check the address space and permissions */ - if (access_type == ACCESS_CODE) { + if (access_type == MMU_INST_FETCH) { /* There is no way to fetch code using epid load */ assert(!use_epid); - if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } - - *prot = prot2; - if (prot2 & PAGE_EXEC) { - LOG_SWTLB("%s: good TLB!\n", __func__); - return 0; - } - - LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); - ret = -3; - } else { - if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { - LOG_SWTLB("%s: AS doesn't match\n", __func__); - return -1; - } + as = msr_ir; + } - *prot = prot2; - if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) { - LOG_SWTLB("%s: found TLB!\n", __func__); - return 0; - } + if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } - LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2); - ret = -2; + *prot = prot2; + if (prot2 & prot_for_access_type(access_type)) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; } - return ret; + LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2); + return access_type == MMU_INST_FETCH ? -3 : -2; } static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type, int mmu_idx) + target_ulong address, + MMUAccessType access_type, + int mmu_idx) { ppcmas_tlb_t *tlb; hwaddr raddr; @@ -1098,7 +1044,7 @@ static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, continue; } ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, - rw, access_type, mmu_idx); + access_type, mmu_idx); if (ret != -1) { goto found_tlb; } @@ -1361,8 +1307,8 @@ void dump_mmu(CPUPPCState *env) } } -static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw) +static int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr, + MMUAccessType access_type) { int in_plb, ret; @@ -1393,7 +1339,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; if (in_plb ^ msr_px) { /* Access in protected area */ - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { /* Access is not allowed */ ret = -2; } @@ -1413,28 +1359,28 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -static int get_physical_address_wtlb( - CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type, - int mmu_idx) +static int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, + MMUAccessType access_type, int type, + int mmu_idx) { int ret = -1; - bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0) - || (access_type != ACCESS_CODE && msr_dr == 0); + bool real_mode = (type == ACCESS_CODE && msr_ir == 0) + || (type != ACCESS_CODE && msr_dr == 0); switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: if (real_mode) { - ret = check_physical(env, ctx, eaddr, rw); + ret = check_physical(env, ctx, eaddr, access_type); } else { /* Try to find a BAT */ if (env->nb_BATs != 0) { - ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type); + ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type); } if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ - ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type); + ret = get_segment_6xx_tlb(env, ctx, eaddr, access_type, type); } } break; @@ -1442,19 +1388,17 @@ static int get_physical_address_wtlb( case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: if (real_mode) { - ret = check_physical(env, ctx, eaddr, rw); + ret = check_physical(env, ctx, eaddr, access_type); } else { - ret = mmu40x_get_physical_address(env, ctx, eaddr, - rw, access_type); + ret = mmu40x_get_physical_address(env, ctx, eaddr, access_type); } break; case POWERPC_MMU_BOOKE: - ret = mmubooke_get_physical_address(env, ctx, eaddr, - rw, access_type); + ret = mmubooke_get_physical_address(env, ctx, eaddr, access_type); break; case POWERPC_MMU_BOOKE206: - ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type, mmu_idx); + ret = mmubooke206_get_physical_address(env, ctx, eaddr, access_type, + mmu_idx); break; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1462,7 +1406,7 @@ static int get_physical_address_wtlb( break; case POWERPC_MMU_REAL: if (real_mode) { - ret = check_physical(env, ctx, eaddr, rw); + ret = check_physical(env, ctx, eaddr, access_type); } else { cpu_abort(env_cpu(env), "PowerPC in real mode do not do any translation\n"); @@ -1476,11 +1420,11 @@ static int get_physical_address_wtlb( return ret; } -static int get_physical_address( - CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) +static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, MMUAccessType access_type, + int type) { - return get_physical_address_wtlb(env, ctx, eaddr, rw, access_type, 0); + return get_physical_address_wtlb(env, ctx, eaddr, access_type, type, 0); } hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) @@ -1508,14 +1452,15 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) ; } - if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) { + if (unlikely(get_physical_address(env, &ctx, addr, MMU_DATA_LOAD, + ACCESS_INT) != 0)) { /* * Some MMUs have separate TLBs for code and data. If we only * try an ACCESS_INT, we may not be able to read instructions * mapped by code TLBs, so we also try a ACCESS_CODE. */ - if (unlikely(get_physical_address(env, &ctx, addr, 0, + if (unlikely(get_physical_address(env, &ctx, addr, MMU_INST_FETCH, ACCESS_CODE) != 0)) { return -1; } @@ -1525,13 +1470,14 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, - int rw, int mmu_idx) + MMUAccessType access_type, int mmu_idx) { uint32_t epid; bool as, pr; uint32_t missed_tid = 0; bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); - if (rw == 2) { + + if (access_type == MMU_INST_FETCH) { as = msr_ir; } env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; @@ -1579,24 +1525,23 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, /* Perform address translation */ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, - int rw, int mmu_idx) + MMUAccessType access_type, int mmu_idx) { CPUState *cs = env_cpu(env); PowerPCCPU *cpu = POWERPC_CPU(cs); mmu_ctx_t ctx; - int access_type; + int type; int ret = 0; - if (rw == 2) { + if (access_type == MMU_INST_FETCH) { /* code access */ - rw = 0; - access_type = ACCESS_CODE; + type = ACCESS_CODE; } else { /* data access */ - access_type = env->access_type; + type = env->access_type; } - ret = get_physical_address_wtlb(env, &ctx, address, rw, - access_type, mmu_idx); + ret = get_physical_address_wtlb(env, &ctx, address, access_type, + type, mmu_idx); if (ret == 0) { tlb_set_page(cs, address & TARGET_PAGE_MASK, ctx.raddr & TARGET_PAGE_MASK, ctx.prot, @@ -1604,7 +1549,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, ret = 0; } else if (ret < 0) { LOG_MMU_STATE(cs); - if (access_type == ACCESS_CODE) { + if (type == ACCESS_CODE) { switch (ret) { case -1: /* No matches in page tables or TLB */ @@ -1632,7 +1577,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cs->exception_index = POWERPC_EXCP_ITLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 0); + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, MMU_DATA_LOAD); return -1; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1674,7 +1619,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { cs->exception_index = POWERPC_EXCP_DSTLB; env->error_code = 1 << 16; } else { @@ -1691,7 +1636,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, get_pteg_offset32(cpu, ctx.hash[1]); break; case POWERPC_MMU_SOFT_74xx: - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { cs->exception_index = POWERPC_EXCP_DSTLB; } else { cs->exception_index = POWERPC_EXCP_DLTLB; @@ -1708,7 +1653,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cs->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_40x_DEAR] = address; - if (rw) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_40x_ESR] = 0x00800000; } else { env->spr[SPR_40x_ESR] = 0x00000000; @@ -1719,13 +1664,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cpu_abort(cs, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, rw, mmu_idx); + booke206_update_mas_tlb_miss(env, address, access_type, mmu_idx); /* fall through */ case POWERPC_MMU_BOOKE: cs->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type); return -1; case POWERPC_MMU_REAL: cpu_abort(cs, "PowerPC in real mode should never raise " @@ -1743,16 +1688,16 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, if (env->mmu_model == POWERPC_MMU_SOFT_4xx || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) { env->spr[SPR_40x_DEAR] = address; - if (rw) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_40x_ESR] |= 0x00800000; } } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type); } else { env->spr[SPR_DAR] = address; - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x0A000000; } else { env->spr[SPR_DSISR] = 0x08000000; @@ -1761,7 +1706,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, break; case -4: /* Direct store exception */ - switch (access_type) { + switch (type) { case ACCESS_FLOAT: /* Floating point load/store */ cs->exception_index = POWERPC_EXCP_ALIGN; @@ -1773,7 +1718,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = address; - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x06000000; } else { env->spr[SPR_DSISR] = 0x04000000; @@ -1784,7 +1729,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cs->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; env->spr[SPR_DAR] = address; - if (rw == 1) { + if (access_type == MMU_DATA_STORE) { env->spr[SPR_DSISR] = 0x06100000; } else { env->spr[SPR_DSISR] = 0x04100000; @@ -2085,32 +2030,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) /*****************************************************************************/ /* Special registers manipulation */ -void ppc_store_sdr1(CPUPPCState *env, target_ulong value) -{ - PowerPCCPU *cpu = env_archcpu(env); - qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); - assert(!cpu->vhyp); -#if defined(TARGET_PPC64) - if (mmu_is_64bit(env->mmu_model)) { - target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE; - target_ulong htabsize = value & SDR_64_HTABSIZE; - - if (value & ~sdr_mask) { - error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1", - value & ~sdr_mask); - value &= sdr_mask; - } - if (htabsize > 28) { - error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1", - htabsize); - return; - } - } -#endif /* defined(TARGET_PPC64) */ - /* FIXME: Should check for valid HTABMASK values in 32-bit case */ - env->spr[SPR_SDR1] = value; -} - #if defined(TARGET_PPC64) void ppc_store_ptcr(CPUPPCState *env, target_ulong value) { diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h new file mode 100644 index 0000000000..0be5f347d5 --- /dev/null +++ b/target/ppc/spr_tcg.h @@ -0,0 +1,136 @@ +/* + * PowerPC emulation for qemu: read/write callbacks for SPRs + * + * Copyright (C) 2021 Instituto de Pesquisas Eldorado + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef SPR_TCG_H +#define SPR_TCG_H + +#define SPR_NOACCESS (&spr_noaccess) + +/* prototypes for readers and writers for SPRs */ +void spr_noaccess(DisasContext *ctx, int gprn, int sprn); +void spr_read_generic(DisasContext *ctx, int gprn, int sprn); +void spr_write_generic(DisasContext *ctx, int sprn, int gprn); +void spr_read_xer(DisasContext *ctx, int gprn, int sprn); +void spr_write_xer(DisasContext *ctx, int sprn, int gprn); +void spr_read_lr(DisasContext *ctx, int gprn, int sprn); +void spr_write_lr(DisasContext *ctx, int sprn, int gprn); +void spr_read_ctr(DisasContext *ctx, int gprn, int sprn); +void spr_write_ctr(DisasContext *ctx, int sprn, int gprn); +void spr_read_ureg(DisasContext *ctx, int gprn, int sprn); +void spr_read_tbl(DisasContext *ctx, int gprn, int sprn); +void spr_read_tbu(DisasContext *ctx, int gprn, int sprn); +void spr_read_atbl(DisasContext *ctx, int gprn, int sprn); +void spr_read_atbu(DisasContext *ctx, int gprn, int sprn); +void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn); +void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn); +void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn); +void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn); + +#ifndef CONFIG_USER_ONLY +void spr_write_generic32(DisasContext *ctx, int sprn, int gprn); +void spr_write_clear(DisasContext *ctx, int sprn, int gprn); +void spr_access_nop(DisasContext *ctx, int sprn, int gprn); +void spr_read_decr(DisasContext *ctx, int gprn, int sprn); +void spr_write_decr(DisasContext *ctx, int sprn, int gprn); +void spr_write_tbl(DisasContext *ctx, int sprn, int gprn); +void spr_write_tbu(DisasContext *ctx, int sprn, int gprn); +void spr_write_atbl(DisasContext *ctx, int sprn, int gprn); +void spr_write_atbu(DisasContext *ctx, int sprn, int gprn); +void spr_read_ibat(DisasContext *ctx, int gprn, int sprn); +void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn); +void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn); +void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn); +void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn); +void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn); +void spr_read_dbat(DisasContext *ctx, int gprn, int sprn); +void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn); +void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn); +void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn); +void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn); +void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn); +void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn); +void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn); +void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn); +void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn); +void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn); +void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn); +void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn); +void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn); +void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn); +void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn); +void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn); +void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn); +void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn); +void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn); +void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn); +void spr_write_pir(DisasContext *ctx, int sprn, int gprn); +void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn); +void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn); +void spr_read_thrm(DisasContext *ctx, int gprn, int sprn); +void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn); +void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn); +void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn); +void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn); +void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn); +void spr_write_eplc(DisasContext *ctx, int sprn, int gprn); +void spr_write_epsc(DisasContext *ctx, int sprn, int gprn); +void spr_write_mas73(DisasContext *ctx, int sprn, int gprn); +void spr_read_mas73(DisasContext *ctx, int gprn, int sprn); +#ifdef TARGET_PPC64 +void spr_read_cfar(DisasContext *ctx, int gprn, int sprn); +void spr_write_cfar(DisasContext *ctx, int sprn, int gprn); +void spr_write_ureg(DisasContext *ctx, int sprn, int gprn); +void spr_read_purr(DisasContext *ctx, int gprn, int sprn); +void spr_write_purr(DisasContext *ctx, int sprn, int gprn); +void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn); +void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn); +void spr_read_vtb(DisasContext *ctx, int gprn, int sprn); +void spr_write_vtb(DisasContext *ctx, int sprn, int gprn); +void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn); +void spr_write_pidr(DisasContext *ctx, int sprn, int gprn); +void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn); +void spr_read_hior(DisasContext *ctx, int gprn, int sprn); +void spr_write_hior(DisasContext *ctx, int sprn, int gprn); +void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn); +void spr_write_pcr(DisasContext *ctx, int sprn, int gprn); +void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn); +void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn); +void spr_write_amr(DisasContext *ctx, int sprn, int gprn); +void spr_write_uamor(DisasContext *ctx, int sprn, int gprn); +void spr_write_iamr(DisasContext *ctx, int sprn, int gprn); +#endif +#endif + +#ifdef TARGET_PPC64 +void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn); +void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn); +void spr_read_tar(DisasContext *ctx, int gprn, int sprn); +void spr_write_tar(DisasContext *ctx, int sprn, int gprn); +void spr_read_tm(DisasContext *ctx, int gprn, int sprn); +void spr_write_tm(DisasContext *ctx, int sprn, int gprn); +void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn); +void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn); +void spr_read_ebb(DisasContext *ctx, int gprn, int sprn); +void spr_write_ebb(DisasContext *ctx, int sprn, int gprn); +void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn); +void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn); +void spr_write_hmer(DisasContext *ctx, int sprn, int gprn); +void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn); +#endif + +#endif diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a6381208a5..ea200f9637 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -36,7 +36,10 @@ #include "exec/translator.h" #include "exec/log.h" #include "qemu/atomic128.h" +#include "spr_tcg.h" +#include "qemu/qemu-print.h" +#include "qapi/error.h" #define CPU_SINGLE_STEP 0x1 #define CPU_BRANCH_STEP 0x2 @@ -154,8 +157,8 @@ void ppc_translate_init(void) /* internal defines */ struct DisasContext { DisasContextBase base; + target_ulong cia; /* current instruction address */ uint32_t opcode; - uint32_t exception; /* Routine used to access memory */ bool pr, hv, dr, le_mode; bool lazy_tlb_flush; @@ -181,6 +184,11 @@ struct DisasContext { uint64_t insns_flags2; }; +#define DISAS_EXIT DISAS_TARGET_0 /* exit to main loop, pc updated */ +#define DISAS_EXIT_UPDATE DISAS_TARGET_1 /* exit to main loop, pc stale */ +#define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */ +#define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */ + /* Return true iff byteswap is needed in a scalar memop */ static inline bool need_byteswap(const DisasContext *ctx) { @@ -252,15 +260,13 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) * These are all synchronous exceptions, we set the PC back to the * faulting instruction */ - if (ctx->exception == POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->base.pc_next - 4); - } + gen_update_nip(ctx, ctx->cia); t0 = tcg_const_i32(excp); t1 = tcg_const_i32(error); gen_helper_raise_exception_err(cpu_env, t0, t1); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - ctx->exception = (excp); + ctx->base.is_jmp = DISAS_NORETURN; } static void gen_exception(DisasContext *ctx, uint32_t excp) @@ -271,13 +277,11 @@ static void gen_exception(DisasContext *ctx, uint32_t excp) * These are all synchronous exceptions, we set the PC back to the * faulting instruction */ - if (ctx->exception == POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->base.pc_next - 4); - } + gen_update_nip(ctx, ctx->cia); t0 = tcg_const_i32(excp); gen_helper_raise_exception(cpu_env, t0); tcg_temp_free_i32(t0); - ctx->exception = (excp); + ctx->base.is_jmp = DISAS_NORETURN; } static void gen_exception_nip(DisasContext *ctx, uint32_t excp, @@ -289,7 +293,21 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp, t0 = tcg_const_i32(excp); gen_helper_raise_exception(cpu_env, t0); tcg_temp_free_i32(t0); - ctx->exception = (excp); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static void gen_icount_io_start(DisasContext *ctx) +{ + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + /* + * An I/O instruction must be last in the TB. + * Chain to the next TB, and let the code from gen_tb_start + * decide if we need to return to the main loop. + * Doing this first also allows this value to be overridden. + */ + ctx->base.is_jmp = DISAS_TOO_MANY; + } } /* @@ -322,19 +340,8 @@ static uint32_t gen_prep_dbgex(DisasContext *ctx) static void gen_debug_exception(DisasContext *ctx) { - TCGv_i32 t0; - - /* - * These are all synchronous exceptions, we set the PC back to the - * faulting instruction - */ - if ((ctx->exception != POWERPC_EXCP_BRANCH) && - (ctx->exception != POWERPC_EXCP_SYNC)) { - gen_update_nip(ctx, ctx->base.pc_next); - } - t0 = tcg_const_i32(EXCP_DEBUG); - gen_helper_raise_exception(cpu_env, t0); - tcg_temp_free_i32(t0); + gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG)); + ctx->base.is_jmp = DISAS_NORETURN; } static inline void gen_inval_exception(DisasContext *ctx, uint32_t error) @@ -354,18 +361,924 @@ static inline void gen_hvpriv_exception(DisasContext *ctx, uint32_t error) gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_PRIV | error); } -/* Stop translation */ -static inline void gen_stop_exception(DisasContext *ctx) +/*****************************************************************************/ +/* SPR READ/WRITE CALLBACKS */ + +void spr_noaccess(DisasContext *ctx, int gprn, int sprn) { - gen_update_nip(ctx, ctx->base.pc_next); - ctx->exception = POWERPC_EXCP_STOP; +#if 0 + sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5); + printf("ERROR: try to access SPR %d !\n", sprn); +#endif +} + +/* #define PPC_DUMP_SPR_ACCESSES */ + +/* + * Generic callbacks: + * do nothing but store/retrieve spr value + */ +static void spr_load_dump_spr(int sprn) +{ +#ifdef PPC_DUMP_SPR_ACCESSES + TCGv_i32 t0 = tcg_const_i32(sprn); + gen_helper_load_dump_spr(cpu_env, t0); + tcg_temp_free_i32(t0); +#endif +} + +void spr_read_generic(DisasContext *ctx, int gprn, int sprn) +{ + gen_load_spr(cpu_gpr[gprn], sprn); + spr_load_dump_spr(sprn); +} + +static void spr_store_dump_spr(int sprn) +{ +#ifdef PPC_DUMP_SPR_ACCESSES + TCGv_i32 t0 = tcg_const_i32(sprn); + gen_helper_store_dump_spr(cpu_env, t0); + tcg_temp_free_i32(t0); +#endif +} + +void spr_write_generic(DisasContext *ctx, int sprn, int gprn) +{ + gen_store_spr(sprn, cpu_gpr[gprn]); + spr_store_dump_spr(sprn); +} + +#if !defined(CONFIG_USER_ONLY) +void spr_write_generic32(DisasContext *ctx, int sprn, int gprn) +{ +#ifdef TARGET_PPC64 + TCGv t0 = tcg_temp_new(); + tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); + spr_store_dump_spr(sprn); +#else + spr_write_generic(ctx, sprn, gprn); +#endif +} + +void spr_write_clear(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_spr(t0, sprn); + tcg_gen_neg_tl(t1, cpu_gpr[gprn]); + tcg_gen_and_tl(t0, t0, t1); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +void spr_access_nop(DisasContext *ctx, int sprn, int gprn) +{ +} + +#endif + +/* SPR common to all PowerPC */ +/* XER */ +void spr_read_xer(DisasContext *ctx, int gprn, int sprn) +{ + TCGv dst = cpu_gpr[gprn]; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + tcg_gen_mov_tl(dst, cpu_xer); + tcg_gen_shli_tl(t0, cpu_so, XER_SO); + tcg_gen_shli_tl(t1, cpu_ov, XER_OV); + tcg_gen_shli_tl(t2, cpu_ca, XER_CA); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_or_tl(dst, dst, t2); + tcg_gen_or_tl(dst, dst, t0); + if (is_isa300(ctx)) { + tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32); + tcg_gen_or_tl(dst, dst, t0); + tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32); + tcg_gen_or_tl(dst, dst, t0); + } + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} + +void spr_write_xer(DisasContext *ctx, int sprn, int gprn) +{ + TCGv src = cpu_gpr[gprn]; + /* Write all flags, while reading back check for isa300 */ + tcg_gen_andi_tl(cpu_xer, src, + ~((1u << XER_SO) | + (1u << XER_OV) | (1u << XER_OV32) | + (1u << XER_CA) | (1u << XER_CA32))); + tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1); + tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1); + tcg_gen_extract_tl(cpu_so, src, XER_SO, 1); + tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1); + tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1); +} + +/* LR */ +void spr_read_lr(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr); +} + +void spr_write_lr(DisasContext *ctx, int sprn, int gprn) +{ + tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]); +} + +/* CFAR */ +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +void spr_read_cfar(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar); +} + +void spr_write_cfar(DisasContext *ctx, int sprn, int gprn) +{ + tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]); +} +#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */ + +/* CTR */ +void spr_read_ctr(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr); +} + +void spr_write_ctr(DisasContext *ctx, int sprn, int gprn) +{ + tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]); +} + +/* User read access to SPR */ +/* USPRx */ +/* UMMCRx */ +/* UPMCx */ +/* USIA */ +/* UDECR */ +void spr_read_ureg(DisasContext *ctx, int gprn, int sprn) +{ + gen_load_spr(cpu_gpr[gprn], sprn + 0x10); +} + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +void spr_write_ureg(DisasContext *ctx, int sprn, int gprn) +{ + gen_store_spr(sprn + 0x10, cpu_gpr[gprn]); +} +#endif + +/* SPR common to all non-embedded PowerPC */ +/* DECR */ +#if !defined(CONFIG_USER_ONLY) +void spr_read_decr(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_decr(cpu_gpr[gprn], cpu_env); +} + +void spr_write_decr(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_decr(cpu_env, cpu_gpr[gprn]); +} +#endif + +/* SPR common to all non-embedded PowerPC, except 601 */ +/* Time base */ +void spr_read_tbl(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_tbl(cpu_gpr[gprn], cpu_env); +} + +void spr_read_tbu(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_tbu(cpu_gpr[gprn], cpu_env); +} + +void spr_read_atbl(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_load_atbl(cpu_gpr[gprn], cpu_env); +} + +void spr_read_atbu(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_load_atbu(cpu_gpr[gprn], cpu_env); +} + +#if !defined(CONFIG_USER_ONLY) +void spr_write_tbl(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_tbu(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_atbl(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_atbu(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]); +} + +#if defined(TARGET_PPC64) +void spr_read_purr(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_purr(cpu_gpr[gprn], cpu_env); +} + +void spr_write_purr(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_purr(cpu_env, cpu_gpr[gprn]); +} + +/* HDECR */ +void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env); +} + +void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]); +} + +void spr_read_vtb(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_vtb(cpu_gpr[gprn], cpu_env); +} + +void spr_write_vtb(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_vtb(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_tbu40(cpu_env, cpu_gpr[gprn]); +} + +#endif +#endif + +#if !defined(CONFIG_USER_ONLY) +/* IBAT0U...IBAT0U */ +/* IBAT0L...IBAT7L */ +void spr_read_ibat(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); +} + +void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4])); +} + +void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); + gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4); + gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2); + gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4); + gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +/* DBAT0U...DBAT7U */ +/* DBAT0L...DBAT7L */ +void spr_read_dbat(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2])); +} + +void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4])); +} + +void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2); + gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4); + gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2); + gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4); + gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +/* SDR1 */ +void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]); +} + +#if defined(TARGET_PPC64) +/* 64 bits PowerPC specific SPRs */ +/* PIDR */ +void spr_write_pidr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]); +} + +void spr_read_hior(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix)); +} + +void spr_write_hior(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); + tcg_temp_free(t0); +} +void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_pcr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_pcr(cpu_env, cpu_gpr[gprn]); +} + +/* DPDES */ +void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env); +} + +void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]); +} +#endif +#endif + +/* PowerPC 601 specific registers */ +/* RTC */ +void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env); +} + +void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env); +} + +#if !defined(CONFIG_USER_ONLY) +void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]); + /* Must stop the translation as endianness may have changed */ + ctx->base.is_jmp = DISAS_EXIT_UPDATE; +} +#endif + +/* Unified bats */ +#if !defined(CONFIG_USER_ONLY) +void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, + IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2])); +} + +void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); + gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2); + gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} +#endif + +/* PowerPC 40x specific registers */ +#if !defined(CONFIG_USER_ONLY) +void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn) +{ + gen_icount_io_start(ctx); + gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env); +} + +void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_store_spr(sprn, cpu_gpr[gprn]); + gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); + /* We must stop translation as we may have rebooted */ + ctx->base.is_jmp = DISAS_EXIT_UPDATE; +} + +void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) +{ + gen_icount_io_start(ctx); + gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]); +} +#endif + +/* PowerPC 403 specific registers */ +/* PBL1 / PBU1 / PBL2 / PBU2 */ +#if !defined(CONFIG_USER_ONLY) +void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn) +{ + tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, + offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1])); +} + +void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1); + gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} + +void spr_write_pir(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF); + gen_store_spr(SPR_PIR, t0); + tcg_temp_free(t0); +} +#endif + +/* SPE specific registers */ +void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); + tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0); + tcg_temp_free_i32(t0); +} + +void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]); + tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr)); + tcg_temp_free_i32(t0); +} + +#if !defined(CONFIG_USER_ONLY) +/* Callback used to write the exception vector base */ +void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask)); + tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} + +void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn) +{ + int sprn_offs; + + if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) { + sprn_offs = sprn - SPR_BOOKE_IVOR0; + } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) { + sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32; + } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) { + sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38; + } else { + printf("Trying to write an unknown exception vector %d %03x\n", + sprn, sprn); + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return; + } + + TCGv t0 = tcg_temp_new(); + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask)); + tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]); + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs])); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} +#endif + +#ifdef TARGET_PPC64 +#ifndef CONFIG_USER_ONLY +void spr_write_amr(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + /* + * Note, the HV=1 PR=0 case is handled earlier by simply using + * spr_write_generic for HV mode in the SPR table + */ + + /* Build insertion mask into t1 based on context */ + if (ctx->pr) { + gen_load_spr(t1, SPR_UAMOR); + } else { + gen_load_spr(t1, SPR_AMOR); + } + + /* Mask new bits into t2 */ + tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); + + /* Load AMR and clear new bits in t0 */ + gen_load_spr(t0, SPR_AMR); + tcg_gen_andc_tl(t0, t0, t1); + + /* Or'in new bits and write it out */ + tcg_gen_or_tl(t0, t0, t2); + gen_store_spr(SPR_AMR, t0); + spr_store_dump_spr(SPR_AMR); + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); } +void spr_write_uamor(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + /* + * Note, the HV=1 case is handled earlier by simply using + * spr_write_generic for HV mode in the SPR table + */ + + /* Build insertion mask into t1 based on context */ + gen_load_spr(t1, SPR_AMOR); + + /* Mask new bits into t2 */ + tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); + + /* Load AMR and clear new bits in t0 */ + gen_load_spr(t0, SPR_UAMOR); + tcg_gen_andc_tl(t0, t0, t1); + + /* Or'in new bits and write it out */ + tcg_gen_or_tl(t0, t0, t2); + gen_store_spr(SPR_UAMOR, t0); + spr_store_dump_spr(SPR_UAMOR); + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} + +void spr_write_iamr(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + /* + * Note, the HV=1 case is handled earlier by simply using + * spr_write_generic for HV mode in the SPR table + */ + + /* Build insertion mask into t1 based on context */ + gen_load_spr(t1, SPR_AMOR); + + /* Mask new bits into t2 */ + tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]); + + /* Load AMR and clear new bits in t0 */ + gen_load_spr(t0, SPR_IAMR); + tcg_gen_andc_tl(t0, t0, t1); + + /* Or'in new bits and write it out */ + tcg_gen_or_tl(t0, t0, t2); + gen_store_spr(SPR_IAMR, t0); + spr_store_dump_spr(SPR_IAMR); + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} +#endif +#endif + #ifndef CONFIG_USER_ONLY -/* No need to update nip here, as execution flow will change */ -static inline void gen_sync_exception(DisasContext *ctx) +void spr_read_thrm(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_fixup_thrm(cpu_env); + gen_load_spr(cpu_gpr[gprn], sprn); + spr_load_dump_spr(sprn); +} +#endif /* !CONFIG_USER_ONLY */ + +#if !defined(CONFIG_USER_ONLY) +void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR0_DCE | L1CSR0_CPE); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} + +void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR1_ICE | L1CSR1_CPE); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} + +void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, cpu_gpr[gprn], + ~(E500_L2CSR0_L2FI | E500_L2CSR0_L2FL | E500_L2CSR0_L2LFC)); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} + +void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]); +} + +void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn) +{ + TCGv_i32 t0 = tcg_const_i32(sprn); + gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); + tcg_temp_free_i32(t0); +} +void spr_write_eplc(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]); +} +void spr_write_epsc(DisasContext *ctx, int sprn, int gprn) { - ctx->exception = POWERPC_EXCP_SYNC; + gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]); +} + +#endif + +#if !defined(CONFIG_USER_ONLY) +void spr_write_mas73(DisasContext *ctx, int sprn, int gprn) +{ + TCGv val = tcg_temp_new(); + tcg_gen_ext32u_tl(val, cpu_gpr[gprn]); + gen_store_spr(SPR_BOOKE_MAS3, val); + tcg_gen_shri_tl(val, cpu_gpr[gprn], 32); + gen_store_spr(SPR_BOOKE_MAS7, val); + tcg_temp_free(val); +} + +void spr_read_mas73(DisasContext *ctx, int gprn, int sprn) +{ + TCGv mas7 = tcg_temp_new(); + TCGv mas3 = tcg_temp_new(); + gen_load_spr(mas7, SPR_BOOKE_MAS7); + tcg_gen_shli_tl(mas7, mas7, 32); + gen_load_spr(mas3, SPR_BOOKE_MAS3); + tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7); + tcg_temp_free(mas3); + tcg_temp_free(mas7); +} + +#endif + +#ifdef TARGET_PPC64 +static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn, + int bit, int sprn, int cause) +{ + TCGv_i32 t1 = tcg_const_i32(bit); + TCGv_i32 t2 = tcg_const_i32(sprn); + TCGv_i32 t3 = tcg_const_i32(cause); + + gen_helper_fscr_facility_check(cpu_env, t1, t2, t3); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn, + int bit, int sprn, int cause) +{ + TCGv_i32 t1 = tcg_const_i32(bit); + TCGv_i32 t2 = tcg_const_i32(sprn); + TCGv_i32 t3 = tcg_const_i32(cause); + + gen_helper_msr_facility_check(cpu_env, t1, t2, t3); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn) +{ + TCGv spr_up = tcg_temp_new(); + TCGv spr = tcg_temp_new(); + + gen_load_spr(spr, sprn - 1); + tcg_gen_shri_tl(spr_up, spr, 32); + tcg_gen_ext32u_tl(cpu_gpr[gprn], spr_up); + + tcg_temp_free(spr); + tcg_temp_free(spr_up); +} + +void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn) +{ + TCGv spr = tcg_temp_new(); + + gen_load_spr(spr, sprn - 1); + tcg_gen_deposit_tl(spr, spr, cpu_gpr[gprn], 32, 32); + gen_store_spr(sprn - 1, spr); + + tcg_temp_free(spr); +} + +#if !defined(CONFIG_USER_ONLY) +void spr_write_hmer(DisasContext *ctx, int sprn, int gprn) +{ + TCGv hmer = tcg_temp_new(); + + gen_load_spr(hmer, sprn); + tcg_gen_and_tl(hmer, cpu_gpr[gprn], hmer); + gen_store_spr(sprn, hmer); + spr_store_dump_spr(sprn); + tcg_temp_free(hmer); +} + +void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]); +} +#endif /* !defined(CONFIG_USER_ONLY) */ + +void spr_read_tar(DisasContext *ctx, int gprn, int sprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); + spr_read_generic(ctx, gprn, sprn); +} + +void spr_write_tar(DisasContext *ctx, int sprn, int gprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); + spr_write_generic(ctx, sprn, gprn); +} + +void spr_read_tm(DisasContext *ctx, int gprn, int sprn) +{ + gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_read_generic(ctx, gprn, sprn); +} + +void spr_write_tm(DisasContext *ctx, int sprn, int gprn) +{ + gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_write_generic(ctx, sprn, gprn); +} + +void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn) +{ + gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_read_prev_upper32(ctx, gprn, sprn); +} + +void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn) +{ + gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_write_prev_upper32(ctx, sprn, gprn); +} + +void spr_read_ebb(DisasContext *ctx, int gprn, int sprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_read_generic(ctx, gprn, sprn); +} + +void spr_write_ebb(DisasContext *ctx, int sprn, int gprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_write_generic(ctx, sprn, gprn); +} + +void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_read_prev_upper32(ctx, gprn, sprn); +} + +void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn) +{ + gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_write_prev_upper32(ctx, sprn, gprn); } #endif @@ -1851,18 +2764,13 @@ static void gen_darn(DisasContext *ctx) if (l > 2) { tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1); } else { - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } + gen_icount_io_start(ctx); if (l == 0) { gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]); } else { /* Return 64-bit random for both CRN and RRN */ gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]); } - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_stop_exception(ctx); - } } } #endif @@ -3112,7 +4020,7 @@ static void gen_eieio(DisasContext *ctx) */ if (!(ctx->insns_flags2 & PPC2_ISA300)) { qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @" - TARGET_FMT_lx "\n", ctx->base.pc_next - 4); + TARGET_FMT_lx "\n", ctx->cia); } else { bar = TCG_MO_ST_LD; } @@ -3157,7 +4065,7 @@ static void gen_isync(DisasContext *ctx) gen_check_tlb_flush(ctx, false); } tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); - gen_stop_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; } #define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE)) @@ -3740,8 +4648,9 @@ static void gen_lookup_and_goto_ptr(DisasContext *ctx) } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) { uint32_t excp = gen_prep_dbgex(ctx); gen_exception(ctx, excp); + } else { + tcg_gen_exit_tb(NULL, 0); } - tcg_gen_exit_tb(NULL, 0); } else { tcg_gen_lookup_and_goto_ptr(); } @@ -3776,20 +4685,20 @@ static void gen_b(DisasContext *ctx) { target_ulong li, target; - ctx->exception = POWERPC_EXCP_BRANCH; /* sign extend LI */ li = LI(ctx->opcode); li = (li ^ 0x02000000) - 0x02000000; if (likely(AA(ctx->opcode) == 0)) { - target = ctx->base.pc_next + li - 4; + target = ctx->cia + li; } else { target = li; } if (LK(ctx->opcode)) { gen_setlr(ctx, ctx->base.pc_next); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->cia); gen_goto_tb(ctx, 0, target); + ctx->base.is_jmp = DISAS_NORETURN; } #define BCOND_IM 0 @@ -3802,7 +4711,6 @@ static void gen_bcond(DisasContext *ctx, int type) uint32_t bo = BO(ctx->opcode); TCGLabel *l1; TCGv target; - ctx->exception = POWERPC_EXCP_BRANCH; if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { target = tcg_temp_local_new(); @@ -3887,11 +4795,11 @@ static void gen_bcond(DisasContext *ctx, int type) } tcg_temp_free_i32(temp); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->cia); if (type == BCOND_IM) { target_ulong li = (target_long)((int16_t)(BD(ctx->opcode))); if (likely(AA(ctx->opcode) == 0)) { - gen_goto_tb(ctx, 0, ctx->base.pc_next + li - 4); + gen_goto_tb(ctx, 0, ctx->cia + li); } else { gen_goto_tb(ctx, 0, li); } @@ -3909,6 +4817,7 @@ static void gen_bcond(DisasContext *ctx, int type) gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->base.pc_next); } + ctx->base.is_jmp = DISAS_NORETURN; } static void gen_bc(DisasContext *ctx) @@ -4004,12 +4913,10 @@ static void gen_rfi(DisasContext *ctx) } /* Restore CPU state */ CHK_SV; - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_icount_io_start(ctx); + gen_update_cfar(ctx, ctx->cia); gen_helper_rfi(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4021,12 +4928,10 @@ static void gen_rfid(DisasContext *ctx) #else /* Restore CPU state */ CHK_SV; - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_icount_io_start(ctx); + gen_update_cfar(ctx, ctx->cia); gen_helper_rfid(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif } @@ -4038,12 +4943,10 @@ static void gen_rfscv(DisasContext *ctx) #else /* Restore CPU state */ CHK_SV; - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_icount_io_start(ctx); + gen_update_cfar(ctx, ctx->cia); gen_helper_rfscv(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif } #endif @@ -4056,7 +4959,7 @@ static void gen_hrfid(DisasContext *ctx) /* Restore CPU state */ CHK_HV; gen_helper_hrfid(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif } #endif @@ -4083,13 +4986,10 @@ static void gen_scv(DisasContext *ctx) uint32_t lev = (ctx->opcode >> 5) & 0x7F; /* Set the PC back to the faulting instruction. */ - if (ctx->exception == POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->base.pc_next - 4); - } + gen_update_nip(ctx, ctx->cia); gen_helper_scv(cpu_env, tcg_constant_i32(lev)); - /* This need not be exact, just not POWERPC_EXCP_NONE */ - ctx->exception = POWERPC_SYSCALL_VECTORED; + ctx->base.is_jmp = DISAS_NORETURN; } #endif #endif @@ -4175,43 +5075,6 @@ static void gen_tdi(DisasContext *ctx) /*** Processor control ***/ -static void gen_read_xer(DisasContext *ctx, TCGv dst) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - tcg_gen_mov_tl(dst, cpu_xer); - tcg_gen_shli_tl(t0, cpu_so, XER_SO); - tcg_gen_shli_tl(t1, cpu_ov, XER_OV); - tcg_gen_shli_tl(t2, cpu_ca, XER_CA); - tcg_gen_or_tl(t0, t0, t1); - tcg_gen_or_tl(dst, dst, t2); - tcg_gen_or_tl(dst, dst, t0); - if (is_isa300(ctx)) { - tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32); - tcg_gen_or_tl(dst, dst, t0); - tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32); - tcg_gen_or_tl(dst, dst, t0); - } - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void gen_write_xer(TCGv src) -{ - /* Write all flags, while reading back check for isa300 */ - tcg_gen_andi_tl(cpu_xer, src, - ~((1u << XER_SO) | - (1u << XER_OV) | (1u << XER_OV32) | - (1u << XER_CA) | (1u << XER_CA32))); - tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1); - tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1); - tcg_gen_extract_tl(cpu_so, src, XER_SO, 1); - tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1); - tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1); -} - /* mcrxr */ static void gen_mcrxr(DisasContext *ctx) { @@ -4299,15 +5162,6 @@ static void gen_mfmsr(DisasContext *ctx) tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr); } -static void spr_noaccess(DisasContext *ctx, int gprn, int sprn) -{ -#if 0 - sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5); - printf("ERROR: try to access SPR %d !\n", sprn); -#endif -} -#define SPR_NOACCESS (&spr_noaccess) - /* mfspr */ static inline void gen_op_mfspr(DisasContext *ctx) { @@ -4338,7 +5192,7 @@ static inline void gen_op_mfspr(DisasContext *ctx) if (sprn != SPR_PVR) { qemu_log_mask(LOG_GUEST_ERROR, "Trying to read privileged spr " "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, - ctx->base.pc_next - 4); + ctx->cia); } gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } @@ -4352,7 +5206,7 @@ static inline void gen_op_mfspr(DisasContext *ctx) /* Not defined */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to read invalid spr %d (0x%03x) at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4); + TARGET_FMT_lx "\n", sprn, sprn, ctx->cia); /* * The behaviour depends on MSR:PR and SPR# bit 0x10, it can @@ -4416,9 +5270,7 @@ static void gen_mtmsrd(DisasContext *ctx) CHK_SV; #if !defined(CONFIG_USER_ONLY) - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } + gen_icount_io_start(ctx); if (ctx->opcode & 0x00010000) { /* L=1 form only updates EE and RI */ TCGv t0 = tcg_temp_new(); @@ -4443,7 +5295,7 @@ static void gen_mtmsrd(DisasContext *ctx) gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]); } /* Must stop the translation as machine state (may have) changed */ - gen_stop_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; #endif /* !defined(CONFIG_USER_ONLY) */ } #endif /* defined(TARGET_PPC64) */ @@ -4453,9 +5305,7 @@ static void gen_mtmsr(DisasContext *ctx) CHK_SV; #if !defined(CONFIG_USER_ONLY) - if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { - gen_io_start(); - } + gen_icount_io_start(ctx); if (ctx->opcode & 0x00010000) { /* L=1 form only updates EE and RI */ TCGv t0 = tcg_temp_new(); @@ -4488,7 +5338,7 @@ static void gen_mtmsr(DisasContext *ctx) tcg_temp_free(msr); } /* Must stop the translation as machine state (may have) changed */ - gen_stop_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; #endif } @@ -4516,7 +5366,7 @@ static void gen_mtspr(DisasContext *ctx) /* Privilege exception */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to write privileged spr " "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, - ctx->base.pc_next - 4); + ctx->cia); gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { @@ -4530,7 +5380,7 @@ static void gen_mtspr(DisasContext *ctx) /* Not defined */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to write invalid spr %d (0x%03x) at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4); + TARGET_FMT_lx "\n", sprn, sprn, ctx->cia); /* @@ -5943,7 +6793,7 @@ static void gen_rfsvc(DisasContext *ctx) CHK_SV; gen_helper_rfsvc(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6323,7 +7173,7 @@ static void gen_rfci_40x(DisasContext *ctx) CHK_SV; /* Restore CPU state */ gen_helper_40x_rfci(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6335,7 +7185,7 @@ static void gen_rfci(DisasContext *ctx) CHK_SV; /* Restore CPU state */ gen_helper_rfci(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6350,7 +7200,7 @@ static void gen_rfdi(DisasContext *ctx) CHK_SV; /* Restore CPU state */ gen_helper_rfdi(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6363,7 +7213,7 @@ static void gen_rfmci(DisasContext *ctx) CHK_SV; /* Restore CPU state */ gen_helper_rfmci(cpu_env); - gen_sync_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6625,7 +7475,7 @@ static void gen_wrtee(DisasContext *ctx) * Stop translation to have a chance to raise an exception if we * just set msr_ee to 1 */ - gen_stop_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6639,7 +7489,7 @@ static void gen_wrteei(DisasContext *ctx) if (ctx->opcode & 0x00008000) { tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE)); /* Stop translation to have a chance to raise an exception */ - gen_stop_exception(ctx); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); } @@ -7638,194 +8488,6 @@ GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \ #include "translate/spe-ops.c.inc" }; -#include "helper_regs.h" -#include "translate_init.c.inc" - -/*****************************************************************************/ -/* Misc PowerPC helpers */ -void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ -#define RGPL 4 -#define RFPL 4 - - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - int i; - - qemu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " - TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n", - env->nip, env->lr, env->ctr, cpu_read_xer(env), - cs->cpu_index); - qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " - "%08x iidx %d didx %d\n", - env->msr, env->spr[SPR_HID0], env->hflags, - cpu_mmu_index(env, true), cpu_mmu_index(env, false)); -#if !defined(NO_TIMER_DUMP) - qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 -#if !defined(CONFIG_USER_ONLY) - " DECR " TARGET_FMT_lu -#endif - "\n", - cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) -#if !defined(CONFIG_USER_ONLY) - , cpu_ppc_load_decr(env) -#endif - ); -#endif - for (i = 0; i < 32; i++) { - if ((i & (RGPL - 1)) == 0) { - qemu_fprintf(f, "GPR%02d", i); - } - qemu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i)); - if ((i & (RGPL - 1)) == (RGPL - 1)) { - qemu_fprintf(f, "\n"); - } - } - qemu_fprintf(f, "CR "); - for (i = 0; i < 8; i++) - qemu_fprintf(f, "%01x", env->crf[i]); - qemu_fprintf(f, " ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) { - a = 'L'; - } else if (env->crf[i] & 0x04) { - a = 'G'; - } else if (env->crf[i] & 0x02) { - a = 'E'; - } - qemu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - qemu_fprintf(f, " ] RES " TARGET_FMT_lx "\n", - env->reserve_addr); - - if (flags & CPU_DUMP_FPU) { - for (i = 0; i < 32; i++) { - if ((i & (RFPL - 1)) == 0) { - qemu_fprintf(f, "FPR%02d", i); - } - qemu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i)); - if ((i & (RFPL - 1)) == (RFPL - 1)) { - qemu_fprintf(f, "\n"); - } - } - qemu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr); - } - -#if !defined(CONFIG_USER_ONLY) - qemu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx - " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n", - env->spr[SPR_SRR0], env->spr[SPR_SRR1], - env->spr[SPR_PVR], env->spr[SPR_VRSAVE]); - - qemu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx - " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n", - env->spr[SPR_SPRG0], env->spr[SPR_SPRG1], - env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]); - - qemu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx - " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n", - env->spr[SPR_SPRG4], env->spr[SPR_SPRG5], - env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]); - -#if defined(TARGET_PPC64) - if (env->excp_model == POWERPC_EXCP_POWER7 || - env->excp_model == POWERPC_EXCP_POWER8 || - env->excp_model == POWERPC_EXCP_POWER9 || - env->excp_model == POWERPC_EXCP_POWER10) { - qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", - env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); - } -#endif - if (env->excp_model == POWERPC_EXCP_BOOKE) { - qemu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx - " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], - env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); - - qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx - " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR], - env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]); - - qemu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx - " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR], - env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]); - - qemu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx - " EPR " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8], - env->spr[SPR_BOOKE_EPR]); - - /* FSL-specific */ - qemu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx - " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n", - env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1], - env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]); - - /* - * IVORs are left out as they are large and do not change often -- - * they can be read with "p $ivor0", "p $ivor1", etc. - */ - } - -#if defined(TARGET_PPC64) - if (env->flags & POWERPC_FLAG_CFAR) { - qemu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar); - } -#endif - - if (env->spr_cb[SPR_LPCR].name) { - qemu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]); - } - - switch (env->mmu_model) { - case POWERPC_MMU_32B: - case POWERPC_MMU_601: - case POWERPC_MMU_SOFT_6xx: - case POWERPC_MMU_SOFT_74xx: -#if defined(TARGET_PPC64) - case POWERPC_MMU_64B: - case POWERPC_MMU_2_03: - case POWERPC_MMU_2_06: - case POWERPC_MMU_2_07: - case POWERPC_MMU_3_00: -#endif - if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */ - qemu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]); - } - if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */ - qemu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]); - } - qemu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n", - env->spr[SPR_DAR], env->spr[SPR_DSISR]); - break; - case POWERPC_MMU_BOOKE206: - qemu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx - " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], - env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]); - - qemu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx - " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n", - env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6], - env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]); - - qemu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx - " TLB1CFG " TARGET_FMT_lx "\n", - env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG], - env->spr[SPR_BOOKE_TLB1CFG]); - break; - default: - break; - } -#endif - -#undef RGPL -#undef RFPL -} - /*****************************************************************************/ /* Opcode types */ enum { @@ -8270,14 +8932,68 @@ void ppc_cpu_dump_statistics(CPUState *cs, int flags) #endif } +static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn) +{ + opc_handler_t **table, *handler; + uint32_t inval; + + ctx->opcode = insn; + + LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n", + insn, opc1(insn), opc2(insn), opc3(insn), opc4(insn), + ctx->le_mode ? "little" : "big"); + + table = cpu->opcodes; + handler = table[opc1(insn)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc2(insn)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc3(insn)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc4(insn)]; + } + } + } + + /* Is opcode *REALLY* valid ? */ + if (unlikely(handler->handler == &gen_invalid)) { + qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: " + "%02x - %02x - %02x - %02x (%08x) " + TARGET_FMT_lx "\n", + opc1(insn), opc2(insn), opc3(insn), opc4(insn), + insn, ctx->cia); + return false; + } + + if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) + && Rc(insn))) { + inval = handler->inval2; + } else { + inval = handler->inval1; + } + + if (unlikely((insn & inval) != 0)) { + qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: " + "%02x - %02x - %02x - %02x (%08x) " + TARGET_FMT_lx "\n", insn & inval, + opc1(insn), opc2(insn), opc3(insn), opc4(insn), + insn, ctx->cia); + return false; + } + + handler->handler(ctx); + return true; +} + static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPUPPCState *env = cs->env_ptr; uint32_t hflags = ctx->base.tb->flags; - int bound; - ctx->exception = POWERPC_EXCP_NONE; ctx->spr_cb = env->spr_cb; ctx->pr = (hflags >> HFLAGS_PR) & 1; ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7; @@ -8316,8 +9032,12 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; } - bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; - ctx->base.max_insns = MIN(ctx->base.max_insns, bound); + if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) { + ctx->base.max_insns = 1; + } else { + int bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; + ctx->base.max_insns = MIN(ctx->base.max_insns, bound); + } } static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs) @@ -8334,8 +9054,8 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, { DisasContext *ctx = container_of(dcbase, DisasContext, base); + gen_update_nip(ctx, ctx->base.pc_next); gen_debug_exception(ctx); - dcbase->is_jmp = DISAS_NORETURN; /* * The address covered by the breakpoint must be included in * [tb->pc, tb->pc + tb->size) in order to for it to be properly @@ -8351,100 +9071,93 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) DisasContext *ctx = container_of(dcbase, DisasContext, base); PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = cs->env_ptr; - opc_handler_t **table, *handler; + uint32_t insn; + bool ok; LOG_DISAS("----------------\n"); LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n", ctx->base.pc_next, ctx->mem_idx, (int)msr_ir); - ctx->opcode = translator_ldl_swap(env, ctx->base.pc_next, - need_byteswap(ctx)); - - LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n", - ctx->opcode, opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), - ctx->le_mode ? "little" : "big"); + ctx->cia = ctx->base.pc_next; + insn = translator_ldl_swap(env, ctx->base.pc_next, need_byteswap(ctx)); ctx->base.pc_next += 4; - table = cpu->opcodes; - handler = table[opc1(ctx->opcode)]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - handler = table[opc2(ctx->opcode)]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - handler = table[opc3(ctx->opcode)]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - handler = table[opc4(ctx->opcode)]; - } - } - } - /* Is opcode *REALLY* valid ? */ - if (unlikely(handler->handler == &gen_invalid)) { - qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: " - "%02x - %02x - %02x - %02x (%08x) " - TARGET_FMT_lx " %d\n", - opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), - ctx->opcode, ctx->base.pc_next - 4, (int)msr_ir); - } else { - uint32_t inval; - if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) - && Rc(ctx->opcode))) { - inval = handler->inval2; - } else { - inval = handler->inval1; - } - - if (unlikely((ctx->opcode & inval) != 0)) { - qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: " - "%02x - %02x - %02x - %02x (%08x) " - TARGET_FMT_lx "\n", ctx->opcode & inval, - opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), - ctx->opcode, ctx->base.pc_next - 4); - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); - ctx->base.is_jmp = DISAS_NORETURN; - return; - } + ok = decode_legacy(cpu, ctx, insn); + if (!ok) { + gen_invalid(ctx); } - (*(handler->handler))(ctx); + #if defined(DO_PPC_STATISTICS) handler->count++; #endif - /* Check trace mode exceptions */ - if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP && - (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) && - ctx->exception != POWERPC_SYSCALL && - ctx->exception != POWERPC_EXCP_TRAP && - ctx->exception != POWERPC_EXCP_BRANCH)) { - uint32_t excp = gen_prep_dbgex(ctx); - gen_exception_nip(ctx, excp, ctx->base.pc_next); - } - - if (tcg_check_temp_count()) { - qemu_log("Opcode %02x %02x %02x %02x (%08x) leaked " - "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode); - } - ctx->base.is_jmp = ctx->exception == POWERPC_EXCP_NONE ? - DISAS_NEXT : DISAS_NORETURN; + translator_loop_temp_check(&ctx->base); } static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); + DisasJumpType is_jmp = ctx->base.is_jmp; + target_ulong nip = ctx->base.pc_next; + int sse; + + if (is_jmp == DISAS_NORETURN) { + /* We have already exited the TB. */ + return; + } + + /* Honor single stepping. */ + sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP); + if (unlikely(sse)) { + switch (is_jmp) { + case DISAS_TOO_MANY: + case DISAS_EXIT_UPDATE: + case DISAS_CHAIN_UPDATE: + gen_update_nip(ctx, nip); + break; + case DISAS_EXIT: + case DISAS_CHAIN: + break; + default: + g_assert_not_reached(); + } - if (ctx->exception == POWERPC_EXCP_NONE) { - gen_goto_tb(ctx, 0, ctx->base.pc_next); - } else if (ctx->exception != POWERPC_EXCP_BRANCH) { - if (unlikely(ctx->base.singlestep_enabled)) { + if (sse & GDBSTUB_SINGLE_STEP) { gen_debug_exception(ctx); + return; + } + /* else CPU_SINGLE_STEP... */ + if (nip <= 0x100 || nip > 0xf00) { + gen_exception(ctx, gen_prep_dbgex(ctx)); + return; } - /* Generate the return instruction */ + } + + switch (is_jmp) { + case DISAS_TOO_MANY: + if (use_goto_tb(ctx, nip)) { + tcg_gen_goto_tb(0); + gen_update_nip(ctx, nip); + tcg_gen_exit_tb(ctx->base.tb, 0); + break; + } + /* fall through */ + case DISAS_CHAIN_UPDATE: + gen_update_nip(ctx, nip); + /* fall through */ + case DISAS_CHAIN: + tcg_gen_lookup_and_goto_ptr(); + break; + + case DISAS_EXIT_UPDATE: + gen_update_nip(ctx, nip); + /* fall through */ + case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); + break; + + default: + g_assert_not_reached(); } } diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index b817d31260..57a7f73bba 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -139,7 +139,7 @@ static void gen_lxvwsx(DisasContext *ctx) gen_addr_reg_index(ctx, EA); data = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, MO_TEUL); + tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UL)); tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); tcg_temp_free(EA); @@ -162,7 +162,7 @@ static void gen_lxvdsx(DisasContext *ctx) gen_addr_reg_index(ctx, EA); data = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, MO_TEQ); + tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); tcg_temp_free(EA); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 4f953ddfba..e243624d2a 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -6412,7 +6412,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n", s->fields.op, s->fields.op2); gen_illegal_opcode(s); - return DISAS_NORETURN; + ret = DISAS_NORETURN; + goto out; } #ifndef CONFIG_USER_ONLY @@ -6428,7 +6429,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) /* privileged instruction */ if ((s->base.tb->flags & FLAG_MASK_PSTATE) && (insn->flags & IF_PRIV)) { gen_program_exception(s, PGM_PRIVILEGED); - return DISAS_NORETURN; + ret = DISAS_NORETURN; + goto out; } /* if AFP is not enabled, instructions and registers are forbidden */ @@ -6455,7 +6457,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) } if (dxc) { gen_data_exception(dxc); - return DISAS_NORETURN; + ret = DISAS_NORETURN; + goto out; } } @@ -6463,7 +6466,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) if (insn->flags & IF_VEC) { if (!((s->base.tb->flags & FLAG_MASK_VECTOR))) { gen_data_exception(0xfe); - return DISAS_NORETURN; + ret = DISAS_NORETURN; + goto out; } } @@ -6484,7 +6488,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) (insn->spec & SPEC_r1_f128 && !is_fp_pair(get_field(s, r1))) || (insn->spec & SPEC_r2_f128 && !is_fp_pair(get_field(s, r2)))) { gen_program_exception(s, PGM_SPECIFICATION); - return DISAS_NORETURN; + ret = DISAS_NORETURN; + goto out; } } @@ -6544,6 +6549,7 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) } #endif +out: /* Advance to the next instruction. */ s->base.pc_next = s->pc_tmp; return ret; diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 0ae4efc48a..73584d9d60 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -917,6 +917,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) "unknown instruction length (pc = %08x)\n", dc->pc); gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + dc->base.pc_next = dc->pc + 1; return; } @@ -1274,11 +1275,13 @@ static void xtensa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) if ((tb_cflags(dc->base.tb) & CF_USE_ICOUNT) && (dc->base.tb->flags & XTENSA_TBFLAG_YIELD)) { gen_exception(dc, EXCP_YIELD); + dc->base.pc_next = dc->pc + 1; dc->base.is_jmp = DISAS_NORETURN; return; } if (dc->base.tb->flags & XTENSA_TBFLAG_EXCEPTION) { gen_exception(dc, EXCP_DEBUG); + dc->base.pc_next = dc->pc + 1; dc->base.is_jmp = DISAS_NORETURN; return; } diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 9f464cb92c..ff5d732889 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -140,25 +140,46 @@ docker-image-debian-mips-cross: docker-image-debian10 docker-image-debian-mips64-cross: docker-image-debian10 docker-image-debian-mips64el-cross: docker-image-debian10 docker-image-debian-mipsel-cross: docker-image-debian10 -docker-image-debian-powerpc-cross: docker-image-debian10 -docker-image-debian-ppc64-cross: docker-image-debian10 docker-image-debian-ppc64el-cross: docker-image-debian10 docker-image-debian-riscv64-cross: docker-image-debian10 docker-image-debian-s390x-cross: docker-image-debian10 docker-image-debian-sh4-cross: docker-image-debian10 docker-image-debian-sparc64-cross: docker-image-debian10 +# +# The build rule for hexagon-cross is special in so far for most of +# the time we don't want to build it. While dockers caching does avoid +# this most of the time sometimes we want to force the issue. +# +docker-image-debian-hexagon-cross: $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker + $(if $(NOCACHE), \ + $(call quiet-command, \ + $(DOCKER_SCRIPT) build -t qemu/debian-hexagon-cross -f $< \ + $(if $V,,--quiet) --no-cache \ + --registry $(DOCKER_REGISTRY) --extra-files \ + $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker.d/build-toolchain.sh, \ + "BUILD", "debian-hexagon-cross"), \ + $(call quiet-command, \ + $(DOCKER_SCRIPT) fetch $(if $V,,--quiet) \ + qemu/debian-hexagon-cross $(DOCKER_REGISTRY), \ + "FETCH", "debian-hexagon-cross") \ + $(call quiet-command, \ + $(DOCKER_SCRIPT) update $(if $V,,--quiet) \ + qemu/debian-hexagon-cross --add-current-user, \ + "PREPARE", "debian-hexagon-cross")) + # Specialist build images, sometimes very limited tools docker-image-debian-tricore-cross: docker-image-debian10 docker-image-debian-all-test-cross: docker-image-debian10 docker-image-debian-arm64-test-cross: docker-image-debian11 +docker-image-debian-powerpc-test-cross: docker-image-debian11 # These images may be good enough for building tests but not for test builds DOCKER_PARTIAL_IMAGES += debian-alpha-cross DOCKER_PARTIAL_IMAGES += debian-arm64-test-cross +DOCKER_PARTIAL_IMAGES += debian-powerpc-test-cross DOCKER_PARTIAL_IMAGES += debian-hppa-cross DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross -DOCKER_PARTIAL_IMAGES += debian-powerpc-cross debian-ppc64-cross DOCKER_PARTIAL_IMAGES += debian-riscv64-cross DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross DOCKER_PARTIAL_IMAGES += debian-tricore-cross @@ -248,7 +269,7 @@ docker-run: docker-qemu-src $(if $(EXECUTABLE), \ $(call quiet-command, \ $(DOCKER_SCRIPT) update \ - $(IMAGE) $(EXECUTABLE), \ + $(IMAGE) --executable $(EXECUTABLE), \ " COPYING $(EXECUTABLE) to $(IMAGE)")) $(call quiet-command, \ $(DOCKER_SCRIPT) run \ diff --git a/tests/docker/docker.py b/tests/docker/docker.py index d28df4c140..4d9bb7c7ed 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -515,16 +515,36 @@ class BuildCommand(SubCommand): return 0 +class FetchCommand(SubCommand): + """ Fetch a docker image from the registry. Args: <tag> <registry>""" + name = "fetch" + + def args(self, parser): + parser.add_argument("tag", + help="Local tag for image") + parser.add_argument("registry", + help="Docker registry") + + def run(self, args, argv): + dkr = Docker() + dkr.command(cmd="pull", quiet=args.quiet, + argv=["%s/%s" % (args.registry, args.tag)]) + dkr.command(cmd="tag", quiet=args.quiet, + argv=["%s/%s" % (args.registry, args.tag), args.tag]) + class UpdateCommand(SubCommand): - """ Update a docker image with new executables. Args: <tag> <executable>""" + """ Update a docker image. Args: <tag> <actions>""" name = "update" def args(self, parser): parser.add_argument("tag", help="Image Tag") - parser.add_argument("executable", + parser.add_argument("--executable", help="Executable to copy") + parser.add_argument("--add-current-user", "-u", dest="user", + action="store_true", + help="Add the current user to image's passwd") def run(self, args, argv): # Create a temporary tarball with our whole build context and @@ -532,28 +552,44 @@ class UpdateCommand(SubCommand): tmp = tempfile.NamedTemporaryFile(suffix="dckr.tar.gz") tmp_tar = TarFile(fileobj=tmp, mode='w') - # Add the executable to the tarball, using the current - # configured binfmt_misc path. If we don't get a path then we - # only need the support libraries copied - ff, enabled = _check_binfmt_misc(args.executable) - - if not enabled: - print("binfmt_misc not enabled, update disabled") - return 1 - - if ff: - tmp_tar.add(args.executable, arcname=ff) - - # Add any associated libraries - libs = _get_so_libs(args.executable) - if libs: - for l in libs: - tmp_tar.add(os.path.realpath(l), arcname=l) - # Create a Docker buildfile df = StringIO() df.write(u"FROM %s\n" % args.tag) - df.write(u"ADD . /\n") + + if args.executable: + # Add the executable to the tarball, using the current + # configured binfmt_misc path. If we don't get a path then we + # only need the support libraries copied + ff, enabled = _check_binfmt_misc(args.executable) + + if not enabled: + print("binfmt_misc not enabled, update disabled") + return 1 + + if ff: + tmp_tar.add(args.executable, arcname=ff) + + # Add any associated libraries + libs = _get_so_libs(args.executable) + if libs: + for l in libs: + so_path = os.path.dirname(l) + name = os.path.basename(l) + real_l = os.path.realpath(l) + try: + tmp_tar.add(real_l, arcname="%s/%s" % (so_path, name)) + except FileNotFoundError: + print("Couldn't add %s/%s to archive" % (so_path, name)) + pass + + df.write(u"ADD . /\n") + + if args.user: + uid = os.getuid() + uname = getpwuid(uid).pw_name + df.write("\n") + df.write("RUN id %s 2>/dev/null || useradd -u %d -U %s" % + (uname, uid, uname)) df_bytes = BytesIO(bytes(df.getvalue(), "UTF-8")) diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 0ac46ddd91..7eeecacc46 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -20,6 +20,7 @@ ENV PACKAGES \ gnutls-dev \ gtk+3.0-dev \ libaio-dev \ + libbpf-dev \ libcap-ng-dev \ libjpeg-turbo-dev \ libnfs-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index a8c6c528b0..efc1349cc8 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -14,6 +14,7 @@ ENV PACKAGES \ git \ glib2-devel \ libaio-devel \ + libbpf-devel \ libepoxy-devel \ libfdt-devel \ libgcrypt-devel \ diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker new file mode 100644 index 0000000000..d5dc299dc1 --- /dev/null +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker @@ -0,0 +1,45 @@ +# +# Docker Hexagon cross-compiler target +# +# This docker target is used for building hexagon tests. As it also +# needs to be able to build QEMU itself in CI we include it's +# build-deps. It is also a "stand-alone" image so as not to be +# triggered by re-builds on other base images given it takes a long +# time to build. +# +FROM qemu/debian10 + +# Install common build utilities +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + bison \ + cmake \ + flex \ + lld \ + rsync \ + wget + +ENV TOOLCHAIN_INSTALL /usr/local +ENV ROOTFS /usr/local + +ENV LLVM_URL https://github.com/llvm/llvm-project/archive/bfcd21876adc3498065e4da92799f613e730d475.tar.gz +ENV MUSL_URL https://github.com/quic/musl/archive/aff74b395fbf59cd7e93b3691905aa1af6c0778c.tar.gz +ENV LINUX_URL https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.18.tar.xz + +ADD build-toolchain.sh /root/hexagon-toolchain/build-toolchain.sh + +RUN cd /root/hexagon-toolchain && ./build-toolchain.sh + +FROM debian:buster-slim +# Duplicate deb line as deb-src +RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list +# Install QEMU build deps for use in CI +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ + DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy git ninja-build && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt build-dep -yy --arch-only qemu +COPY --from=0 /usr/local /usr/local +ENV PATH $PATH:/usr/local/bin/ diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh new file mode 100755 index 0000000000..19b1c9f83e --- /dev/null +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +set -e + +BASE=$(readlink -f ${PWD}) + +TOOLCHAIN_INSTALL=$(readlink -f "$TOOLCHAIN_INSTALL") +ROOTFS=$(readlink -f "$ROOTFS") + +TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin +HEX_SYSROOT=${TOOLCHAIN_INSTALL}/hexagon-unknown-linux-musl +HEX_TOOLS_TARGET_BASE=${HEX_SYSROOT}/usr + +function cdp() { + DIR="$1" + mkdir -p "$DIR" + cd "$DIR" +} + +function fetch() { + DIR="$1" + URL="$2" + TEMP="$(readlink -f "$PWD/tmp.tar.gz")" + wget --quiet "$URL" -O "$TEMP" + cdp "$DIR" + tar xaf "$TEMP" --strip-components=1 + rm "$TEMP" + cd - +} + +build_llvm_clang() { + fetch "$BASE/llvm-project" "$LLVM_URL" + cdp "$BASE/build-llvm" + + cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=${TOOLCHAIN_INSTALL} \ + -DLLVM_ENABLE_LLD=ON \ + -DLLVM_TARGETS_TO_BUILD="Hexagon" \ + -DLLVM_ENABLE_PROJECTS="clang;lld" \ + "$BASE/llvm-project/llvm" + ninja all install + cd ${TOOLCHAIN_BIN} + ln -sf clang hexagon-unknown-linux-musl-clang + ln -sf clang++ hexagon-unknown-linux-musl-clang++ + ln -sf llvm-ar hexagon-unknown-linux-musl-ar + ln -sf llvm-objdump hexagon-unknown-linux-musl-objdump + ln -sf llvm-objcopy hexagon-unknown-linux-musl-objcopy + ln -sf llvm-readelf hexagon-unknown-linux-musl-readelf + ln -sf llvm-ranlib hexagon-unknown-linux-musl-ranlib + + # workaround for now: + cat <<EOF > hexagon-unknown-linux-musl.cfg +-G0 --sysroot=${HEX_SYSROOT} +EOF +} + +build_clang_rt() { + cdp "$BASE/build-clang_rt" + cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_CONFIG_PATH="$BASE/build-llvm/bin/llvm-config" \ + -DCMAKE_ASM_FLAGS="-G0 -mlong-calls -fno-pic --target=hexagon-unknown-linux-musl " \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_C_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \ + -DCMAKE_ASM_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \ + -DCMAKE_INSTALL_PREFIX=${HEX_TOOLS_TARGET_BASE} \ + -DCMAKE_CROSSCOMPILING=ON \ + -DCMAKE_C_COMPILER_FORCED=ON \ + -DCMAKE_CXX_COMPILER_FORCED=ON \ + -DCOMPILER_RT_BUILD_BUILTINS=ON \ + -DCOMPILER_RT_BUILTINS_ENABLE_PIC=OFF \ + -DCMAKE_SIZEOF_VOID_P=4 \ + -DCOMPILER_RT_OS_DIR= \ + -DCAN_TARGET_hexagon=1 \ + -DCAN_TARGET_x86_64=0 \ + -DCOMPILER_RT_SUPPORTED_ARCH=hexagon \ + -DLLVM_ENABLE_PROJECTS="compiler-rt" \ + "$BASE/llvm-project/compiler-rt" + ninja install-compiler-rt +} + +build_musl_headers() { + fetch "$BASE/musl" "$MUSL_URL" + cd "$BASE/musl" + make clean + CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \ + CROSS_COMPILE=hexagon-unknown-linux-musl \ + LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \ + CROSS_CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \ + ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE} + PATH=${TOOLCHAIN_BIN}:$PATH make CROSS_COMPILE= install-headers + + cd ${HEX_SYSROOT}/.. + ln -sf hexagon-unknown-linux-musl hexagon +} + +build_kernel_headers() { + fetch "$BASE/linux" "$LINUX_URL" + mkdir -p "$BASE/build-linux" + cd "$BASE/linux" + make O=../build-linux ARCH=hexagon \ + KBUILD_CFLAGS_KERNEL="-mlong-calls" \ + CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \ + LD=${TOOLCHAIN_BIN}/ld.lld \ + KBUILD_VERBOSE=1 comet_defconfig + make mrproper + + cd "$BASE/build-linux" + make \ + ARCH=hexagon \ + CC=${TOOLCHAIN_BIN}/clang \ + INSTALL_HDR_PATH=${HEX_TOOLS_TARGET_BASE} \ + V=1 \ + headers_install +} + +build_musl() { + cd "$BASE/musl" + make clean + CROSS_COMPILE=hexagon-unknown-linux-musl- \ + AR=llvm-ar \ + RANLIB=llvm-ranlib \ + STRIP=llvm-strip \ + CC=clang \ + LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \ + CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \ + ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE} + PATH=${TOOLCHAIN_BIN}/:$PATH make CROSS_COMPILE= install + cd ${HEX_TOOLS_TARGET_BASE}/lib + ln -sf libc.so ld-musl-hexagon.so + ln -sf ld-musl-hexagon.so ld-musl-hexagon.so.1 + cdp ${HEX_TOOLS_TARGET_BASE}/../lib + ln -sf ../usr/lib/ld-musl-hexagon.so.1 +} + +build_llvm_clang +build_kernel_headers +build_musl_headers +build_clang_rt +build_musl diff --git a/tests/docker/dockerfiles/debian-powerpc-cross.docker b/tests/docker/dockerfiles/debian-powerpc-cross.docker deleted file mode 100644 index 07e1789650..0000000000 --- a/tests/docker/dockerfiles/debian-powerpc-cross.docker +++ /dev/null @@ -1,12 +0,0 @@ -# -# Docker powerpc cross-compiler target -# -# This docker target builds on the debian Buster base image. -# -FROM qemu/debian10 - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-powerpc-linux-gnu \ - libc6-dev-powerpc-cross diff --git a/tests/docker/dockerfiles/debian-powerpc-test-cross.docker b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker new file mode 100644 index 0000000000..36b336f709 --- /dev/null +++ b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker @@ -0,0 +1,17 @@ +# +# Docker powerpc/ppc64/ppc64le cross-compiler target +# +# This docker target builds on the debian Bullseye base image. +# +FROM qemu/debian11 + +RUN apt update && \ + DEBIAN_FRONTEND=noninteractive eatmydata \ + apt install -y --no-install-recommends \ + gcc-powerpc-linux-gnu \ + libc6-dev-powerpc-cross \ + gcc-10-powerpc64-linux-gnu \ + libc6-dev-ppc64-cross \ + gcc-10-powerpc64le-linux-gnu \ + libc6-dev-ppc64el-cross + diff --git a/tests/docker/dockerfiles/debian-ppc64-cross.docker b/tests/docker/dockerfiles/debian-ppc64-cross.docker deleted file mode 100644 index 8efe68874e..0000000000 --- a/tests/docker/dockerfiles/debian-ppc64-cross.docker +++ /dev/null @@ -1,11 +0,0 @@ -# -# Docker ppc64 cross-compiler target -# -# This docker target builds on the debian Buster base image. -FROM qemu/debian10 - -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - gcc-powerpc64-linux-gnu \ - libc6-dev-ppc64-cross diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index d8fa16372d..0979c0e1f4 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -32,6 +32,7 @@ ENV PACKAGES \ libcurl-devel \ libepoxy-devel \ libfdt-devel \ + libbpf-devel \ libiscsi-devel \ libjpeg-devel \ libpmem-devel \ diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu index a56564660c..84c8543878 100644 --- a/tests/tcg/Makefile.qemu +++ b/tests/tcg/Makefile.qemu @@ -22,6 +22,8 @@ quiet-@ = $(if $(V),,@) quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3) CROSS_CC_GUEST:= +CROSS_AS_GUEST:= +CROSS_LD_GUEST:= DOCKER_IMAGE:= -include tests/tcg/config-$(TARGET).mak @@ -42,6 +44,8 @@ cross-build-guest-tests: $(call quiet-command, \ (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC="$(CROSS_CC_GUEST)" \ + $(if $(CROSS_AS_GUEST),AS="$(CROSS_AS_GUEST)") \ + $(if $(CROSS_LD_GUEST),LD="$(CROSS_LD_GUEST)") \ SRC_PATH="$(SRC_PATH)" BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \ EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ "BUILD","$(TARGET) guest-tests with $(CROSS_CC_GUEST)") @@ -59,11 +63,24 @@ DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \ -i qemu/$(DOCKER_IMAGE) \ -s $(SRC_PATH) -- " +DOCKER_AS_CMD=$(if $(DOCKER_CROSS_AS_GUEST),"$(DOCKER_SCRIPT) cc \ + --cc $(DOCKER_CROSS_AS_GUEST) \ + -i qemu/$(DOCKER_IMAGE) \ + -s $(SRC_PATH) -- ") + +DOCKER_LD_CMD=$(if $(DOCKER_CROSS_LD_GUEST),"$(DOCKER_SCRIPT) cc \ + --cc $(DOCKER_CROSS_LD_GUEST) \ + -i qemu/$(DOCKER_IMAGE) \ + -s $(SRC_PATH) -- ") + + .PHONY: docker-build-guest-tests docker-build-guest-tests: docker-image-$(DOCKER_IMAGE) $(call quiet-command, \ (mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \ $(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \ + $(if $(DOCKER_AS_CMD),AS=$(DOCKER_AS_CMD)) \ + $(if $(DOCKER_LD_CMD),LD=$(DOCKER_LD_CMD)) \ SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \ EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \ "BUILD","$(TARGET) guest-tests with docker qemu/$(DOCKER_IMAGE)") diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index cab8c6b3a2..b29fae4630 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -43,9 +43,10 @@ quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) # $1 = test name, $2 = cmd, $3 = desc ifdef CONFIG_USER_ONLY -run-test = $(call quiet-command, timeout $(TIMEOUT) $2 > $1.out,"TEST",$3) +run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \ + "TEST",$3) else -run-test = $(call quiet-command, timeout $(TIMEOUT) $2,"TEST",$3) +run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2,"TEST",$3) endif # $1 = test name, $2 = reference diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index 8f20ce065d..ed6492ce59 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -74,37 +74,17 @@ fi for target in $target_list; do arch=${target%%-*} - case $arch in - arm|armeb) - arches=arm - ;; - aarch64|aarch64_be) - arches="aarch64 arm" - ;; - mips*) - arches=mips - ;; - ppc*) - arches=ppc - ;; - sh4|sh4eb) - arches=sh4 - ;; - x86_64) - arches="x86_64 i386" - ;; - xtensa|xtensaeb) - arches=xtensa - ;; - alpha|cris|hexagon|hppa|i386|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64) - arches=$target - ;; - *) - continue - ;; - esac + # reset all container fields container_image= + container_hosts= + container_cross_cc= + container_cross_as= + container_cross_ld= + + # suppress clang + supress_clang= + case $target in aarch64-*) # We don't have any bigendian build tools so we only use this for AArch64 @@ -128,6 +108,11 @@ for target in $target_list; do container_image=fedora-cris-cross container_cross_cc=cris-linux-gnu-gcc ;; + hexagon-*) + container_hosts=x86_64 + container_image=debian-hexagon-cross + container_cross_cc=hexagon-unknown-linux-musl-clang + ;; hppa-*) container_hosts=x86_64 container_image=debian-hppa-cross @@ -137,6 +122,7 @@ for target in $target_list; do container_hosts=x86_64 container_image=fedora-i386-cross container_cross_cc=gcc + supress_clang=yes ;; m68k-*) container_hosts=x86_64 @@ -165,18 +151,14 @@ for target in $target_list; do ;; ppc-*|ppc64abi32-*) container_hosts=x86_64 - container_image=debian-powerpc-cross - container_cross_cc=powerpc-linux-gnu-gcc - ;; - ppc64-*) - container_hosts=x86_64 - container_image=debian-ppc64-cross - container_cross_cc=powerpc64-linux-gnu-gcc + container_image=debian-powerpc-test-cross + container_cross_cc=powerpc-linux-gnu-gcc-10 ;; - ppc64le-*) + ppc64-*|ppc64le-*) container_hosts=x86_64 - container_image=debian-ppc64el-cross - container_cross_cc=powerpc64le-linux-gnu-gcc + container_image=debian-powerpc-test-cross + container_cross_cc=${target%%-*}-linux-gnu-gcc-10 + container_cross_cc=powerpc${container_cross_cc#ppc} ;; riscv64-*) container_hosts=x86_64 @@ -198,10 +180,17 @@ for target in $target_list; do container_image=debian-sparc64-cross container_cross_cc=sparc64-linux-gnu-gcc ;; + tricore-softmmu) + container_hosts=x86_64 + container_image=debian-tricore-cross + container_cross_as=tricore-as + container_cross_ld=tricore-ld + ;; x86_64-*) container_hosts="aarch64 ppc64el x86_64" container_image=debian-amd64-cross container_cross_cc=x86_64-linux-gnu-gcc + supress_clang=yes ;; xtensa*-softmmu) container_hosts=x86_64 @@ -216,6 +205,7 @@ for target in $target_list; do echo "# Automatically generated by configure - do not modify" > $config_target_mak echo "TARGET_NAME=$arch" >> $config_target_mak + echo "target=$target" >> $config_target_mak case $target in *-linux-user | *-bsd-user) echo "CONFIG_USER_ONLY=y" >> $config_target_mak @@ -231,74 +221,91 @@ for target in $target_list; do echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak got_cross_cc=no - for i in $arch $arches; do - if eval test "x\${cross_cc_$i+yes}" != xyes; then - continue - fi - eval "target_compiler=\${cross_cc_$i}" - if ! has $target_compiler; then - continue - fi - write_c_skeleton - if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then - # For host systems we might get away with building without -static - if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then - continue - fi - echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak - else - echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak - fi - echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak + if eval test "x\${cross_cc_$arch}" != xyes; then + eval "target_compiler=\${cross_cc_$arch}" - # Test for compiler features for optional tests. We only do this - # for cross compilers because ensuring the docker containers based - # compilers is a requirememt for adding a new test that needs a - # compiler feature. - case $target in - aarch64-*) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.1-a+sve -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.3-a -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mbranch-protection=standard -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak - fi - if do_compiler "$target_compiler" $target_compiler_cflags \ - -march=armv8.5-a+memtag -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak - fi - ;; - ppc*) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -mpower8-vector -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak - fi - ;; - i386-linux-user) - if do_compiler "$target_compiler" $target_compiler_cflags \ - -Werror -fno-pie -o $TMPE $TMPC; then - echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak - fi - ;; - esac + if has "$target_compiler"; then + if test "$supress_clang" = yes && + $target_compiler --version | grep -qi "clang"; then + got_cross_cc=no + else + write_c_skeleton + if ! do_compiler "$target_compiler" $target_compiler_cflags \ + -o $TMPE $TMPC -static ; then + # For host systems we might get away with building without -static + if do_compiler "$target_compiler" $target_compiler_cflags \ + -o $TMPE $TMPC ; then + got_cross_cc=yes + echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak + echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak + fi + else + got_cross_cc=yes + echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak + echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak + fi + fi + fi + fi - enabled_cross_compilers="$enabled_cross_compilers $target_compiler" - got_cross_cc=yes - break - done + if test $got_cross_cc = yes; then + # Test for compiler features for optional tests. We only do this + # for cross compilers because ensuring the docker containers based + # compilers is a requirememt for adding a new test that needs a + # compiler feature. - if test $got_cross_cc = no && test "$container" != no && test -n "$container_image"; then + case $target in + aarch64-*) + if do_compiler "$target_compiler" $target_compiler_cflags \ + -march=armv8.1-a+sve -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak + fi + if do_compiler "$target_compiler" $target_compiler_cflags \ + -march=armv8.3-a -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak + fi + if do_compiler "$target_compiler" $target_compiler_cflags \ + -mbranch-protection=standard -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak + fi + if do_compiler "$target_compiler" $target_compiler_cflags \ + -march=armv8.5-a+memtag -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak + fi + ;; + ppc*) + if do_compiler "$target_compiler" $target_compiler_cflags \ + -mpower8-vector -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak + fi + if do_compiler "$target_compiler" $target_compiler_cflags \ + -mpower10 -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak + fi + ;; + i386-linux-user) + if do_compiler "$target_compiler" $target_compiler_cflags \ + -Werror -fno-pie -o $TMPE $TMPC; then + echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak + fi + ;; + esac + elif test $got_cross_cc = no && test "$container" != no && \ + test -n "$container_image"; then for host in $container_hosts; do if test "$host" = "$ARCH"; then echo "DOCKER_IMAGE=$container_image" >> $config_target_mak - echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> $config_target_mak + echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> \ + $config_target_mak + if test -n "$container_cross_as"; then + echo "DOCKER_CROSS_AS_GUEST=$container_cross_as" >> \ + $config_target_mak + fi + if test -n "$container_cross_ld"; then + echo "DOCKER_CROSS_LD_GUEST=$container_cross_ld" >> \ + $config_target_mak + fi fi done fi diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c index eb0ec6f8eb..41c7f66e2e 100644 --- a/tests/tcg/multiarch/system/memory.c +++ b/tests/tcg/multiarch/system/memory.c @@ -326,6 +326,7 @@ static bool do_unsigned_test(init_ufn fn) fn(i); ok = do_unsigned_reads(i); } + return ok; #else fn(0); return do_unsigned_reads(0); diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index 0c6a4585fc..a6a4ddaeca 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -10,4 +10,17 @@ PPC64_TESTS=bcdsub endif bcdsub: CFLAGS += -mpower8-vector +PPC64_TESTS += byte_reverse +ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) +run-byte_reverse: QEMU_OPTS+=-cpu POWER10 +run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10 +else +byte_reverse: + $(call skip-test, "BUILD of $@", "missing compiler support") +run-byte_reverse: + $(call skip-test, "RUN of byte_reverse", "not built") +run-plugin-byte_reverse-with-%: + $(call skip-test, "RUN of byte_reverse ($*)", "not built") +endif + TESTS += $(PPC64_TESTS) diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target index 1acfcff94a..c0c14ffbad 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -9,4 +9,17 @@ PPC64LE_TESTS=bcdsub endif bcdsub: CFLAGS += -mpower8-vector +PPC64LE_TESTS += byte_reverse +ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) +run-byte_reverse: QEMU_OPTS+=-cpu POWER10 +run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10 +else +byte_reverse: + $(call skip-test, "BUILD of $@", "missing compiler support") +run-byte_reverse: + $(call skip-test, "RUN of byte_reverse", "not built") +run-plugin-byte_reverse-with-%: + $(call skip-test, "RUN of byte_reverse ($*)", "not built") +endif + TESTS += $(PPC64LE_TESTS) diff --git a/tests/tcg/ppc64le/byte_reverse.c b/tests/tcg/ppc64le/byte_reverse.c new file mode 100644 index 0000000000..53b76fc2e2 --- /dev/null +++ b/tests/tcg/ppc64le/byte_reverse.c @@ -0,0 +1,21 @@ +#include <assert.h> + +int main(void) +{ + unsigned long var; + + var = 0xFEDCBA9876543210; + asm("brh %0, %0" : "+r"(var)); + assert(var == 0xDCFE98BA54761032); + + var = 0xFEDCBA9876543210; + asm("brw %0, %0" : "+r"(var)); + assert(var == 0x98BADCFE10325476); + + var = 0xFEDCBA9876543210; + asm("brd %0, %0" : "+r"(var)); + assert(var == 0x1032547698BADCFE); + + return 0; +} + diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target new file mode 100644 index 0000000000..5007c60ce8 --- /dev/null +++ b/tests/tcg/tricore/Makefile.softmmu-target @@ -0,0 +1,26 @@ +TESTS_PATH = $(SRC_PATH)/tests/tcg/tricore + +LDFLAGS = -T$(TESTS_PATH)/link.ld +ASFLAGS = + +TESTS += test_abs.tst +TESTS += test_bmerge.tst +TESTS += test_clz.tst +TESTS += test_dvstep.tst +TESTS += test_fadd.tst +TESTS += test_fmul.tst +TESTS += test_ftoi.tst +TESTS += test_madd.tst +TESTS += test_msub.tst +TESTS += test_muls.tst + +QEMU_OPTS += -M tricore_testboard -nographic -kernel + +%.pS: $(TESTS_PATH)/%.S + $(HOST_CC) -E -o $@ $< + +%.o: %.pS + $(AS) $(ASFLAGS) -o $@ $< + +%.tst: %.o + $(LD) $(LDFLAGS) $< -o $@ diff --git a/tests/tcg/tricore/link.ld b/tests/tcg/tricore/link.ld new file mode 100644 index 0000000000..364bcdc00a --- /dev/null +++ b/tests/tcg/tricore/link.ld @@ -0,0 +1,60 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-tricore") +OUTPUT_ARCH(tricore) +ENTRY(_start) + +/* the internal ram description */ +MEMORY +{ + text_ram (rx!p): org = 0x80000000, len = 15K + data_ram (w!xp): org = 0xd0000000, len = 130K +} +/* + * Define the sizes of the user and system stacks. + */ +__USTACK_SIZE = DEFINED (__USTACK_SIZE) ? __USTACK_SIZE : 1K ; +/* + * Define the start address and the size of the context save area. + */ +__CSA_BEGIN = 0xd0000000 ; +__CSA_SIZE = 8k ; +__CSA_END = __CSA_BEGIN + __CSA_SIZE ; + +SECTIONS +{ + .text : + { + *(.text) + . = ALIGN(8); + } > text_ram + + .rodata : + { + *(.rodata) + *(.rodata1) + } > data_ram + + .data : + { + . = ALIGN(8) ; + *(.data) + *(.data.*) + . = ALIGN(8) ; + __USTACK = . + __USTACK_SIZE -768; + + } > data_ram + /* + * Allocate space for BSS sections. + */ + .bss : + { + BSS_BASE = . ; + *(.bss) + *(COMMON) + . = ALIGN(8) ; + } > data_ram + /* Make sure CSA, stack and heap addresses are properly aligned. */ + _. = ASSERT ((__CSA_BEGIN & 0x3f) == 0 , "illegal CSA start address") ; + _. = ASSERT ((__CSA_SIZE & 0x3f) == 0 , "illegal CSA size") ; + +} diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h new file mode 100644 index 0000000000..0d76fc403a --- /dev/null +++ b/tests/tcg/tricore/macros.h @@ -0,0 +1,129 @@ +/* Helpers */ +#define LI(reg, val) \ + mov.u reg, lo:val; \ + movh DREG_TEMP_LI, up:val; \ + or reg, reg, DREG_TEMP_LI; \ + +/* Address definitions */ +#define TESTDEV_ADDR 0xf0000000 +/* Register definitions */ +#define DREG_RS1 %d0 +#define DREG_RS2 %d1 +#define DREG_RS3 %d4 +#define DREG_CALC_RESULT %d1 +#define DREG_CALC_PSW %d2 +#define DREG_CORRECT_PSW %d3 +#define DREG_TEMP_LI %d10 +#define DREG_TEMP %d11 +#define DREG_TEST_NUM %d14 +#define DREG_CORRECT_RESULT %d15 + +#define DREG_DEV_ADDR %a15 + +#define EREG_RS1 %e6 +#define EREG_RS1_LO %d6 +#define EREG_RS1_HI %d7 +#define EREG_RS2 %e8 +#define EREG_RS2_LO %d8 +#define EREG_RS2_HI %d9 +#define EREG_CALC_RESULT %e8 +#define EREG_CALC_RESULT_HI %d9 +#define EREG_CALC_RESULT_LO %d8 +#define EREG_CORRECT_RESULT_LO %d0 +#define EREG_CORRECT_RESULT_HI %d1 + +/* Test case wrappers */ +#define TEST_CASE(num, testreg, correct, code...) \ +test_ ## num: \ + code; \ + LI(DREG_CORRECT_RESULT, correct) \ + mov DREG_TEST_NUM, num; \ + jne testreg, DREG_CORRECT_RESULT, fail \ + +#define TEST_CASE_E(num, correct_lo, correct_hi, code...) \ +test_ ## num: \ + code; \ + mov DREG_TEST_NUM, num; \ + LI(EREG_CORRECT_RESULT_LO, correct_lo) \ + jne EREG_CALC_RESULT_LO, EREG_CORRECT_RESULT_LO, fail; \ + LI(EREG_CORRECT_RESULT_HI, correct_hi) \ + jne EREG_CALC_RESULT_HI, EREG_CORRECT_RESULT_HI, fail; + +#define TEST_CASE_PSW(num, testreg, correct, correct_psw, code...) \ +test_ ## num: \ + code; \ + LI(DREG_CORRECT_RESULT, correct) \ + mov DREG_TEST_NUM, num; \ + jne testreg, DREG_CORRECT_RESULT, fail; \ + mfcr DREG_CALC_PSW, $psw; \ + LI(DREG_CORRECT_PSW, correct_psw) \ + mov DREG_TEST_NUM, num; \ + jne DREG_CALC_PSW, DREG_CORRECT_PSW, fail; + +/* Actual test case type + * e.g inst %dX, %dY -> TEST_D_D + * inst %dX, %dY, %dZ -> TEST_D_DD + * inst %eX, %dY, %dZ -> TEST_E_DD + */ +#define TEST_D_D(insn, num, result, rs1) \ + TEST_CASE(num, DREG_CALC_RESULT, result, \ + LI(DREG_RS1, rs1); \ + insn DREG_CALC_RESULT, DREG_RS1; \ + ) + +#define TEST_D_D_PSW(insn, num, result, psw, rs1) \ + TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ + LI(DREG_RS1, rs1); \ + rstv; \ + insn DREG_CORRECT_RESULT, DREG_RS1; \ + ) + +#define TEST_D_DD_PSW(insn, num, result, psw, rs1, rs2) \ + TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2; \ + ) + +#define TEST_D_DDD_PSW(insn, num, result, psw, rs1, rs2, rs3) \ + TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + LI(DREG_RS3, rs3); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, DREG_RS3; \ + ) + +#define TEST_D_DDI_PSW(insn, num, result, psw, rs1, rs2, imm) \ + TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \ + LI(DREG_RS1, rs1); \ + LI(DREG_RS2, rs2); \ + rstv; \ + insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm; \ + ) + +#define TEST_E_ED(insn, num, res_hi, res_lo, rs1_hi, rs1_lo, rs2) \ + TEST_CASE_E(num, res_lo, res_hi, \ + LI(EREG_RS1_LO, rs1_lo); \ + LI(EREG_RS1_HI, rs1_hi); \ + LI(DREG_RS2, rs2); \ + insn EREG_CALC_RESULT, EREG_RS1, DREG_RS2; \ + ) + +/* Pass/Fail handling part */ +#define TEST_PASSFAIL \ + j pass; \ +fail: \ + LI(DREG_TEMP, TESTDEV_ADDR) \ + mov.a DREG_DEV_ADDR, DREG_TEMP; \ + st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\ + debug; \ + j fail; \ +pass: \ + LI(DREG_TEMP, TESTDEV_ADDR) \ + mov.a DREG_DEV_ADDR, DREG_TEMP; \ + mov DREG_TEST_NUM, 0; \ + st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\ + debug; \ + j pass; diff --git a/tests/tcg/tricore/test_abs.S b/tests/tcg/tricore/test_abs.S new file mode 100644 index 0000000000..e42240159a --- /dev/null +++ b/tests/tcg/tricore/test_abs.S @@ -0,0 +1,7 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D(abs, 1, 0, 0) + + TEST_PASSFAIL diff --git a/tests/tcg/tricore/test_bmerge.S b/tests/tcg/tricore/test_bmerge.S new file mode 100644 index 0000000000..8a0fa6d3f6 --- /dev/null +++ b/tests/tcg/tricore/test_bmerge.S @@ -0,0 +1,8 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DD_PSW(bmerge, 1, 0x555557f7, 0x00000b80, 0x0000001d, 0x0000ffff) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_clz.S b/tests/tcg/tricore/test_clz.S new file mode 100644 index 0000000000..e03835f123 --- /dev/null +++ b/tests/tcg/tricore/test_clz.S @@ -0,0 +1,9 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D(cls.h, 1, 0x0, 0x6db17976) + TEST_D_D(cls.h, 2, 0x000f000f, 0x0) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_dvstep.S b/tests/tcg/tricore/test_dvstep.S new file mode 100644 index 0000000000..858dbc62dd --- /dev/null +++ b/tests/tcg/tricore/test_dvstep.S @@ -0,0 +1,15 @@ +#include "macros.h" +.text +.global _start +_start: + # Result RS1 RS2 + TEST_E_ED(dvstep, 1, 0x000001ff, 0xfffe5cff, 0x00000001, 0xfffffe5c, 0x0) + TEST_E_ED(dvstep, 2, 0x00000000, 0x000000ff, 0x00000000, 0x00000000, 0x0) + TEST_E_ED(dvstep, 3, 0x0000f000, 0x000000fd, 0x010000f0, 0x00000000, 0x0) + TEST_E_ED(dvstep, 4, 0xfffff000, 0x00000000, 0x7ffffff0, 0x00000000, 0x0) + TEST_E_ED(dvstep.u, 5, 0xffffff00, 0x100008ff, 0xffffffff, 0x00100008, 0x0) + TEST_E_ED(dvstep.u, 6, 0x00000100, 0x00000000, 0x08000001, 0x00000000, \ + 0xffffff2d) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_fadd.S b/tests/tcg/tricore/test_fadd.S new file mode 100644 index 0000000000..1a65054803 --- /dev/null +++ b/tests/tcg/tricore/test_fadd.S @@ -0,0 +1,16 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DD_PSW(add.f, 1, 0x7fc00000, 0x00000b80, 0xffffff85, 0x00001234) + TEST_D_DD_PSW(add.f, 2, 0xf9c00000, 0x00000b80, 0xf9400000, 0xf9400000) + TEST_D_DD_PSW(add.f, 3, 0x8bb858ca, 0x00000b80, 0x8b3858ca, 0x8b3858ca) + TEST_D_DD_PSW(add.f, 4, 0x00000000, 0x00000b80, 0x000000ff, 0x00000000) + TEST_D_DD_PSW(add.f, 5, 0x7fc00000, 0x00000b80, 0xfffffe52, 0x0a4cf70c) + TEST_D_DD_PSW(add.f, 6, 0x9e6d5076, 0x84000b80, 0x9ded50ec, 0x9ded4fff) + TEST_D_DD_PSW(add.f, 7, 0x00000000, 0x04000b80, 0x0000e8bd, 0x00000000) + TEST_D_DD_PSW(add.f, 8, 0x7fc00000, 0xc4000b80, 0xffad546e, 0xffad546e) + TEST_D_DD_PSW(add.f, 9, 0x7fc00000, 0x04000b80, 0xfffe0000, 0x08130000) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_fmul.S b/tests/tcg/tricore/test_fmul.S new file mode 100644 index 0000000000..fb1f634b2d --- /dev/null +++ b/tests/tcg/tricore/test_fmul.S @@ -0,0 +1,8 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DD_PSW(mul.f, 1, 0x974f4f0a, 0x84000b80, 0x1a0b1980, 0xbcbec42d) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_ftoi.S b/tests/tcg/tricore/test_ftoi.S new file mode 100644 index 0000000000..fb4af6b5aa --- /dev/null +++ b/tests/tcg/tricore/test_ftoi.S @@ -0,0 +1,10 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_D_PSW(ftoi, 1, 0x0, 0x84000b80, 0x05f6e605) + TEST_D_D_PSW(ftoi, 2, 0x0, 0x04000b80, 0x00012200) + TEST_D_D_PSW(ftoi, 3, 0x0, 0xc4000b80, 0xffffffff) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_madd.S b/tests/tcg/tricore/test_madd.S new file mode 100644 index 0000000000..5d839772bb --- /dev/null +++ b/tests/tcg/tricore/test_madd.S @@ -0,0 +1,11 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DDI_PSW(madd, 1, 0x0000fffd, 0x60000b80, 0x0000ffff, 0x7fffffff,2) + TEST_D_DDI_PSW(madd, 2, 0xffff7fff, 0x60000b80, 0xffff8001, 0x7fffffff,2) + TEST_D_DDD_PSW(madds.u, 3, 0xffffffff, 0x60000b80, 0x00000000, 0x80000000, \ + 0x80000000) + + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_msub.S b/tests/tcg/tricore/test_msub.S new file mode 100644 index 0000000000..6dee87d99c --- /dev/null +++ b/tests/tcg/tricore/test_msub.S @@ -0,0 +1,9 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DDI_PSW(msub, 1, 0xd2fbe5e0, 0x00000b80,0x64003300, 0xff5420d4, -216) + TEST_D_DDI_PSW(msub, 2, 0xfffffc10, 0x00000b80,0xfffffe68, 0xfffffffd, -200) + TEST_D_DDD_PSW(msubs.u, 3, 0x0, 0x60000b80, 0x1, 0xffffffff, 0xffffffdb) + TEST_PASSFAIL + diff --git a/tests/tcg/tricore/test_muls.S b/tests/tcg/tricore/test_muls.S new file mode 100644 index 0000000000..ca517556bc --- /dev/null +++ b/tests/tcg/tricore/test_muls.S @@ -0,0 +1,9 @@ +#include "macros.h" +.text +.global _start +_start: + TEST_D_DD_PSW(muls.u, 1, 0xffffffff, 0x78000b80, 0x80000001, 0xffffffff) + TEST_D_DD_PSW(muls.u, 2, 0xffffffff, 0x60000b80, 0xfffffffe, 0xffffffff) + + TEST_PASSFAIL + diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target index 20bf96202a..2151ea6302 100644 --- a/tests/tcg/x86_64/Makefile.target +++ b/tests/tcg/x86_64/Makefile.target @@ -3,14 +3,18 @@ # x86_64 tests - included from tests/tcg/Makefile.target # # Currently we only build test-x86_64 and test-i386-ssse3 from -# $(SRC)/tests/tcg/i386/ +# $(SRC_PATH)/tests/tcg/i386/ # include $(SRC_PATH)/tests/tcg/i386/Makefile.target +X86_64_TESTS += vsyscall TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64 QEMU_OPTS += -cpu max test-x86_64: LDFLAGS+=-lm -lc test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + +vsyscall: $(SRC_PATH)/tests/tcg/x86_64/vsyscall.c + $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) diff --git a/tests/tcg/x86_64/vsyscall.c b/tests/tcg/x86_64/vsyscall.c new file mode 100644 index 0000000000..786b047053 --- /dev/null +++ b/tests/tcg/x86_64/vsyscall.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <time.h> + +#define VSYSCALL_PAGE 0xffffffffff600000 +#define TIME_OFFSET 0x400 +typedef time_t (*time_func)(time_t *); + +int main(void) +{ + printf("%ld\n", ((time_func)(VSYSCALL_PAGE + TIME_OFFSET))(NULL)); + return 0; +} |