From patchwork Mon May 3 07:29:44 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Igor V. Kovalenko" X-Patchwork-Id: 51481 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BC388B7D71 for ; Mon, 3 May 2010 18:05:12 +1000 (EST) Received: from localhost ([127.0.0.1]:33940 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O8qc0-0007uF-IK for incoming@patchwork.ozlabs.org; Mon, 03 May 2010 04:02:44 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O8q6X-0006hU-N0 for qemu-devel@nongnu.org; Mon, 03 May 2010 03:30:15 -0400 Received: from [140.186.70.92] (port=53524 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O8q6Q-0006eP-5L for qemu-devel@nongnu.org; Mon, 03 May 2010 03:30:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O8q69-0003T0-D9 for qemu-devel@nongnu.org; Mon, 03 May 2010 03:30:00 -0400 Received: from mail-fx0-f45.google.com ([209.85.161.45]:62070) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O8q68-0003RG-3I for qemu-devel@nongnu.org; Mon, 03 May 2010 03:29:48 -0400 Received: by fxm12 with SMTP id 12so1871510fxm.4 for ; Mon, 03 May 2010 00:29:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:subject:to:from:date :message-id:in-reply-to:references:user-agent:mime-version :content-type:content-transfer-encoding; bh=MEiXvyp9LhJUfAx0RIh3bRe0/vd8AbB9VlWUM5DIAxw=; b=B6q2fwXECcGLAcJxGoGJ3dA2Mj1JZGIThQFRwZRm5el4LKgBjako1rQxH1fenu0g0M tqCHo5pXa44PK/ypfDQoiHsTr+ycjroD27vyPknvpBE2s9F3XKm3hgtDsOGKn+T0NfDg Hy6T5n/z32fdZ8cS4dn07d7F5SxGljhQCia9g= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:to:from:date:message-id:in-reply-to:references:user-agent :mime-version:content-type:content-transfer-encoding; b=HB8ZJla4pRO6/0/E1dxY6dWzJagUwpfi0SFuMDOeqb3eKgcJuOQNmmAxSAv9HeGNal UXOVJ9QNdEc+vM9jwrO8hLk+ybv+p56zLU/NC/LZMTQs1JEWq4bk+MlQBU8Oe/3YNesv EKRHu+1pdCTFESZ4IWeAh1qdqQ7gGmNOMP6Ls= Received: by 10.103.81.22 with SMTP id i22mr1034036mul.128.1272871786328; Mon, 03 May 2010 00:29:46 -0700 (PDT) Received: from skyserv ([87.255.14.75]) by mx.google.com with ESMTPS id 14sm19187563muo.46.2010.05.03.00.29.45 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 03 May 2010 00:29:45 -0700 (PDT) Received: from localhost ([127.0.0.1] helo=[192.168.1.2]) by skyserv with esmtp (Exim 4.71) (envelope-from ) id 1O8q64-00008t-Pe for qemu-devel@nongnu.org; Mon, 03 May 2010 11:29:44 +0400 To: qemu-devel@nongnu.org From: "Igor V. Kovalenko" Date: Mon, 03 May 2010 11:29:44 +0400 Message-ID: <20100503072944.367.50356.stgit@skyserv> In-Reply-To: <20100503072448.367.7010.stgit@skyserv> References: <20100503072448.367.7010.stgit@skyserv> User-Agent: StGit/0.15 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: [Qemu-devel] [PATCH 3/3] sparc64: handle asi referencing nucleus and secondary MMU contexts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Igor V. Kovalenko - increase max supported MMU modes to 6 - handle nucleus context asi - handle secondary context asi - handle non-faulting loads from secondary context Signed-off-by: Igor V. Kovalenko --- softmmu_exec.h | 25 ++++- target-sparc/cpu.h | 13 ++- target-sparc/exec.h | 4 + target-sparc/helper.c | 42 ++++++-- target-sparc/op_helper.c | 235 ++++++++++++++++++++++++++++++++++------------ 5 files changed, 241 insertions(+), 78 deletions(-) diff --git a/softmmu_exec.h b/softmmu_exec.h index a43e621..28d1d53 100644 --- a/softmmu_exec.h +++ b/softmmu_exec.h @@ -100,9 +100,28 @@ #undef MEMSUFFIX #endif /* (NB_MMU_MODES >= 5) */ -#if (NB_MMU_MODES > 5) -#error "NB_MMU_MODES > 5 is not supported for now" -#endif /* (NB_MMU_MODES > 5) */ +#if (NB_MMU_MODES >= 6) + +#define ACCESS_TYPE 5 +#define MEMSUFFIX MMU_MODE5_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX +#endif /* (NB_MMU_MODES >= 6) */ + +#if (NB_MMU_MODES > 6) +#error "NB_MMU_MODES > 6 is not supported for now" +#endif /* (NB_MMU_MODES > 6) */ /* these access are slower, they must be as rare as possible */ #define ACCESS_TYPE (NB_MMU_MODES) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index b705728..b679333 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -224,7 +224,7 @@ enum { #if !defined(TARGET_SPARC64) #define NB_MMU_MODES 2 #else -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 6 typedef struct trap_state { uint64_t tpc; uint64_t tnpc; @@ -571,6 +571,9 @@ static inline void PUT_CWP64(CPUSPARCState *env1, int cwp) #if !defined(CONFIG_USER_ONLY) void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi, int size); +target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, + int mmu_idx); + #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); @@ -587,10 +590,18 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #define MMU_MODE1_SUFFIX _kernel #ifdef TARGET_SPARC64 #define MMU_MODE2_SUFFIX _hypv +#define MMU_MODE3_SUFFIX _nucleus +#define MMU_MODE4_SUFFIX _user_secondary +#define MMU_MODE5_SUFFIX _kernel_secondary #endif #define MMU_USER_IDX 0 #define MMU_KERNEL_IDX 1 #define MMU_HYPV_IDX 2 +#ifdef TARGET_SPARC64 +#define MMU_NUCLEUS_IDX 3 +#define MMU_USER_SECONDARY_IDX 4 +#define MMU_KERNEL_SECONDARY_IDX 5 +#endif static inline int cpu_mmu_index(CPUState *env1) { diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 70df828..1e9de82 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -13,6 +13,10 @@ register struct CPUSPARCState *env asm(AREG0); #include "cpu.h" #include "exec-all.h" +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif /* !defined(CONFIG_USER_ONLY) */ + /* op_helper.c */ void do_interrupt(CPUState *env); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 4ece01b..cac6cad 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -420,21 +420,32 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, - target_ulong address, int rw, int is_user) + target_ulong address, int rw, int mmu_idx) { unsigned int i; uint64_t context; + int is_user = (mmu_idx == MMU_USER_IDX || + mmu_idx == MMU_USER_SECONDARY_IDX); + if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ *physical = ultrasparc_truncate_physical(address); *prot = PAGE_READ | PAGE_WRITE; return 0; } - if (env->tl == 0) { + switch(mmu_idx) { + case MMU_USER_IDX: + case MMU_KERNEL_IDX: context = env->dmmu.mmu_primary_context & 0x1fff; - } else { + break; + case MMU_USER_SECONDARY_IDX: + case MMU_KERNEL_SECONDARY_IDX: + context = env->dmmu.mmu_secondary_context & 0x1fff; + break; + case MMU_NUCLEUS_IDX: context = 0; + break; } for (i = 0; i < 64; i++) { @@ -482,11 +493,14 @@ static int get_physical_address_data(CPUState *env, static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot, - target_ulong address, int is_user) + target_ulong address, int mmu_idx) { unsigned int i; uint64_t context; + int is_user = (mmu_idx == MMU_USER_IDX || + mmu_idx == MMU_USER_SECONDARY_IDX); + if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { /* IMMU disabled */ *physical = ultrasparc_truncate_physical(address); @@ -495,8 +509,10 @@ static int get_physical_address_code(CPUState *env, } if (env->tl == 0) { + /* PRIMARY context */ context = env->dmmu.mmu_primary_context & 0x1fff; } else { + /* NUCLEUS context */ context = 0; } @@ -535,17 +551,15 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical, target_ulong address, int rw, int mmu_idx, target_ulong *page_size) { - int is_user = mmu_idx == MMU_USER_IDX; - /* ??? We treat everything as a small page, then explicitly flush everything when an entry is evicted. */ *page_size = TARGET_PAGE_SIZE; if (rw == 2) return get_physical_address_code(env, physical, prot, address, - is_user); + mmu_idx); else return get_physical_address_data(env, physical, prot, address, rw, - is_user); + mmu_idx); } /* Perform address translation */ @@ -659,21 +673,27 @@ void dump_mmu(CPUState *env) #if !defined(CONFIG_USER_ONLY) -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, + int mmu_idx) { target_phys_addr_t phys_addr; target_ulong page_size; int prot, access_index; if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, - MMU_KERNEL_IDX, &page_size) != 0) + mmu_idx, &page_size) != 0) if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, - 0, MMU_KERNEL_IDX, &page_size) != 0) + 0, mmu_idx, &page_size) != 0) return -1; if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) return -1; return phys_addr; } + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return cpu_get_phys_page_nofault(env, addr, MMU_KERNEL_IDX); +} #endif void cpu_reset(CPUSPARCState *env) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index e048845..0388646 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,9 +1,6 @@ #include "exec.h" #include "host-utils.h" #include "helper.h" -#if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ //#define DEBUG_MMU //#define DEBUG_MXCC @@ -2141,17 +2138,29 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) switch (asi) { case 0x82: // Primary no-fault case 0x8a: // Primary no-fault LE - if (cpu_get_phys_page_debug(env, addr) == -1ULL) { + case 0x83: // Secondary no-fault + case 0x8b: // Secondary no-fault LE + { + /* secondary space access has lowest asi bit equal to 1 */ + int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX + : MMU_KERNEL_SECONDARY_IDX; + + if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) { #ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); + dump_asi("read ", last_addr, asi, size, ret); #endif - return 0; + return 0; + } } // Fall through case 0x10: // As if user primary + case 0x11: // As if user secondary case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE case 0x80: // Primary + case 0x81: // Secondary case 0x88: // Primary LE + case 0x89: // Secondary LE case 0xe2: // UA2007 Primary block init case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { @@ -2173,37 +2182,75 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) break; } } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch(size) { + case 1: + ret = ldub_kernel_secondary(addr); + break; + case 2: + ret = lduw_kernel_secondary(addr); + break; + case 4: + ret = ldl_kernel_secondary(addr); + break; + default: + case 8: + ret = ldq_kernel_secondary(addr); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_kernel(addr); + break; + case 2: + ret = lduw_kernel(addr); + break; + case 4: + ret = ldl_kernel(addr); + break; + default: + case 8: + ret = ldq_kernel(addr); + break; + } + } + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { switch(size) { case 1: - ret = ldub_kernel(addr); + ret = ldub_user_secondary(addr); break; case 2: - ret = lduw_kernel(addr); + ret = lduw_user_secondary(addr); break; case 4: - ret = ldl_kernel(addr); + ret = ldl_user_secondary(addr); break; default: case 8: - ret = ldq_kernel(addr); + ret = ldq_user_secondary(addr); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_user(addr); + break; + case 2: + ret = lduw_user(addr); + break; + case 4: + ret = ldl_user(addr); + break; + default: + case 8: + ret = ldq_user(addr); break; } - } - } else { - switch(size) { - case 1: - ret = ldub_user(addr); - break; - case 2: - ret = lduw_user(addr); - break; - case 4: - ret = ldl_user(addr); - break; - default: - case 8: - ret = ldq_user(addr); - break; } } break; @@ -2234,22 +2281,27 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) // Only ldda allowed raise_exception(TT_ILL_INSN); return 0; - case 0x83: // Secondary no-fault - case 0x8b: // Secondary no-fault LE - if (cpu_get_phys_page_debug(env, addr) == -1ULL) { -#ifdef DEBUG_ASI - dump_asi("read ", last_addr, asi, size, ret); -#endif - return 0; - } - // Fall through case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) - case 0x11: // As if user secondary - case 0x19: // As if user secondary LE + { + switch(size) { + case 1: + ret = ldub_nucleus(addr); + break; + case 2: + ret = lduw_nucleus(addr); + break; + case 4: + ret = ldl_nucleus(addr); + break; + default: + case 8: + ret = ldq_nucleus(addr); + break; + } + break; + } case 0x4a: // UPA config - case 0x81: // Secondary - case 0x89: // Secondary LE // XXX break; case 0x45: // LSU @@ -2463,9 +2515,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) switch(asi) { case 0x10: // As if user primary + case 0x11: // As if user secondary case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE case 0x80: // Primary + case 0x81: // Secondary case 0x88: // Primary LE + case 0x89: // Secondary LE case 0xe2: // UA2007 Primary block init case 0xe3: // UA2007 Secondary block init if ((asi & 0x80) && (env->pstate & PS_PRIV)) { @@ -2487,37 +2543,75 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) break; } } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { + switch(size) { + case 1: + stb_kernel_secondary(addr, val); + break; + case 2: + stw_kernel_secondary(addr, val); + break; + case 4: + stl_kernel_secondary(addr, val); + break; + case 8: + default: + stq_kernel_secondary(addr, val); + break; + } + } else { + switch(size) { + case 1: + stb_kernel(addr, val); + break; + case 2: + stw_kernel(addr, val); + break; + case 4: + stl_kernel(addr, val); + break; + case 8: + default: + stq_kernel(addr, val); + break; + } + } + } + } else { + /* secondary space access has lowest asi bit equal to 1 */ + if (asi & 1) { switch(size) { case 1: - stb_kernel(addr, val); + stb_user_secondary(addr, val); break; case 2: - stw_kernel(addr, val); + stw_user_secondary(addr, val); break; case 4: - stl_kernel(addr, val); + stl_user_secondary(addr, val); break; case 8: default: - stq_kernel(addr, val); + stq_user_secondary(addr, val); + break; + } + } else { + switch(size) { + case 1: + stb_user(addr, val); + break; + case 2: + stw_user(addr, val); + break; + case 4: + stl_user(addr, val); + break; + case 8: + default: + stq_user(addr, val); break; } - } - } else { - switch(size) { - case 1: - stb_user(addr, val); - break; - case 2: - stw_user(addr, val); - break; - case 4: - stl_user(addr, val); - break; - case 8: - default: - stq_user(addr, val); - break; } } break; @@ -2550,11 +2644,26 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) return; case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) - case 0x11: // As if user secondary - case 0x19: // As if user secondary LE + { + switch(size) { + case 1: + stb_nucleus(addr, val); + break; + case 2: + stw_nucleus(addr, val); + break; + case 4: + stl_nucleus(addr, val); + break; + default: + case 8: + stq_nucleus(addr, val); + break; + } + break; + } + case 0x4a: // UPA config - case 0x81: // Secondary - case 0x89: // Secondary LE // XXX return; case 0x45: // LSU