xref: /qemu/target/alpha/helper.c (revision 74781c08)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  Alpha emulation cpu helpers for qemu.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
9d6ea4236SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10fcf5ef2aSThomas Huth  *
11fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15fcf5ef2aSThomas Huth  *
16fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth  */
19fcf5ef2aSThomas Huth 
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
24*74781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
255f8ab000SAlex Bennée #include "fpu/softfloat-types.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
2790c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
28fcf5ef2aSThomas Huth 
29fcf5ef2aSThomas Huth 
30fcf5ef2aSThomas Huth #define CONVERT_BIT(X, SRC, DST) \
31fcf5ef2aSThomas Huth     (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
32fcf5ef2aSThomas Huth 
cpu_alpha_load_fpcr(CPUAlphaState * env)33fcf5ef2aSThomas Huth uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env)
34fcf5ef2aSThomas Huth {
35fcf5ef2aSThomas Huth     return (uint64_t)env->fpcr << 32;
36fcf5ef2aSThomas Huth }
37fcf5ef2aSThomas Huth 
cpu_alpha_store_fpcr(CPUAlphaState * env,uint64_t val)38fcf5ef2aSThomas Huth void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val)
39fcf5ef2aSThomas Huth {
40ea937dedSRichard Henderson     static const uint8_t rm_map[] = {
41ea937dedSRichard Henderson         [FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT] = float_round_nearest_even,
42ea937dedSRichard Henderson         [FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT] = float_round_to_zero,
43ea937dedSRichard Henderson         [FPCR_DYN_MINUS >> FPCR_DYN_SHIFT] = float_round_down,
44ea937dedSRichard Henderson         [FPCR_DYN_PLUS >> FPCR_DYN_SHIFT] = float_round_up,
45ea937dedSRichard Henderson     };
46ea937dedSRichard Henderson 
47fcf5ef2aSThomas Huth     uint32_t fpcr = val >> 32;
48fcf5ef2aSThomas Huth     uint32_t t = 0;
49fcf5ef2aSThomas Huth 
50106e1319SRichard Henderson     /* Record the raw value before adjusting for linux-user.  */
51fcf5ef2aSThomas Huth     env->fpcr = fpcr;
5221ba8564SRichard Henderson 
5321ba8564SRichard Henderson #ifdef CONFIG_USER_ONLY
5421ba8564SRichard Henderson     /*
5521ba8564SRichard Henderson      * Override some of these bits with the contents of ENV->SWCR.
5621ba8564SRichard Henderson      * In system mode, some of these would trap to the kernel, at
5721ba8564SRichard Henderson      * which point the kernel's handler would emulate and apply
5821ba8564SRichard Henderson      * the software exception mask.
5921ba8564SRichard Henderson      */
60106e1319SRichard Henderson     uint32_t soft_fpcr = alpha_ieee_swcr_to_fpcr(env->swcr) >> 32;
618cd99905SRichard Henderson     fpcr |= soft_fpcr & (FPCR_STATUS_MASK | FPCR_DNZ);
6280093070SRichard Henderson 
6380093070SRichard Henderson     /*
6480093070SRichard Henderson      * The IOV exception is disabled by the kernel with SWCR_TRAP_ENABLE_INV,
6580093070SRichard Henderson      * which got mapped by alpha_ieee_swcr_to_fpcr to FPCR_INVD.
6680093070SRichard Henderson      * Add FPCR_IOV to fpcr_exc_enable so that it is handled identically.
6780093070SRichard Henderson      */
6880093070SRichard Henderson     t |= CONVERT_BIT(soft_fpcr, FPCR_INVD, FPCR_IOV);
69106e1319SRichard Henderson #endif
70106e1319SRichard Henderson 
71106e1319SRichard Henderson     t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
72106e1319SRichard Henderson     t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
73106e1319SRichard Henderson     t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
74106e1319SRichard Henderson     t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
75106e1319SRichard Henderson     t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
76106e1319SRichard Henderson 
77106e1319SRichard Henderson     env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
78106e1319SRichard Henderson 
79106e1319SRichard Henderson     env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT];
80106e1319SRichard Henderson     env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
81a8938e5fSRichard Henderson 
82a8938e5fSRichard Henderson     t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
83106e1319SRichard Henderson #ifdef CONFIG_USER_ONLY
84a8938e5fSRichard Henderson     t |= (env->swcr & SWCR_MAP_UMZ) != 0;
8521ba8564SRichard Henderson #endif
86a8938e5fSRichard Henderson     env->fpcr_flush_to_zero = t;
87fcf5ef2aSThomas Huth }
88fcf5ef2aSThomas Huth 
helper_load_fpcr(CPUAlphaState * env)89fcf5ef2aSThomas Huth uint64_t helper_load_fpcr(CPUAlphaState *env)
90fcf5ef2aSThomas Huth {
91fcf5ef2aSThomas Huth     return cpu_alpha_load_fpcr(env);
92fcf5ef2aSThomas Huth }
93fcf5ef2aSThomas Huth 
helper_store_fpcr(CPUAlphaState * env,uint64_t val)94fcf5ef2aSThomas Huth void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
95fcf5ef2aSThomas Huth {
96fcf5ef2aSThomas Huth     cpu_alpha_store_fpcr(env, val);
97fcf5ef2aSThomas Huth }
98fcf5ef2aSThomas Huth 
cpu_alpha_addr_gr(CPUAlphaState * env,unsigned reg)99fcf5ef2aSThomas Huth static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
100fcf5ef2aSThomas Huth {
101fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
102bcd2625dSRichard Henderson     if (env->flags & ENV_FLAG_PAL_MODE) {
103fcf5ef2aSThomas Huth         if (reg >= 8 && reg <= 14) {
104fcf5ef2aSThomas Huth             return &env->shadow[reg - 8];
105fcf5ef2aSThomas Huth         } else if (reg == 25) {
106fcf5ef2aSThomas Huth             return &env->shadow[7];
107fcf5ef2aSThomas Huth         }
108fcf5ef2aSThomas Huth     }
109fcf5ef2aSThomas Huth #endif
110fcf5ef2aSThomas Huth     return &env->ir[reg];
111fcf5ef2aSThomas Huth }
112fcf5ef2aSThomas Huth 
cpu_alpha_load_gr(CPUAlphaState * env,unsigned reg)113fcf5ef2aSThomas Huth uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
114fcf5ef2aSThomas Huth {
115fcf5ef2aSThomas Huth     return *cpu_alpha_addr_gr(env, reg);
116fcf5ef2aSThomas Huth }
117fcf5ef2aSThomas Huth 
cpu_alpha_store_gr(CPUAlphaState * env,unsigned reg,uint64_t val)118fcf5ef2aSThomas Huth void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
119fcf5ef2aSThomas Huth {
120fcf5ef2aSThomas Huth     *cpu_alpha_addr_gr(env, reg) = val;
121fcf5ef2aSThomas Huth }
122fcf5ef2aSThomas Huth 
123fcf5ef2aSThomas Huth #if defined(CONFIG_USER_ONLY)
alpha_cpu_record_sigsegv(CPUState * cs,vaddr address,MMUAccessType access_type,bool maperr,uintptr_t retaddr)12490113883SRichard Henderson void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
12590113883SRichard Henderson                               MMUAccessType access_type,
12690113883SRichard Henderson                               bool maperr, uintptr_t retaddr)
127fcf5ef2aSThomas Huth {
128ab709f13SRichard Henderson     CPUAlphaState *env = cpu_env(cs);
12990113883SRichard Henderson     target_ulong mmcsr, cause;
130fcf5ef2aSThomas Huth 
13190113883SRichard Henderson     /* Assuming !maperr, infer the missing protection. */
13290113883SRichard Henderson     switch (access_type) {
13390113883SRichard Henderson     case MMU_DATA_LOAD:
13490113883SRichard Henderson         mmcsr = MM_K_FOR;
13590113883SRichard Henderson         cause = 0;
13690113883SRichard Henderson         break;
13790113883SRichard Henderson     case MMU_DATA_STORE:
13890113883SRichard Henderson         mmcsr = MM_K_FOW;
13990113883SRichard Henderson         cause = 1;
14090113883SRichard Henderson         break;
14190113883SRichard Henderson     case MMU_INST_FETCH:
14290113883SRichard Henderson         mmcsr = MM_K_FOE;
14390113883SRichard Henderson         cause = -1;
14490113883SRichard Henderson         break;
14590113883SRichard Henderson     default:
14690113883SRichard Henderson         g_assert_not_reached();
14790113883SRichard Henderson     }
14890113883SRichard Henderson     if (maperr) {
14990113883SRichard Henderson         if (address < BIT_ULL(TARGET_VIRT_ADDR_SPACE_BITS - 1)) {
15090113883SRichard Henderson             /* Userspace address, therefore page not mapped. */
15190113883SRichard Henderson             mmcsr = MM_K_TNV;
15290113883SRichard Henderson         } else {
15390113883SRichard Henderson             /* Kernel or invalid address. */
15490113883SRichard Henderson             mmcsr = MM_K_ACV;
15590113883SRichard Henderson         }
15690113883SRichard Henderson     }
15790113883SRichard Henderson 
15890113883SRichard Henderson     /* Record the arguments that PALcode would give to the kernel. */
159ab709f13SRichard Henderson     env->trap_arg0 = address;
160ab709f13SRichard Henderson     env->trap_arg1 = mmcsr;
161ab709f13SRichard Henderson     env->trap_arg2 = cause;
162fcf5ef2aSThomas Huth }
163fcf5ef2aSThomas Huth #else
164fcf5ef2aSThomas Huth /* Returns the OSF/1 entMM failure indication, or -1 on success.  */
get_physical_address(CPUAlphaState * env,target_ulong addr,int prot_need,int mmu_idx,target_ulong * pphys,int * pprot)165fcf5ef2aSThomas Huth static int get_physical_address(CPUAlphaState *env, target_ulong addr,
166fcf5ef2aSThomas Huth                                 int prot_need, int mmu_idx,
167fcf5ef2aSThomas Huth                                 target_ulong *pphys, int *pprot)
168fcf5ef2aSThomas Huth {
1691c7ad260SRichard Henderson     CPUState *cs = env_cpu(env);
170fcf5ef2aSThomas Huth     target_long saddr = addr;
171fcf5ef2aSThomas Huth     target_ulong phys = 0;
172fcf5ef2aSThomas Huth     target_ulong L1pte, L2pte, L3pte;
173fcf5ef2aSThomas Huth     target_ulong pt, index;
174fcf5ef2aSThomas Huth     int prot = 0;
175fcf5ef2aSThomas Huth     int ret = MM_K_ACV;
176fcf5ef2aSThomas Huth 
177fcf5ef2aSThomas Huth     /* Handle physical accesses.  */
178fcf5ef2aSThomas Huth     if (mmu_idx == MMU_PHYS_IDX) {
179fcf5ef2aSThomas Huth         phys = addr;
180fcf5ef2aSThomas Huth         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
181fcf5ef2aSThomas Huth         ret = -1;
182fcf5ef2aSThomas Huth         goto exit;
183fcf5ef2aSThomas Huth     }
184fcf5ef2aSThomas Huth 
185fcf5ef2aSThomas Huth     /* Ensure that the virtual address is properly sign-extended from
186fcf5ef2aSThomas Huth        the last implemented virtual address bit.  */
187fcf5ef2aSThomas Huth     if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
188fcf5ef2aSThomas Huth         goto exit;
189fcf5ef2aSThomas Huth     }
190fcf5ef2aSThomas Huth 
191fcf5ef2aSThomas Huth     /* Translate the superpage.  */
192fcf5ef2aSThomas Huth     /* ??? When we do more than emulate Unix PALcode, we'll need to
193fcf5ef2aSThomas Huth        determine which KSEG is actually active.  */
194fcf5ef2aSThomas Huth     if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
195fcf5ef2aSThomas Huth         /* User-space cannot access KSEG addresses.  */
196fcf5ef2aSThomas Huth         if (mmu_idx != MMU_KERNEL_IDX) {
197fcf5ef2aSThomas Huth             goto exit;
198fcf5ef2aSThomas Huth         }
199fcf5ef2aSThomas Huth 
200fcf5ef2aSThomas Huth         /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
201fcf5ef2aSThomas Huth            We would not do this if the 48-bit KSEG is enabled.  */
202fcf5ef2aSThomas Huth         phys = saddr & ((1ull << 40) - 1);
203fcf5ef2aSThomas Huth         phys |= (saddr & (1ull << 40)) << 3;
204fcf5ef2aSThomas Huth 
205fcf5ef2aSThomas Huth         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
206fcf5ef2aSThomas Huth         ret = -1;
207fcf5ef2aSThomas Huth         goto exit;
208fcf5ef2aSThomas Huth     }
209fcf5ef2aSThomas Huth 
210fcf5ef2aSThomas Huth     /* Interpret the page table exactly like PALcode does.  */
211fcf5ef2aSThomas Huth 
212fcf5ef2aSThomas Huth     pt = env->ptbr;
213fcf5ef2aSThomas Huth 
2146ad4d7eeSPeter Maydell     /* TODO: rather than using ldq_phys() to read the page table we should
2156ad4d7eeSPeter Maydell      * use address_space_ldq() so that we can handle the case when
2166ad4d7eeSPeter Maydell      * the page table read gives a bus fault, rather than ignoring it.
2176ad4d7eeSPeter Maydell      * For the existing code the zero data that ldq_phys will return for
2186ad4d7eeSPeter Maydell      * an access to invalid memory will result in our treating the page
2196ad4d7eeSPeter Maydell      * table as invalid, which may even be the right behaviour.
2206ad4d7eeSPeter Maydell      */
2216ad4d7eeSPeter Maydell 
222fcf5ef2aSThomas Huth     /* L1 page table read.  */
223fcf5ef2aSThomas Huth     index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
224fcf5ef2aSThomas Huth     L1pte = ldq_phys(cs->as, pt + index*8);
225fcf5ef2aSThomas Huth 
226fcf5ef2aSThomas Huth     if (unlikely((L1pte & PTE_VALID) == 0)) {
227fcf5ef2aSThomas Huth         ret = MM_K_TNV;
228fcf5ef2aSThomas Huth         goto exit;
229fcf5ef2aSThomas Huth     }
230fcf5ef2aSThomas Huth     if (unlikely((L1pte & PTE_KRE) == 0)) {
231fcf5ef2aSThomas Huth         goto exit;
232fcf5ef2aSThomas Huth     }
233fcf5ef2aSThomas Huth     pt = L1pte >> 32 << TARGET_PAGE_BITS;
234fcf5ef2aSThomas Huth 
235fcf5ef2aSThomas Huth     /* L2 page table read.  */
236fcf5ef2aSThomas Huth     index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
237fcf5ef2aSThomas Huth     L2pte = ldq_phys(cs->as, pt + index*8);
238fcf5ef2aSThomas Huth 
239fcf5ef2aSThomas Huth     if (unlikely((L2pte & PTE_VALID) == 0)) {
240fcf5ef2aSThomas Huth         ret = MM_K_TNV;
241fcf5ef2aSThomas Huth         goto exit;
242fcf5ef2aSThomas Huth     }
243fcf5ef2aSThomas Huth     if (unlikely((L2pte & PTE_KRE) == 0)) {
244fcf5ef2aSThomas Huth         goto exit;
245fcf5ef2aSThomas Huth     }
246fcf5ef2aSThomas Huth     pt = L2pte >> 32 << TARGET_PAGE_BITS;
247fcf5ef2aSThomas Huth 
248fcf5ef2aSThomas Huth     /* L3 page table read.  */
249fcf5ef2aSThomas Huth     index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
250fcf5ef2aSThomas Huth     L3pte = ldq_phys(cs->as, pt + index*8);
251fcf5ef2aSThomas Huth 
252fcf5ef2aSThomas Huth     phys = L3pte >> 32 << TARGET_PAGE_BITS;
253fcf5ef2aSThomas Huth     if (unlikely((L3pte & PTE_VALID) == 0)) {
254fcf5ef2aSThomas Huth         ret = MM_K_TNV;
255fcf5ef2aSThomas Huth         goto exit;
256fcf5ef2aSThomas Huth     }
257fcf5ef2aSThomas Huth 
258fcf5ef2aSThomas Huth #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
259fcf5ef2aSThomas Huth # error page bits out of date
260fcf5ef2aSThomas Huth #endif
261fcf5ef2aSThomas Huth 
262fcf5ef2aSThomas Huth     /* Check access violations.  */
263fcf5ef2aSThomas Huth     if (L3pte & (PTE_KRE << mmu_idx)) {
264fcf5ef2aSThomas Huth         prot |= PAGE_READ | PAGE_EXEC;
265fcf5ef2aSThomas Huth     }
266fcf5ef2aSThomas Huth     if (L3pte & (PTE_KWE << mmu_idx)) {
267fcf5ef2aSThomas Huth         prot |= PAGE_WRITE;
268fcf5ef2aSThomas Huth     }
269fcf5ef2aSThomas Huth     if (unlikely((prot & prot_need) == 0 && prot_need)) {
270fcf5ef2aSThomas Huth         goto exit;
271fcf5ef2aSThomas Huth     }
272fcf5ef2aSThomas Huth 
273fcf5ef2aSThomas Huth     /* Check fault-on-operation violations.  */
274fcf5ef2aSThomas Huth     prot &= ~(L3pte >> 1);
275fcf5ef2aSThomas Huth     ret = -1;
276fcf5ef2aSThomas Huth     if (unlikely((prot & prot_need) == 0)) {
277fcf5ef2aSThomas Huth         ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
278fcf5ef2aSThomas Huth                prot_need & PAGE_WRITE ? MM_K_FOW :
279fcf5ef2aSThomas Huth                prot_need & PAGE_READ ? MM_K_FOR : -1);
280fcf5ef2aSThomas Huth     }
281fcf5ef2aSThomas Huth 
282fcf5ef2aSThomas Huth  exit:
283fcf5ef2aSThomas Huth     *pphys = phys;
284fcf5ef2aSThomas Huth     *pprot = prot;
285fcf5ef2aSThomas Huth     return ret;
286fcf5ef2aSThomas Huth }
287fcf5ef2aSThomas Huth 
alpha_cpu_get_phys_page_debug(CPUState * cs,vaddr addr)288fcf5ef2aSThomas Huth hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
289fcf5ef2aSThomas Huth {
290fcf5ef2aSThomas Huth     target_ulong phys;
291fcf5ef2aSThomas Huth     int prot, fail;
292fcf5ef2aSThomas Huth 
29350cb36ceSPhilippe Mathieu-Daudé     fail = get_physical_address(cpu_env(cs), addr, 0, 0, &phys, &prot);
294fcf5ef2aSThomas Huth     return (fail >= 0 ? -1 : phys);
295fcf5ef2aSThomas Huth }
296fcf5ef2aSThomas Huth 
alpha_cpu_tlb_fill(CPUState * cs,vaddr addr,int size,MMUAccessType access_type,int mmu_idx,bool probe,uintptr_t retaddr)297e41c9452SRichard Henderson bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
298e41c9452SRichard Henderson                         MMUAccessType access_type, int mmu_idx,
299e41c9452SRichard Henderson                         bool probe, uintptr_t retaddr)
300fcf5ef2aSThomas Huth {
30150cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(cs);
302fcf5ef2aSThomas Huth     target_ulong phys;
303fcf5ef2aSThomas Huth     int prot, fail;
304fcf5ef2aSThomas Huth 
305e41c9452SRichard Henderson     fail = get_physical_address(env, addr, 1 << access_type,
306e41c9452SRichard Henderson                                 mmu_idx, &phys, &prot);
307fcf5ef2aSThomas Huth     if (unlikely(fail >= 0)) {
308e41c9452SRichard Henderson         if (probe) {
309e41c9452SRichard Henderson             return false;
310e41c9452SRichard Henderson         }
311fcf5ef2aSThomas Huth         cs->exception_index = EXCP_MMFAULT;
312fcf5ef2aSThomas Huth         env->trap_arg0 = addr;
313fcf5ef2aSThomas Huth         env->trap_arg1 = fail;
314cb1de55aSAurelien Jarno         env->trap_arg2 = (access_type == MMU_DATA_LOAD ? 0ull :
315cb1de55aSAurelien Jarno                           access_type == MMU_DATA_STORE ? 1ull :
316cb1de55aSAurelien Jarno                           /* access_type == MMU_INST_FETCH */ -1ull);
317e41c9452SRichard Henderson         cpu_loop_exit_restore(cs, retaddr);
318fcf5ef2aSThomas Huth     }
319fcf5ef2aSThomas Huth 
320fcf5ef2aSThomas Huth     tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
321fcf5ef2aSThomas Huth                  prot, mmu_idx, TARGET_PAGE_SIZE);
322e41c9452SRichard Henderson     return true;
323e41c9452SRichard Henderson }
324fcf5ef2aSThomas Huth 
alpha_cpu_do_interrupt(CPUState * cs)325fcf5ef2aSThomas Huth void alpha_cpu_do_interrupt(CPUState *cs)
326fcf5ef2aSThomas Huth {
32750cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(cs);
328fcf5ef2aSThomas Huth     int i = cs->exception_index;
329fcf5ef2aSThomas Huth 
330fcf5ef2aSThomas Huth     if (qemu_loglevel_mask(CPU_LOG_INT)) {
331fcf5ef2aSThomas Huth         static int count;
332fcf5ef2aSThomas Huth         const char *name = "<unknown>";
333fcf5ef2aSThomas Huth 
334fcf5ef2aSThomas Huth         switch (i) {
335fcf5ef2aSThomas Huth         case EXCP_RESET:
336fcf5ef2aSThomas Huth             name = "reset";
337fcf5ef2aSThomas Huth             break;
338fcf5ef2aSThomas Huth         case EXCP_MCHK:
339fcf5ef2aSThomas Huth             name = "mchk";
340fcf5ef2aSThomas Huth             break;
341fcf5ef2aSThomas Huth         case EXCP_SMP_INTERRUPT:
342fcf5ef2aSThomas Huth             name = "smp_interrupt";
343fcf5ef2aSThomas Huth             break;
344fcf5ef2aSThomas Huth         case EXCP_CLK_INTERRUPT:
345fcf5ef2aSThomas Huth             name = "clk_interrupt";
346fcf5ef2aSThomas Huth             break;
347fcf5ef2aSThomas Huth         case EXCP_DEV_INTERRUPT:
348fcf5ef2aSThomas Huth             name = "dev_interrupt";
349fcf5ef2aSThomas Huth             break;
350fcf5ef2aSThomas Huth         case EXCP_MMFAULT:
351fcf5ef2aSThomas Huth             name = "mmfault";
352fcf5ef2aSThomas Huth             break;
353fcf5ef2aSThomas Huth         case EXCP_UNALIGN:
354fcf5ef2aSThomas Huth             name = "unalign";
355fcf5ef2aSThomas Huth             break;
356fcf5ef2aSThomas Huth         case EXCP_OPCDEC:
357fcf5ef2aSThomas Huth             name = "opcdec";
358fcf5ef2aSThomas Huth             break;
359fcf5ef2aSThomas Huth         case EXCP_ARITH:
360fcf5ef2aSThomas Huth             name = "arith";
361fcf5ef2aSThomas Huth             break;
362fcf5ef2aSThomas Huth         case EXCP_FEN:
363fcf5ef2aSThomas Huth             name = "fen";
364fcf5ef2aSThomas Huth             break;
365fcf5ef2aSThomas Huth         case EXCP_CALL_PAL:
366fcf5ef2aSThomas Huth             name = "call_pal";
367fcf5ef2aSThomas Huth             break;
368fcf5ef2aSThomas Huth         }
369fcf5ef2aSThomas Huth         qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016"
370fcf5ef2aSThomas Huth                  PRIx64 " sp=%016" PRIx64 "\n",
371fcf5ef2aSThomas Huth                  ++count, name, env->error_code, cs->cpu_index,
372fcf5ef2aSThomas Huth                  env->pc, env->ir[IR_SP]);
373fcf5ef2aSThomas Huth     }
374fcf5ef2aSThomas Huth 
375fcf5ef2aSThomas Huth     cs->exception_index = -1;
376fcf5ef2aSThomas Huth 
377fcf5ef2aSThomas Huth     switch (i) {
378fcf5ef2aSThomas Huth     case EXCP_RESET:
379fcf5ef2aSThomas Huth         i = 0x0000;
380fcf5ef2aSThomas Huth         break;
381fcf5ef2aSThomas Huth     case EXCP_MCHK:
382fcf5ef2aSThomas Huth         i = 0x0080;
383fcf5ef2aSThomas Huth         break;
384fcf5ef2aSThomas Huth     case EXCP_SMP_INTERRUPT:
385fcf5ef2aSThomas Huth         i = 0x0100;
386fcf5ef2aSThomas Huth         break;
387fcf5ef2aSThomas Huth     case EXCP_CLK_INTERRUPT:
388fcf5ef2aSThomas Huth         i = 0x0180;
389fcf5ef2aSThomas Huth         break;
390fcf5ef2aSThomas Huth     case EXCP_DEV_INTERRUPT:
391fcf5ef2aSThomas Huth         i = 0x0200;
392fcf5ef2aSThomas Huth         break;
393fcf5ef2aSThomas Huth     case EXCP_MMFAULT:
394fcf5ef2aSThomas Huth         i = 0x0280;
395fcf5ef2aSThomas Huth         break;
396fcf5ef2aSThomas Huth     case EXCP_UNALIGN:
397fcf5ef2aSThomas Huth         i = 0x0300;
398fcf5ef2aSThomas Huth         break;
399fcf5ef2aSThomas Huth     case EXCP_OPCDEC:
400fcf5ef2aSThomas Huth         i = 0x0380;
401fcf5ef2aSThomas Huth         break;
402fcf5ef2aSThomas Huth     case EXCP_ARITH:
403fcf5ef2aSThomas Huth         i = 0x0400;
404fcf5ef2aSThomas Huth         break;
405fcf5ef2aSThomas Huth     case EXCP_FEN:
406fcf5ef2aSThomas Huth         i = 0x0480;
407fcf5ef2aSThomas Huth         break;
408fcf5ef2aSThomas Huth     case EXCP_CALL_PAL:
409fcf5ef2aSThomas Huth         i = env->error_code;
410fcf5ef2aSThomas Huth         /* There are 64 entry points for both privileged and unprivileged,
411fcf5ef2aSThomas Huth            with bit 0x80 indicating unprivileged.  Each entry point gets
412fcf5ef2aSThomas Huth            64 bytes to do its job.  */
413fcf5ef2aSThomas Huth         if (i & 0x80) {
414fcf5ef2aSThomas Huth             i = 0x2000 + (i - 0x80) * 64;
415fcf5ef2aSThomas Huth         } else {
416fcf5ef2aSThomas Huth             i = 0x1000 + i * 64;
417fcf5ef2aSThomas Huth         }
418fcf5ef2aSThomas Huth         break;
419fcf5ef2aSThomas Huth     default:
420fcf5ef2aSThomas Huth         cpu_abort(cs, "Unhandled CPU exception");
421fcf5ef2aSThomas Huth     }
422fcf5ef2aSThomas Huth 
423fcf5ef2aSThomas Huth     /* Remember where the exception happened.  Emulate real hardware in
424fcf5ef2aSThomas Huth        that the low bit of the PC indicates PALmode.  */
425bcd2625dSRichard Henderson     env->exc_addr = env->pc | (env->flags & ENV_FLAG_PAL_MODE);
426fcf5ef2aSThomas Huth 
427fcf5ef2aSThomas Huth     /* Continue execution at the PALcode entry point.  */
428fcf5ef2aSThomas Huth     env->pc = env->palbr + i;
429fcf5ef2aSThomas Huth 
430fcf5ef2aSThomas Huth     /* Switch to PALmode.  */
431bcd2625dSRichard Henderson     env->flags |= ENV_FLAG_PAL_MODE;
432fcf5ef2aSThomas Huth }
433fcf5ef2aSThomas Huth 
alpha_cpu_exec_interrupt(CPUState * cs,int interrupt_request)434fcf5ef2aSThomas Huth bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
435fcf5ef2aSThomas Huth {
43650cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(cs);
437fcf5ef2aSThomas Huth     int idx = -1;
438fcf5ef2aSThomas Huth 
439fcf5ef2aSThomas Huth     /* We never take interrupts while in PALmode.  */
440bcd2625dSRichard Henderson     if (env->flags & ENV_FLAG_PAL_MODE) {
441fcf5ef2aSThomas Huth         return false;
442fcf5ef2aSThomas Huth     }
443fcf5ef2aSThomas Huth 
444fcf5ef2aSThomas Huth     /* Fall through the switch, collecting the highest priority
445fcf5ef2aSThomas Huth        interrupt that isn't masked by the processor status IPL.  */
446fcf5ef2aSThomas Huth     /* ??? This hard-codes the OSF/1 interrupt levels.  */
447bcd2625dSRichard Henderson     switch ((env->flags >> ENV_FLAG_PS_SHIFT) & PS_INT_MASK) {
448fcf5ef2aSThomas Huth     case 0 ... 3:
449fcf5ef2aSThomas Huth         if (interrupt_request & CPU_INTERRUPT_HARD) {
450fcf5ef2aSThomas Huth             idx = EXCP_DEV_INTERRUPT;
451fcf5ef2aSThomas Huth         }
452fcf5ef2aSThomas Huth         /* FALLTHRU */
453fcf5ef2aSThomas Huth     case 4:
454fcf5ef2aSThomas Huth         if (interrupt_request & CPU_INTERRUPT_TIMER) {
455fcf5ef2aSThomas Huth             idx = EXCP_CLK_INTERRUPT;
456fcf5ef2aSThomas Huth         }
457fcf5ef2aSThomas Huth         /* FALLTHRU */
458fcf5ef2aSThomas Huth     case 5:
459fcf5ef2aSThomas Huth         if (interrupt_request & CPU_INTERRUPT_SMP) {
460fcf5ef2aSThomas Huth             idx = EXCP_SMP_INTERRUPT;
461fcf5ef2aSThomas Huth         }
462fcf5ef2aSThomas Huth         /* FALLTHRU */
463fcf5ef2aSThomas Huth     case 6:
464fcf5ef2aSThomas Huth         if (interrupt_request & CPU_INTERRUPT_MCHK) {
465fcf5ef2aSThomas Huth             idx = EXCP_MCHK;
466fcf5ef2aSThomas Huth         }
467fcf5ef2aSThomas Huth     }
468fcf5ef2aSThomas Huth     if (idx >= 0) {
469fcf5ef2aSThomas Huth         cs->exception_index = idx;
470fcf5ef2aSThomas Huth         env->error_code = 0;
471fcf5ef2aSThomas Huth         alpha_cpu_do_interrupt(cs);
472fcf5ef2aSThomas Huth         return true;
473fcf5ef2aSThomas Huth     }
474fcf5ef2aSThomas Huth     return false;
475fcf5ef2aSThomas Huth }
476fcf5ef2aSThomas Huth 
4779354e694SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
4789354e694SPhilippe Mathieu-Daudé 
alpha_cpu_dump_state(CPUState * cs,FILE * f,int flags)47990c84c56SMarkus Armbruster void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags)
480fcf5ef2aSThomas Huth {
4814a247932SRichard Henderson     static const char linux_reg_names[31][4] = {
482fcf5ef2aSThomas Huth         "v0",  "t0",  "t1", "t2",  "t3", "t4", "t5", "t6",
483fcf5ef2aSThomas Huth         "t7",  "s0",  "s1", "s2",  "s3", "s4", "s5", "fp",
484fcf5ef2aSThomas Huth         "a0",  "a1",  "a2", "a3",  "a4", "a5", "t8", "t9",
4854a247932SRichard Henderson         "t10", "t11", "ra", "t12", "at", "gp", "sp"
486fcf5ef2aSThomas Huth     };
48750cb36ceSPhilippe Mathieu-Daudé     CPUAlphaState *env = cpu_env(cs);
488fcf5ef2aSThomas Huth     int i;
489fcf5ef2aSThomas Huth 
49090c84c56SMarkus Armbruster     qemu_fprintf(f, "PC      " TARGET_FMT_lx " PS      %02x\n",
491bcd2625dSRichard Henderson                  env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8));
492fcf5ef2aSThomas Huth     for (i = 0; i < 31; i++) {
4934a247932SRichard Henderson         qemu_fprintf(f, "%-8s" TARGET_FMT_lx "%c",
494a68d82b8SRichard Henderson                      linux_reg_names[i], cpu_alpha_load_gr(env, i),
495a68d82b8SRichard Henderson                      (i % 3) == 2 ? '\n' : ' ');
496fcf5ef2aSThomas Huth     }
497fcf5ef2aSThomas Huth 
49890c84c56SMarkus Armbruster     qemu_fprintf(f, "lock_a  " TARGET_FMT_lx " lock_v  " TARGET_FMT_lx "\n",
499fcf5ef2aSThomas Huth                  env->lock_addr, env->lock_value);
500fcf5ef2aSThomas Huth 
501a68d82b8SRichard Henderson     if (flags & CPU_DUMP_FPU) {
502fcf5ef2aSThomas Huth         for (i = 0; i < 31; i++) {
5034a247932SRichard Henderson             qemu_fprintf(f, "f%-7d%016" PRIx64 "%c", i, env->fir[i],
504a68d82b8SRichard Henderson                          (i % 3) == 2 ? '\n' : ' ');
505a68d82b8SRichard Henderson         }
5064a247932SRichard Henderson         qemu_fprintf(f, "fpcr    %016" PRIx64 "\n", cpu_alpha_load_fpcr(env));
507fcf5ef2aSThomas Huth     }
50890c84c56SMarkus Armbruster     qemu_fprintf(f, "\n");
509fcf5ef2aSThomas Huth }
510fcf5ef2aSThomas Huth 
511fcf5ef2aSThomas Huth /* This should only be called from translate, via gen_excp.
512fcf5ef2aSThomas Huth    We expect that ENV->PC has already been updated.  */
helper_excp(CPUAlphaState * env,int excp,int error)5138905770bSMarc-André Lureau G_NORETURN void helper_excp(CPUAlphaState *env, int excp, int error)
514fcf5ef2aSThomas Huth {
5151c7ad260SRichard Henderson     CPUState *cs = env_cpu(env);
516fcf5ef2aSThomas Huth 
517fcf5ef2aSThomas Huth     cs->exception_index = excp;
518fcf5ef2aSThomas Huth     env->error_code = error;
519fcf5ef2aSThomas Huth     cpu_loop_exit(cs);
520fcf5ef2aSThomas Huth }
521fcf5ef2aSThomas Huth 
522fcf5ef2aSThomas Huth /* This may be called from any of the helpers to set up EXCEPTION_INDEX.  */
dynamic_excp(CPUAlphaState * env,uintptr_t retaddr,int excp,int error)5238905770bSMarc-André Lureau G_NORETURN void dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
524fcf5ef2aSThomas Huth                              int excp, int error)
525fcf5ef2aSThomas Huth {
5261c7ad260SRichard Henderson     CPUState *cs = env_cpu(env);
527fcf5ef2aSThomas Huth 
528fcf5ef2aSThomas Huth     cs->exception_index = excp;
529fcf5ef2aSThomas Huth     env->error_code = error;
530fcf5ef2aSThomas Huth     if (retaddr) {
5313d419a4dSRichard Henderson         cpu_restore_state(cs, retaddr);
532fcf5ef2aSThomas Huth         /* Floating-point exceptions (our only users) point to the next PC.  */
533fcf5ef2aSThomas Huth         env->pc += 4;
534fcf5ef2aSThomas Huth     }
535fcf5ef2aSThomas Huth     cpu_loop_exit(cs);
536fcf5ef2aSThomas Huth }
537fcf5ef2aSThomas Huth 
arith_excp(CPUAlphaState * env,uintptr_t retaddr,int exc,uint64_t mask)5388905770bSMarc-André Lureau G_NORETURN void arith_excp(CPUAlphaState *env, uintptr_t retaddr,
539fcf5ef2aSThomas Huth                            int exc, uint64_t mask)
540fcf5ef2aSThomas Huth {
541fcf5ef2aSThomas Huth     env->trap_arg0 = exc;
542fcf5ef2aSThomas Huth     env->trap_arg1 = mask;
543fcf5ef2aSThomas Huth     dynamic_excp(env, retaddr, EXCP_ARITH, 0);
544fcf5ef2aSThomas Huth }
545