blob: a4fae31e3823ecee8f7090e03635db69f556e445 [file] [log] [blame]
bellard79aceca2003-11-23 14:55:54 +00001/*
bellard3fc6c082005-07-02 20:59:34 +00002 * PowerPC emulation helpers for qemu.
ths5fafdf22007-09-16 21:08:06 +00003 *
j_mayer76a66252007-03-07 08:32:30 +00004 * Copyright (c) 2003-2007 Jocelyn Mayer
bellard79aceca2003-11-23 14:55:54 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard79aceca2003-11-23 14:55:54 +000018 */
bellardfdabc362005-07-04 22:17:05 +000019#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24#include <signal.h>
bellardfdabc362005-07-04 22:17:05 +000025
26#include "cpu.h"
27#include "exec-all.h"
j_mayer0411a972007-10-25 21:35:50 +000028#include "helper_regs.h"
aurel32ca10f862008-04-11 21:35:42 +000029#include "qemu-common.h"
aurel32d76d1652008-12-16 10:43:58 +000030#include "kvm.h"
bellard9a64fbe2004-01-04 22:58:38 +000031
32//#define DEBUG_MMU
33//#define DEBUG_BATS
j_mayer6b542af2007-11-24 02:03:55 +000034//#define DEBUG_SLB
j_mayer76a66252007-03-07 08:32:30 +000035//#define DEBUG_SOFTWARE_TLB
j_mayer0411a972007-10-25 21:35:50 +000036//#define DUMP_PAGE_TABLES
bellard9a64fbe2004-01-04 22:58:38 +000037//#define DEBUG_EXCEPTIONS
bellardfdabc362005-07-04 22:17:05 +000038//#define FLUSH_ALL_TLBS
bellard9a64fbe2004-01-04 22:58:38 +000039
aliguorid12d51d2009-01-15 21:48:06 +000040#ifdef DEBUG_MMU
aliguori93fcfe32009-01-15 22:34:14 +000041# define LOG_MMU(...) qemu_log(__VA_ARGS__)
42# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
aliguorid12d51d2009-01-15 21:48:06 +000043#else
44# define LOG_MMU(...) do { } while (0)
45# define LOG_MMU_STATE(...) do { } while (0)
46#endif
47
48
49#ifdef DEBUG_SOFTWARE_TLB
aliguori93fcfe32009-01-15 22:34:14 +000050# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000051#else
52# define LOG_SWTLB(...) do { } while (0)
53#endif
54
55#ifdef DEBUG_BATS
aliguori93fcfe32009-01-15 22:34:14 +000056# define LOG_BATS(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000057#else
58# define LOG_BATS(...) do { } while (0)
59#endif
60
61#ifdef DEBUG_SLB
aliguori93fcfe32009-01-15 22:34:14 +000062# define LOG_SLB(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000063#else
64# define LOG_SLB(...) do { } while (0)
65#endif
66
67#ifdef DEBUG_EXCEPTIONS
aliguori93fcfe32009-01-15 22:34:14 +000068# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000069#else
70# define LOG_EXCP(...) do { } while (0)
71#endif
72
73
bellard9a64fbe2004-01-04 22:58:38 +000074/*****************************************************************************/
bellard3fc6c082005-07-02 20:59:34 +000075/* PowerPC MMU emulation */
bellarda541f292004-04-12 20:39:29 +000076
j_mayerd9bce9d2007-03-17 14:02:15 +000077#if defined(CONFIG_USER_ONLY)
j_mayere96efcf2007-04-14 12:17:09 +000078int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
j_mayer6ebbf392007-10-14 07:07:08 +000079 int mmu_idx, int is_softmmu)
bellard24741ef2005-10-30 21:23:39 +000080{
81 int exception, error_code;
j_mayerd9bce9d2007-03-17 14:02:15 +000082
bellard24741ef2005-10-30 21:23:39 +000083 if (rw == 2) {
j_mayere1833e12007-09-29 13:06:16 +000084 exception = POWERPC_EXCP_ISI;
j_mayer8f793432007-10-03 20:19:40 +000085 error_code = 0x40000000;
bellard24741ef2005-10-30 21:23:39 +000086 } else {
j_mayere1833e12007-09-29 13:06:16 +000087 exception = POWERPC_EXCP_DSI;
j_mayer8f793432007-10-03 20:19:40 +000088 error_code = 0x40000000;
bellard24741ef2005-10-30 21:23:39 +000089 if (rw)
90 error_code |= 0x02000000;
91 env->spr[SPR_DAR] = address;
92 env->spr[SPR_DSISR] = error_code;
93 }
94 env->exception_index = exception;
95 env->error_code = error_code;
j_mayer76a66252007-03-07 08:32:30 +000096
bellard24741ef2005-10-30 21:23:39 +000097 return 1;
98}
j_mayer76a66252007-03-07 08:32:30 +000099
Anthony Liguoric227f092009-10-01 16:12:16 -0500100target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
bellard24741ef2005-10-30 21:23:39 +0000101{
102 return addr;
103}
j_mayer36081602007-09-17 08:21:54 +0000104
bellard24741ef2005-10-30 21:23:39 +0000105#else
j_mayer76a66252007-03-07 08:32:30 +0000106/* Common routines used by software and hardware TLBs emulation */
Blue Swirl636aa202009-08-16 09:06:54 +0000107static inline int pte_is_valid(target_ulong pte0)
bellard9a64fbe2004-01-04 22:58:38 +0000108{
j_mayer76a66252007-03-07 08:32:30 +0000109 return pte0 & 0x80000000 ? 1 : 0;
110}
111
Blue Swirl636aa202009-08-16 09:06:54 +0000112static inline void pte_invalidate(target_ulong *pte0)
j_mayer76a66252007-03-07 08:32:30 +0000113{
114 *pte0 &= ~0x80000000;
115}
116
j_mayercaa40392007-09-19 04:36:02 +0000117#if defined(TARGET_PPC64)
Blue Swirl636aa202009-08-16 09:06:54 +0000118static inline int pte64_is_valid(target_ulong pte0)
j_mayercaa40392007-09-19 04:36:02 +0000119{
120 return pte0 & 0x0000000000000001ULL ? 1 : 0;
121}
122
Blue Swirl636aa202009-08-16 09:06:54 +0000123static inline void pte64_invalidate(target_ulong *pte0)
j_mayercaa40392007-09-19 04:36:02 +0000124{
125 *pte0 &= ~0x0000000000000001ULL;
126}
127#endif
128
j_mayer76a66252007-03-07 08:32:30 +0000129#define PTE_PTEM_MASK 0x7FFFFFBF
130#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
j_mayercaa40392007-09-19 04:36:02 +0000131#if defined(TARGET_PPC64)
132#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
133#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
134#endif
j_mayer76a66252007-03-07 08:32:30 +0000135
Blue Swirl636aa202009-08-16 09:06:54 +0000136static inline int pp_check(int key, int pp, int nx)
j_mayerb227a8e2007-10-14 10:21:20 +0000137{
138 int access;
139
140 /* Compute access rights */
141 /* When pp is 3/7, the result is undefined. Set it to noaccess */
142 access = 0;
143 if (key == 0) {
144 switch (pp) {
145 case 0x0:
146 case 0x1:
147 case 0x2:
148 access |= PAGE_WRITE;
149 /* No break here */
150 case 0x3:
151 case 0x6:
152 access |= PAGE_READ;
153 break;
154 }
155 } else {
156 switch (pp) {
157 case 0x0:
158 case 0x6:
159 access = 0;
160 break;
161 case 0x1:
162 case 0x3:
163 access = PAGE_READ;
164 break;
165 case 0x2:
166 access = PAGE_READ | PAGE_WRITE;
167 break;
168 }
169 }
170 if (nx == 0)
171 access |= PAGE_EXEC;
172
173 return access;
174}
175
Blue Swirl636aa202009-08-16 09:06:54 +0000176static inline int check_prot(int prot, int rw, int access_type)
j_mayerb227a8e2007-10-14 10:21:20 +0000177{
178 int ret;
179
180 if (access_type == ACCESS_CODE) {
181 if (prot & PAGE_EXEC)
182 ret = 0;
183 else
184 ret = -2;
185 } else if (rw) {
186 if (prot & PAGE_WRITE)
187 ret = 0;
188 else
189 ret = -2;
190 } else {
191 if (prot & PAGE_READ)
192 ret = 0;
193 else
194 ret = -2;
195 }
196
197 return ret;
198}
199
Anthony Liguoric227f092009-10-01 16:12:16 -0500200static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
Blue Swirl636aa202009-08-16 09:06:54 +0000201 target_ulong pte1, int h, int rw, int type)
j_mayer76a66252007-03-07 08:32:30 +0000202{
j_mayercaa40392007-09-19 04:36:02 +0000203 target_ulong ptem, mmask;
j_mayerb227a8e2007-10-14 10:21:20 +0000204 int access, ret, pteh, ptev, pp;
j_mayer76a66252007-03-07 08:32:30 +0000205
206 access = 0;
207 ret = -1;
208 /* Check validity and table match */
j_mayercaa40392007-09-19 04:36:02 +0000209#if defined(TARGET_PPC64)
210 if (is_64b) {
211 ptev = pte64_is_valid(pte0);
212 pteh = (pte0 >> 1) & 1;
213 } else
214#endif
215 {
216 ptev = pte_is_valid(pte0);
217 pteh = (pte0 >> 6) & 1;
218 }
219 if (ptev && h == pteh) {
j_mayer76a66252007-03-07 08:32:30 +0000220 /* Check vsid & api */
j_mayercaa40392007-09-19 04:36:02 +0000221#if defined(TARGET_PPC64)
222 if (is_64b) {
223 ptem = pte0 & PTE64_PTEM_MASK;
224 mmask = PTE64_CHECK_MASK;
j_mayerb227a8e2007-10-14 10:21:20 +0000225 pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
blueswir129c8ca62009-03-07 20:57:01 +0000226 ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
j_mayerb227a8e2007-10-14 10:21:20 +0000227 ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
j_mayercaa40392007-09-19 04:36:02 +0000228 } else
229#endif
230 {
231 ptem = pte0 & PTE_PTEM_MASK;
232 mmask = PTE_CHECK_MASK;
j_mayerb227a8e2007-10-14 10:21:20 +0000233 pp = pte1 & 0x00000003;
j_mayercaa40392007-09-19 04:36:02 +0000234 }
235 if (ptem == ctx->ptem) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500236 if (ctx->raddr != (target_phys_addr_t)-1ULL) {
j_mayer76a66252007-03-07 08:32:30 +0000237 /* all matches should have equal RPN, WIMG & PP */
j_mayercaa40392007-09-19 04:36:02 +0000238 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
aliguori93fcfe32009-01-15 22:34:14 +0000239 qemu_log("Bad RPN/WIMG/PP\n");
j_mayer76a66252007-03-07 08:32:30 +0000240 return -3;
241 }
242 }
243 /* Compute access rights */
j_mayerb227a8e2007-10-14 10:21:20 +0000244 access = pp_check(ctx->key, pp, ctx->nx);
j_mayer76a66252007-03-07 08:32:30 +0000245 /* Keep the matching PTE informations */
246 ctx->raddr = pte1;
247 ctx->prot = access;
j_mayerb227a8e2007-10-14 10:21:20 +0000248 ret = check_prot(ctx->prot, rw, type);
249 if (ret == 0) {
j_mayer76a66252007-03-07 08:32:30 +0000250 /* Access granted */
aliguorid12d51d2009-01-15 21:48:06 +0000251 LOG_MMU("PTE access granted !\n");
j_mayer76a66252007-03-07 08:32:30 +0000252 } else {
253 /* Access right violation */
aliguorid12d51d2009-01-15 21:48:06 +0000254 LOG_MMU("PTE access rejected\n");
j_mayer76a66252007-03-07 08:32:30 +0000255 }
256 }
257 }
258
259 return ret;
260}
261
Anthony Liguoric227f092009-10-01 16:12:16 -0500262static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
Blue Swirl636aa202009-08-16 09:06:54 +0000263 target_ulong pte1, int h, int rw, int type)
j_mayercaa40392007-09-19 04:36:02 +0000264{
j_mayerb227a8e2007-10-14 10:21:20 +0000265 return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
j_mayercaa40392007-09-19 04:36:02 +0000266}
267
268#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -0500269static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
Blue Swirl636aa202009-08-16 09:06:54 +0000270 target_ulong pte1, int h, int rw, int type)
j_mayercaa40392007-09-19 04:36:02 +0000271{
j_mayerb227a8e2007-10-14 10:21:20 +0000272 return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
j_mayercaa40392007-09-19 04:36:02 +0000273}
274#endif
275
Anthony Liguoric227f092009-10-01 16:12:16 -0500276static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
Blue Swirl636aa202009-08-16 09:06:54 +0000277 int ret, int rw)
j_mayer76a66252007-03-07 08:32:30 +0000278{
279 int store = 0;
280
281 /* Update page flags */
282 if (!(*pte1p & 0x00000100)) {
283 /* Update accessed flag */
284 *pte1p |= 0x00000100;
285 store = 1;
286 }
287 if (!(*pte1p & 0x00000080)) {
288 if (rw == 1 && ret == 0) {
289 /* Update changed flag */
290 *pte1p |= 0x00000080;
291 store = 1;
292 } else {
293 /* Force page fault for first write access */
294 ctx->prot &= ~PAGE_WRITE;
295 }
296 }
297
298 return store;
299}
300
301/* Software driven TLB helpers */
Blue Swirl636aa202009-08-16 09:06:54 +0000302static inline int ppc6xx_tlb_getnum(CPUState *env, target_ulong eaddr, int way,
303 int is_code)
j_mayer76a66252007-03-07 08:32:30 +0000304{
305 int nr;
306
307 /* Select TLB num in a way from address */
308 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
309 /* Select TLB way */
310 nr += env->tlb_per_way * way;
311 /* 6xx have separate TLBs for instructions and data */
312 if (is_code && env->id_tlbs == 1)
313 nr += env->nb_tlb;
314
315 return nr;
316}
317
Blue Swirl636aa202009-08-16 09:06:54 +0000318static inline void ppc6xx_tlb_invalidate_all(CPUState *env)
j_mayer76a66252007-03-07 08:32:30 +0000319{
Anthony Liguoric227f092009-10-01 16:12:16 -0500320 ppc6xx_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +0000321 int nr, max;
322
aliguorid12d51d2009-01-15 21:48:06 +0000323 //LOG_SWTLB("Invalidate all TLBs\n");
j_mayer76a66252007-03-07 08:32:30 +0000324 /* Invalidate all defined software TLB */
325 max = env->nb_tlb;
326 if (env->id_tlbs == 1)
327 max *= 2;
328 for (nr = 0; nr < max; nr++) {
j_mayer1d0a48f2007-03-31 11:10:49 +0000329 tlb = &env->tlb[nr].tlb6;
j_mayer76a66252007-03-07 08:32:30 +0000330 pte_invalidate(&tlb->pte0);
331 }
j_mayer76a66252007-03-07 08:32:30 +0000332 tlb_flush(env, 1);
j_mayer76a66252007-03-07 08:32:30 +0000333}
334
Blue Swirl636aa202009-08-16 09:06:54 +0000335static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env,
336 target_ulong eaddr,
337 int is_code, int match_epn)
j_mayer76a66252007-03-07 08:32:30 +0000338{
j_mayer4a057712007-04-19 08:42:21 +0000339#if !defined(FLUSH_ALL_TLBS)
Anthony Liguoric227f092009-10-01 16:12:16 -0500340 ppc6xx_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +0000341 int way, nr;
342
j_mayer76a66252007-03-07 08:32:30 +0000343 /* Invalidate ITLB + DTLB, all ways */
344 for (way = 0; way < env->nb_ways; way++) {
345 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
j_mayer1d0a48f2007-03-31 11:10:49 +0000346 tlb = &env->tlb[nr].tlb6;
j_mayer76a66252007-03-07 08:32:30 +0000347 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
Blue Swirl90e189e2009-08-16 11:13:18 +0000348 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
349 env->nb_tlb, eaddr);
j_mayer76a66252007-03-07 08:32:30 +0000350 pte_invalidate(&tlb->pte0);
351 tlb_flush_page(env, tlb->EPN);
352 }
353 }
354#else
355 /* XXX: PowerPC specification say this is valid as well */
356 ppc6xx_tlb_invalidate_all(env);
357#endif
358}
359
Blue Swirl636aa202009-08-16 09:06:54 +0000360static inline void ppc6xx_tlb_invalidate_virt(CPUState *env,
361 target_ulong eaddr, int is_code)
j_mayer76a66252007-03-07 08:32:30 +0000362{
363 __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
364}
365
366void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
367 target_ulong pte0, target_ulong pte1)
368{
Anthony Liguoric227f092009-10-01 16:12:16 -0500369 ppc6xx_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +0000370 int nr;
371
372 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
j_mayer1d0a48f2007-03-31 11:10:49 +0000373 tlb = &env->tlb[nr].tlb6;
Blue Swirl90e189e2009-08-16 11:13:18 +0000374 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
375 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
j_mayer76a66252007-03-07 08:32:30 +0000376 /* Invalidate any pending reference in Qemu for this virtual address */
377 __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
378 tlb->pte0 = pte0;
379 tlb->pte1 = pte1;
380 tlb->EPN = EPN;
j_mayer76a66252007-03-07 08:32:30 +0000381 /* Store last way for LRU mechanism */
382 env->last_way = way;
383}
384
Anthony Liguoric227f092009-10-01 16:12:16 -0500385static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
Blue Swirl636aa202009-08-16 09:06:54 +0000386 target_ulong eaddr, int rw, int access_type)
j_mayer76a66252007-03-07 08:32:30 +0000387{
Anthony Liguoric227f092009-10-01 16:12:16 -0500388 ppc6xx_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +0000389 int nr, best, way;
390 int ret;
j_mayerd9bce9d2007-03-17 14:02:15 +0000391
j_mayer76a66252007-03-07 08:32:30 +0000392 best = -1;
393 ret = -1; /* No TLB found */
394 for (way = 0; way < env->nb_ways; way++) {
395 nr = ppc6xx_tlb_getnum(env, eaddr, way,
396 access_type == ACCESS_CODE ? 1 : 0);
j_mayer1d0a48f2007-03-31 11:10:49 +0000397 tlb = &env->tlb[nr].tlb6;
j_mayer76a66252007-03-07 08:32:30 +0000398 /* This test "emulates" the PTE index match for hardware TLBs */
399 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
Blue Swirl90e189e2009-08-16 11:13:18 +0000400 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
401 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
402 pte_is_valid(tlb->pte0) ? "valid" : "inval",
403 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
j_mayer76a66252007-03-07 08:32:30 +0000404 continue;
405 }
Blue Swirl90e189e2009-08-16 11:13:18 +0000406 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
407 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
408 pte_is_valid(tlb->pte0) ? "valid" : "inval",
409 tlb->EPN, eaddr, tlb->pte1,
410 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
j_mayerb227a8e2007-10-14 10:21:20 +0000411 switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
j_mayer76a66252007-03-07 08:32:30 +0000412 case -3:
413 /* TLB inconsistency */
414 return -1;
415 case -2:
416 /* Access violation */
417 ret = -2;
418 best = nr;
419 break;
420 case -1:
421 default:
422 /* No match */
423 break;
424 case 0:
425 /* access granted */
426 /* XXX: we should go on looping to check all TLBs consistency
427 * but we can speed-up the whole thing as the
428 * result would be undefined if TLBs are not consistent.
429 */
430 ret = 0;
431 best = nr;
432 goto done;
433 }
434 }
435 if (best != -1) {
436 done:
Blue Swirl90e189e2009-08-16 11:13:18 +0000437 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
438 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
j_mayer76a66252007-03-07 08:32:30 +0000439 /* Update page flags */
j_mayer1d0a48f2007-03-31 11:10:49 +0000440 pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
j_mayer76a66252007-03-07 08:32:30 +0000441 }
442
443 return ret;
444}
445
446/* Perform BAT hit & translation */
Blue Swirl636aa202009-08-16 09:06:54 +0000447static inline void bat_size_prot(CPUState *env, target_ulong *blp, int *validp,
448 int *protp, target_ulong *BATu,
449 target_ulong *BATl)
j_mayerfaadf502007-11-03 13:37:12 +0000450{
451 target_ulong bl;
452 int pp, valid, prot;
453
454 bl = (*BATu & 0x00001FFC) << 15;
455 valid = 0;
456 prot = 0;
457 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
458 ((msr_pr != 0) && (*BATu & 0x00000001))) {
459 valid = 1;
460 pp = *BATl & 0x00000003;
461 if (pp != 0) {
462 prot = PAGE_READ | PAGE_EXEC;
463 if (pp == 0x2)
464 prot |= PAGE_WRITE;
465 }
466 }
467 *blp = bl;
468 *validp = valid;
469 *protp = prot;
470}
471
Blue Swirl636aa202009-08-16 09:06:54 +0000472static inline void bat_601_size_prot(CPUState *env, target_ulong *blp,
473 int *validp, int *protp,
474 target_ulong *BATu, target_ulong *BATl)
j_mayerfaadf502007-11-03 13:37:12 +0000475{
476 target_ulong bl;
477 int key, pp, valid, prot;
478
479 bl = (*BATl & 0x0000003F) << 17;
Blue Swirl90e189e2009-08-16 11:13:18 +0000480 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
481 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
j_mayerfaadf502007-11-03 13:37:12 +0000482 prot = 0;
483 valid = (*BATl >> 6) & 1;
484 if (valid) {
485 pp = *BATu & 0x00000003;
486 if (msr_pr == 0)
487 key = (*BATu >> 3) & 1;
488 else
489 key = (*BATu >> 2) & 1;
490 prot = pp_check(key, pp, 0);
491 }
492 *blp = bl;
493 *validp = valid;
494 *protp = prot;
495}
496
Anthony Liguoric227f092009-10-01 16:12:16 -0500497static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
Blue Swirl636aa202009-08-16 09:06:54 +0000498 int rw, int type)
j_mayer76a66252007-03-07 08:32:30 +0000499{
500 target_ulong *BATlt, *BATut, *BATu, *BATl;
501 target_ulong base, BEPIl, BEPIu, bl;
j_mayerfaadf502007-11-03 13:37:12 +0000502 int i, valid, prot;
bellard9a64fbe2004-01-04 22:58:38 +0000503 int ret = -1;
504
Blue Swirl90e189e2009-08-16 11:13:18 +0000505 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
506 type == ACCESS_CODE ? 'I' : 'D', virtual);
bellard9a64fbe2004-01-04 22:58:38 +0000507 switch (type) {
508 case ACCESS_CODE:
509 BATlt = env->IBAT[1];
510 BATut = env->IBAT[0];
511 break;
512 default:
513 BATlt = env->DBAT[1];
514 BATut = env->DBAT[0];
515 break;
516 }
bellard9a64fbe2004-01-04 22:58:38 +0000517 base = virtual & 0xFFFC0000;
j_mayerfaadf502007-11-03 13:37:12 +0000518 for (i = 0; i < env->nb_BATs; i++) {
bellard9a64fbe2004-01-04 22:58:38 +0000519 BATu = &BATut[i];
520 BATl = &BATlt[i];
521 BEPIu = *BATu & 0xF0000000;
522 BEPIl = *BATu & 0x0FFE0000;
j_mayerfaadf502007-11-03 13:37:12 +0000523 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
524 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
525 } else {
526 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
527 }
Blue Swirl90e189e2009-08-16 11:13:18 +0000528 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
529 " BATl " TARGET_FMT_lx "\n", __func__,
530 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
bellard9a64fbe2004-01-04 22:58:38 +0000531 if ((virtual & 0xF0000000) == BEPIu &&
532 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
533 /* BAT matches */
j_mayerfaadf502007-11-03 13:37:12 +0000534 if (valid != 0) {
bellard9a64fbe2004-01-04 22:58:38 +0000535 /* Get physical address */
j_mayer76a66252007-03-07 08:32:30 +0000536 ctx->raddr = (*BATl & 0xF0000000) |
bellard9a64fbe2004-01-04 22:58:38 +0000537 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
bellarda541f292004-04-12 20:39:29 +0000538 (virtual & 0x0001F000);
j_mayerb227a8e2007-10-14 10:21:20 +0000539 /* Compute access rights */
j_mayerfaadf502007-11-03 13:37:12 +0000540 ctx->prot = prot;
j_mayerb227a8e2007-10-14 10:21:20 +0000541 ret = check_prot(ctx->prot, rw, type);
aliguorid12d51d2009-01-15 21:48:06 +0000542 if (ret == 0)
Blue Swirl90e189e2009-08-16 11:13:18 +0000543 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
aliguorid12d51d2009-01-15 21:48:06 +0000544 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
545 ctx->prot & PAGE_WRITE ? 'W' : '-');
bellard9a64fbe2004-01-04 22:58:38 +0000546 break;
547 }
548 }
549 }
550 if (ret < 0) {
aliguorid12d51d2009-01-15 21:48:06 +0000551#if defined(DEBUG_BATS)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000552 if (qemu_log_enabled()) {
Blue Swirl90e189e2009-08-16 11:13:18 +0000553 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
j_mayer4a057712007-04-19 08:42:21 +0000554 for (i = 0; i < 4; i++) {
555 BATu = &BATut[i];
556 BATl = &BATlt[i];
557 BEPIu = *BATu & 0xF0000000;
558 BEPIl = *BATu & 0x0FFE0000;
559 bl = (*BATu & 0x00001FFC) << 15;
Blue Swirl90e189e2009-08-16 11:13:18 +0000560 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
561 " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " "
562 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
Blue Swirl0bf9e312009-07-20 17:19:25 +0000563 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
564 *BATu, *BATl, BEPIu, BEPIl, bl);
j_mayer4a057712007-04-19 08:42:21 +0000565 }
bellard9a64fbe2004-01-04 22:58:38 +0000566 }
567#endif
bellard9a64fbe2004-01-04 22:58:38 +0000568 }
569 /* No hit */
570 return ret;
571}
572
573/* PTE table lookup */
Anthony Liguoric227f092009-10-01 16:12:16 -0500574static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
Blue Swirl636aa202009-08-16 09:06:54 +0000575 int type, int target_page_bits)
bellard9a64fbe2004-01-04 22:58:38 +0000576{
j_mayer76a66252007-03-07 08:32:30 +0000577 target_ulong base, pte0, pte1;
578 int i, good = -1;
j_mayercaa40392007-09-19 04:36:02 +0000579 int ret, r;
bellard9a64fbe2004-01-04 22:58:38 +0000580
j_mayer76a66252007-03-07 08:32:30 +0000581 ret = -1; /* No entry found */
582 base = ctx->pg_addr[h];
bellard9a64fbe2004-01-04 22:58:38 +0000583 for (i = 0; i < 8; i++) {
j_mayercaa40392007-09-19 04:36:02 +0000584#if defined(TARGET_PPC64)
585 if (is_64b) {
586 pte0 = ldq_phys(base + (i * 16));
blueswir15b5aba42009-03-07 20:51:18 +0000587 pte1 = ldq_phys(base + (i * 16) + 8);
588
589 /* We have a TLB that saves 4K pages, so let's
590 * split a huge page to 4k chunks */
591 if (target_page_bits != TARGET_PAGE_BITS)
592 pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
593 & TARGET_PAGE_MASK;
594
j_mayerb227a8e2007-10-14 10:21:20 +0000595 r = pte64_check(ctx, pte0, pte1, h, rw, type);
Blue Swirl90e189e2009-08-16 11:13:18 +0000596 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
597 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
598 base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
599 (int)((pte0 >> 1) & 1), ctx->ptem);
j_mayercaa40392007-09-19 04:36:02 +0000600 } else
601#endif
602 {
603 pte0 = ldl_phys(base + (i * 8));
604 pte1 = ldl_phys(base + (i * 8) + 4);
j_mayerb227a8e2007-10-14 10:21:20 +0000605 r = pte32_check(ctx, pte0, pte1, h, rw, type);
Blue Swirl90e189e2009-08-16 11:13:18 +0000606 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
607 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
608 base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
609 (int)((pte0 >> 6) & 1), ctx->ptem);
j_mayer12de9a32007-10-05 22:06:02 +0000610 }
j_mayercaa40392007-09-19 04:36:02 +0000611 switch (r) {
j_mayer76a66252007-03-07 08:32:30 +0000612 case -3:
613 /* PTE inconsistency */
614 return -1;
615 case -2:
616 /* Access violation */
617 ret = -2;
618 good = i;
619 break;
620 case -1:
621 default:
622 /* No PTE match */
623 break;
624 case 0:
625 /* access granted */
626 /* XXX: we should go on looping to check all PTEs consistency
627 * but if we can speed-up the whole thing as the
628 * result would be undefined if PTEs are not consistent.
629 */
630 ret = 0;
631 good = i;
632 goto done;
bellard9a64fbe2004-01-04 22:58:38 +0000633 }
634 }
635 if (good != -1) {
j_mayer76a66252007-03-07 08:32:30 +0000636 done:
Blue Swirl90e189e2009-08-16 11:13:18 +0000637 LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
638 ctx->raddr, ctx->prot, ret);
bellard9a64fbe2004-01-04 22:58:38 +0000639 /* Update page flags */
j_mayer76a66252007-03-07 08:32:30 +0000640 pte1 = ctx->raddr;
j_mayercaa40392007-09-19 04:36:02 +0000641 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
642#if defined(TARGET_PPC64)
643 if (is_64b) {
644 stq_phys_notdirty(base + (good * 16) + 8, pte1);
645 } else
646#endif
647 {
648 stl_phys_notdirty(base + (good * 8) + 4, pte1);
649 }
650 }
bellard9a64fbe2004-01-04 22:58:38 +0000651 }
652
653 return ret;
654}
655
Anthony Liguoric227f092009-10-01 16:12:16 -0500656static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type,
Blue Swirl636aa202009-08-16 09:06:54 +0000657 int target_page_bits)
j_mayercaa40392007-09-19 04:36:02 +0000658{
blueswir15b5aba42009-03-07 20:51:18 +0000659 return _find_pte(ctx, 0, h, rw, type, target_page_bits);
j_mayercaa40392007-09-19 04:36:02 +0000660}
661
662#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -0500663static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type,
Blue Swirl636aa202009-08-16 09:06:54 +0000664 int target_page_bits)
j_mayercaa40392007-09-19 04:36:02 +0000665{
blueswir15b5aba42009-03-07 20:51:18 +0000666 return _find_pte(ctx, 1, h, rw, type, target_page_bits);
j_mayercaa40392007-09-19 04:36:02 +0000667}
668#endif
669
Anthony Liguoric227f092009-10-01 16:12:16 -0500670static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
Blue Swirl636aa202009-08-16 09:06:54 +0000671 int type, int target_page_bits)
j_mayercaa40392007-09-19 04:36:02 +0000672{
673#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +0000674 if (env->mmu_model & POWERPC_MMU_64)
blueswir15b5aba42009-03-07 20:51:18 +0000675 return find_pte64(ctx, h, rw, type, target_page_bits);
j_mayercaa40392007-09-19 04:36:02 +0000676#endif
677
blueswir15b5aba42009-03-07 20:51:18 +0000678 return find_pte32(ctx, h, rw, type, target_page_bits);
j_mayercaa40392007-09-19 04:36:02 +0000679}
680
j_mayercaa40392007-09-19 04:36:02 +0000681#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -0500682static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
j_mayereacc3242007-10-14 09:06:19 +0000683{
Anthony Liguoric227f092009-10-01 16:12:16 -0500684 ppc_slb_t *retval = &env->slb[nr];
blueswir18eee0af2009-03-07 20:57:42 +0000685
686#if 0 // XXX implement bridge mode?
687 if (env->spr[SPR_ASR] & 1) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500688 target_phys_addr_t sr_base;
blueswir18eee0af2009-03-07 20:57:42 +0000689
690 sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
691 sr_base += (12 * nr);
692
693 retval->tmp64 = ldq_phys(sr_base);
694 retval->tmp = ldl_phys(sr_base + 8);
695 }
696#endif
697
698 return retval;
j_mayereacc3242007-10-14 09:06:19 +0000699}
700
Anthony Liguoric227f092009-10-01 16:12:16 -0500701static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
j_mayereacc3242007-10-14 09:06:19 +0000702{
Anthony Liguoric227f092009-10-01 16:12:16 -0500703 ppc_slb_t *entry = &env->slb[nr];
blueswir18eee0af2009-03-07 20:57:42 +0000704
705 if (slb == entry)
706 return;
707
708 entry->tmp64 = slb->tmp64;
709 entry->tmp = slb->tmp;
710}
711
Anthony Liguoric227f092009-10-01 16:12:16 -0500712static inline int slb_is_valid(ppc_slb_t *slb)
blueswir18eee0af2009-03-07 20:57:42 +0000713{
714 return (int)(slb->tmp64 & 0x0000000008000000ULL);
715}
716
Anthony Liguoric227f092009-10-01 16:12:16 -0500717static inline void slb_invalidate(ppc_slb_t *slb)
blueswir18eee0af2009-03-07 20:57:42 +0000718{
719 slb->tmp64 &= ~0x0000000008000000ULL;
j_mayereacc3242007-10-14 09:06:19 +0000720}
721
Blue Swirl636aa202009-08-16 09:06:54 +0000722static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
723 target_ulong *vsid, target_ulong *page_mask,
724 int *attr, int *target_page_bits)
j_mayercaa40392007-09-19 04:36:02 +0000725{
j_mayercaa40392007-09-19 04:36:02 +0000726 target_ulong mask;
j_mayercaa40392007-09-19 04:36:02 +0000727 int n, ret;
j_mayercaa40392007-09-19 04:36:02 +0000728
729 ret = -5;
Blue Swirl90e189e2009-08-16 11:13:18 +0000730 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
j_mayer12de9a32007-10-05 22:06:02 +0000731 mask = 0x0000000000000000ULL; /* Avoid gcc warning */
j_mayereacc3242007-10-14 09:06:19 +0000732 for (n = 0; n < env->slb_nr; n++) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500733 ppc_slb_t *slb = slb_get_entry(env, n);
blueswir18eee0af2009-03-07 20:57:42 +0000734
735 LOG_SLB("%s: seg %d %016" PRIx64 " %08"
736 PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
737 if (slb_is_valid(slb)) {
j_mayercaa40392007-09-19 04:36:02 +0000738 /* SLB entry is valid */
blueswir18eee0af2009-03-07 20:57:42 +0000739 if (slb->tmp & 0x8) {
blueswir15b5aba42009-03-07 20:51:18 +0000740 /* 1 TB Segment */
j_mayercaa40392007-09-19 04:36:02 +0000741 mask = 0xFFFF000000000000ULL;
blueswir15b5aba42009-03-07 20:51:18 +0000742 if (target_page_bits)
743 *target_page_bits = 24; // XXX 16M pages?
744 } else {
745 /* 256MB Segment */
746 mask = 0xFFFFFFFFF0000000ULL;
747 if (target_page_bits)
748 *target_page_bits = TARGET_PAGE_BITS;
j_mayercaa40392007-09-19 04:36:02 +0000749 }
blueswir18eee0af2009-03-07 20:57:42 +0000750 if ((eaddr & mask) == (slb->tmp64 & mask)) {
j_mayercaa40392007-09-19 04:36:02 +0000751 /* SLB match */
blueswir18eee0af2009-03-07 20:57:42 +0000752 *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
j_mayercaa40392007-09-19 04:36:02 +0000753 *page_mask = ~mask;
blueswir18eee0af2009-03-07 20:57:42 +0000754 *attr = slb->tmp & 0xFF;
j_mayereacc3242007-10-14 09:06:19 +0000755 ret = n;
j_mayercaa40392007-09-19 04:36:02 +0000756 break;
757 }
758 }
j_mayercaa40392007-09-19 04:36:02 +0000759 }
760
761 return ret;
762}
j_mayer12de9a32007-10-05 22:06:02 +0000763
j_mayereacc3242007-10-14 09:06:19 +0000764void ppc_slb_invalidate_all (CPUPPCState *env)
765{
j_mayereacc3242007-10-14 09:06:19 +0000766 int n, do_invalidate;
767
768 do_invalidate = 0;
j_mayer2c1ee062007-10-26 00:37:04 +0000769 /* XXX: Warning: slbia never invalidates the first segment */
770 for (n = 1; n < env->slb_nr; n++) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500771 ppc_slb_t *slb = slb_get_entry(env, n);
blueswir18eee0af2009-03-07 20:57:42 +0000772
773 if (slb_is_valid(slb)) {
774 slb_invalidate(slb);
775 slb_set_entry(env, n, slb);
j_mayereacc3242007-10-14 09:06:19 +0000776 /* XXX: given the fact that segment size is 256 MB or 1TB,
777 * and we still don't have a tlb_flush_mask(env, n, mask)
778 * in Qemu, we just invalidate all TLBs
779 */
780 do_invalidate = 1;
781 }
j_mayereacc3242007-10-14 09:06:19 +0000782 }
783 if (do_invalidate)
784 tlb_flush(env, 1);
785}
786
787void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
788{
j_mayereacc3242007-10-14 09:06:19 +0000789 target_ulong vsid, page_mask;
j_mayereacc3242007-10-14 09:06:19 +0000790 int attr;
791 int n;
792
blueswir15b5aba42009-03-07 20:51:18 +0000793 n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
j_mayereacc3242007-10-14 09:06:19 +0000794 if (n >= 0) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500795 ppc_slb_t *slb = slb_get_entry(env, n);
blueswir18eee0af2009-03-07 20:57:42 +0000796
797 if (slb_is_valid(slb)) {
798 slb_invalidate(slb);
799 slb_set_entry(env, n, slb);
j_mayereacc3242007-10-14 09:06:19 +0000800 /* XXX: given the fact that segment size is 256 MB or 1TB,
801 * and we still don't have a tlb_flush_mask(env, n, mask)
802 * in Qemu, we just invalidate all TLBs
803 */
804 tlb_flush(env, 1);
805 }
806 }
807}
808
j_mayer12de9a32007-10-05 22:06:02 +0000809target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
810{
j_mayer12de9a32007-10-05 22:06:02 +0000811 target_ulong rt;
Anthony Liguoric227f092009-10-01 16:12:16 -0500812 ppc_slb_t *slb = slb_get_entry(env, slb_nr);
j_mayer12de9a32007-10-05 22:06:02 +0000813
blueswir18eee0af2009-03-07 20:57:42 +0000814 if (slb_is_valid(slb)) {
j_mayer12de9a32007-10-05 22:06:02 +0000815 /* SLB entry is valid */
816 /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
blueswir18eee0af2009-03-07 20:57:42 +0000817 rt = slb->tmp >> 8; /* 65:88 => 40:63 */
818 rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
j_mayer12de9a32007-10-05 22:06:02 +0000819 /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
blueswir18eee0af2009-03-07 20:57:42 +0000820 rt |= ((slb->tmp >> 4) & 0xF) << 27;
j_mayer12de9a32007-10-05 22:06:02 +0000821 } else {
822 rt = 0;
823 }
blueswir18eee0af2009-03-07 20:57:42 +0000824 LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
Blue Swirl90e189e2009-08-16 11:13:18 +0000825 TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
j_mayer12de9a32007-10-05 22:06:02 +0000826
827 return rt;
828}
829
blueswir1f6b868fc2009-03-07 20:50:01 +0000830void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
j_mayer12de9a32007-10-05 22:06:02 +0000831{
Anthony Liguoric227f092009-10-01 16:12:16 -0500832 ppc_slb_t *slb;
j_mayer12de9a32007-10-05 22:06:02 +0000833
blueswir1f6b868fc2009-03-07 20:50:01 +0000834 uint64_t vsid;
835 uint64_t esid;
836 int flags, valid, slb_nr;
837
838 vsid = rs >> 12;
839 flags = ((rs >> 8) & 0xf);
840
841 esid = rb >> 28;
842 valid = (rb & (1 << 27));
843 slb_nr = rb & 0xfff;
844
blueswir18eee0af2009-03-07 20:57:42 +0000845 slb = slb_get_entry(env, slb_nr);
846 slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
847 slb->tmp = (vsid << 8) | (flags << 3);
blueswir1f6b868fc2009-03-07 20:50:01 +0000848
Blue Swirl90e189e2009-08-16 11:13:18 +0000849 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
850 " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
851 slb->tmp);
blueswir1f6b868fc2009-03-07 20:50:01 +0000852
blueswir18eee0af2009-03-07 20:57:42 +0000853 slb_set_entry(env, slb_nr, slb);
j_mayer12de9a32007-10-05 22:06:02 +0000854}
j_mayercaa40392007-09-19 04:36:02 +0000855#endif /* defined(TARGET_PPC64) */
856
bellard9a64fbe2004-01-04 22:58:38 +0000857/* Perform segment based translation */
Anthony Liguoric227f092009-10-01 16:12:16 -0500858static inline target_phys_addr_t get_pgaddr(target_phys_addr_t sdr1,
Blue Swirl636aa202009-08-16 09:06:54 +0000859 int sdr_sh,
Anthony Liguoric227f092009-10-01 16:12:16 -0500860 target_phys_addr_t hash,
861 target_phys_addr_t mask)
j_mayer12de9a32007-10-05 22:06:02 +0000862{
Anthony Liguoric227f092009-10-01 16:12:16 -0500863 return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);
j_mayer12de9a32007-10-05 22:06:02 +0000864}
865
Anthony Liguoric227f092009-10-01 16:12:16 -0500866static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
Blue Swirl636aa202009-08-16 09:06:54 +0000867 target_ulong eaddr, int rw, int type)
bellard9a64fbe2004-01-04 22:58:38 +0000868{
Anthony Liguoric227f092009-10-01 16:12:16 -0500869 target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
j_mayercaa40392007-09-19 04:36:02 +0000870 target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
871#if defined(TARGET_PPC64)
872 int attr;
bellard9a64fbe2004-01-04 22:58:38 +0000873#endif
blueswir15b5aba42009-03-07 20:51:18 +0000874 int ds, vsid_sh, sdr_sh, pr, target_page_bits;
j_mayercaa40392007-09-19 04:36:02 +0000875 int ret, ret2;
876
j_mayer0411a972007-10-25 21:35:50 +0000877 pr = msr_pr;
j_mayercaa40392007-09-19 04:36:02 +0000878#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +0000879 if (env->mmu_model & POWERPC_MMU_64) {
aliguorid12d51d2009-01-15 21:48:06 +0000880 LOG_MMU("Check SLBs\n");
blueswir15b5aba42009-03-07 20:51:18 +0000881 ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
882 &target_page_bits);
j_mayercaa40392007-09-19 04:36:02 +0000883 if (ret < 0)
884 return ret;
j_mayer0411a972007-10-25 21:35:50 +0000885 ctx->key = ((attr & 0x40) && (pr != 0)) ||
886 ((attr & 0x80) && (pr == 0)) ? 1 : 0;
j_mayercaa40392007-09-19 04:36:02 +0000887 ds = 0;
blueswir15b5aba42009-03-07 20:51:18 +0000888 ctx->nx = attr & 0x10 ? 1 : 0;
889 ctx->eaddr = eaddr;
j_mayercaa40392007-09-19 04:36:02 +0000890 vsid_mask = 0x00003FFFFFFFFF80ULL;
891 vsid_sh = 7;
892 sdr_sh = 18;
893 sdr_mask = 0x3FF80;
894 } else
895#endif /* defined(TARGET_PPC64) */
896 {
897 sr = env->sr[eaddr >> 28];
898 page_mask = 0x0FFFFFFF;
j_mayer0411a972007-10-25 21:35:50 +0000899 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
900 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
j_mayercaa40392007-09-19 04:36:02 +0000901 ds = sr & 0x80000000 ? 1 : 0;
j_mayerb227a8e2007-10-14 10:21:20 +0000902 ctx->nx = sr & 0x10000000 ? 1 : 0;
j_mayercaa40392007-09-19 04:36:02 +0000903 vsid = sr & 0x00FFFFFF;
904 vsid_mask = 0x01FFFFC0;
905 vsid_sh = 6;
906 sdr_sh = 16;
907 sdr_mask = 0xFFC0;
blueswir15b5aba42009-03-07 20:51:18 +0000908 target_page_bits = TARGET_PAGE_BITS;
Blue Swirl90e189e2009-08-16 11:13:18 +0000909 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
910 TARGET_FMT_lx " lr=" TARGET_FMT_lx
911 " ir=%d dr=%d pr=%d %d t=%d\n",
912 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
913 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
j_mayercaa40392007-09-19 04:36:02 +0000914 }
Blue Swirl90e189e2009-08-16 11:13:18 +0000915 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
916 ctx->key, ds, ctx->nx, vsid);
j_mayercaa40392007-09-19 04:36:02 +0000917 ret = -1;
918 if (!ds) {
bellard9a64fbe2004-01-04 22:58:38 +0000919 /* Check if instruction fetch is allowed, if needed */
j_mayerb227a8e2007-10-14 10:21:20 +0000920 if (type != ACCESS_CODE || ctx->nx == 0) {
bellard9a64fbe2004-01-04 22:58:38 +0000921 /* Page address translation */
j_mayer76a66252007-03-07 08:32:30 +0000922 /* Primary table address */
923 sdr = env->sdr1;
blueswir15b5aba42009-03-07 20:51:18 +0000924 pgidx = (eaddr & page_mask) >> target_page_bits;
j_mayer12de9a32007-10-05 22:06:02 +0000925#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +0000926 if (env->mmu_model & POWERPC_MMU_64) {
j_mayer12de9a32007-10-05 22:06:02 +0000927 htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
928 /* XXX: this is false for 1 TB segments */
929 hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
930 } else
931#endif
932 {
933 htab_mask = sdr & 0x000001FF;
934 hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
935 }
936 mask = (htab_mask << sdr_sh) | sdr_mask;
Blue Swirl90e189e2009-08-16 11:13:18 +0000937 LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
938 " mask " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
939 sdr, sdr_sh, hash, mask, page_mask);
j_mayercaa40392007-09-19 04:36:02 +0000940 ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
j_mayer76a66252007-03-07 08:32:30 +0000941 /* Secondary table address */
j_mayercaa40392007-09-19 04:36:02 +0000942 hash = (~hash) & vsid_mask;
Blue Swirl90e189e2009-08-16 11:13:18 +0000943 LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
944 " mask " TARGET_FMT_plx "\n", sdr, sdr_sh, hash, mask);
j_mayercaa40392007-09-19 04:36:02 +0000945 ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
946#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +0000947 if (env->mmu_model & POWERPC_MMU_64) {
j_mayercaa40392007-09-19 04:36:02 +0000948 /* Only 5 bits of the page index are used in the AVPN */
blueswir15b5aba42009-03-07 20:51:18 +0000949 if (target_page_bits > 23) {
950 ctx->ptem = (vsid << 12) |
951 ((pgidx << (target_page_bits - 16)) & 0xF80);
952 } else {
953 ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
954 }
j_mayercaa40392007-09-19 04:36:02 +0000955 } else
956#endif
957 {
958 ctx->ptem = (vsid << 7) | (pgidx >> 10);
959 }
j_mayer76a66252007-03-07 08:32:30 +0000960 /* Initialize real address with an invalid value */
Anthony Liguoric227f092009-10-01 16:12:16 -0500961 ctx->raddr = (target_phys_addr_t)-1ULL;
j_mayer7dbe11a2007-10-01 05:16:57 +0000962 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
963 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
j_mayer76a66252007-03-07 08:32:30 +0000964 /* Software TLB search */
965 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
j_mayer76a66252007-03-07 08:32:30 +0000966 } else {
Blue Swirl90e189e2009-08-16 11:13:18 +0000967 LOG_MMU("0 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
968 "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
969 " pg_addr=" TARGET_FMT_plx "\n",
970 sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
j_mayer76a66252007-03-07 08:32:30 +0000971 /* Primary table lookup */
blueswir15b5aba42009-03-07 20:51:18 +0000972 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
j_mayer76a66252007-03-07 08:32:30 +0000973 if (ret < 0) {
974 /* Secondary table lookup */
aliguorid12d51d2009-01-15 21:48:06 +0000975 if (eaddr != 0xEFFFFFFF)
Blue Swirl90e189e2009-08-16 11:13:18 +0000976 LOG_MMU("1 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
977 "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
978 " pg_addr=" TARGET_FMT_plx "\n", sdr, vsid,
979 pgidx, hash, ctx->pg_addr[1]);
blueswir15b5aba42009-03-07 20:51:18 +0000980 ret2 = find_pte(env, ctx, 1, rw, type,
981 target_page_bits);
j_mayer76a66252007-03-07 08:32:30 +0000982 if (ret2 != -1)
983 ret = ret2;
984 }
bellard9a64fbe2004-01-04 22:58:38 +0000985 }
j_mayer0411a972007-10-25 21:35:50 +0000986#if defined (DUMP_PAGE_TABLES)
aliguori93fcfe32009-01-15 22:34:14 +0000987 if (qemu_log_enabled()) {
Anthony Liguoric227f092009-10-01 16:12:16 -0500988 target_phys_addr_t curaddr;
j_mayerb33c17e2007-10-07 17:30:34 +0000989 uint32_t a0, a1, a2, a3;
Blue Swirl90e189e2009-08-16 11:13:18 +0000990 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
991 "\n", sdr, mask + 0x80);
j_mayerb33c17e2007-10-07 17:30:34 +0000992 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
993 curaddr += 16) {
994 a0 = ldl_phys(curaddr);
995 a1 = ldl_phys(curaddr + 4);
996 a2 = ldl_phys(curaddr + 8);
997 a3 = ldl_phys(curaddr + 12);
998 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
Blue Swirl90e189e2009-08-16 11:13:18 +0000999 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
1000 curaddr, a0, a1, a2, a3);
j_mayer12de9a32007-10-05 22:06:02 +00001001 }
j_mayerb33c17e2007-10-07 17:30:34 +00001002 }
1003 }
j_mayer12de9a32007-10-05 22:06:02 +00001004#endif
bellard9a64fbe2004-01-04 22:58:38 +00001005 } else {
aliguorid12d51d2009-01-15 21:48:06 +00001006 LOG_MMU("No access allowed\n");
j_mayer76a66252007-03-07 08:32:30 +00001007 ret = -3;
bellard9a64fbe2004-01-04 22:58:38 +00001008 }
1009 } else {
aliguorid12d51d2009-01-15 21:48:06 +00001010 LOG_MMU("direct store...\n");
bellard9a64fbe2004-01-04 22:58:38 +00001011 /* Direct-store segment : absolutely *BUGGY* for now */
1012 switch (type) {
1013 case ACCESS_INT:
1014 /* Integer load/store : only access allowed */
1015 break;
1016 case ACCESS_CODE:
1017 /* No code fetch is allowed in direct-store areas */
1018 return -4;
1019 case ACCESS_FLOAT:
1020 /* Floating point load/store */
1021 return -4;
1022 case ACCESS_RES:
1023 /* lwarx, ldarx or srwcx. */
1024 return -4;
1025 case ACCESS_CACHE:
1026 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
1027 /* Should make the instruction do no-op.
1028 * As it already do no-op, it's quite easy :-)
1029 */
j_mayer76a66252007-03-07 08:32:30 +00001030 ctx->raddr = eaddr;
bellard9a64fbe2004-01-04 22:58:38 +00001031 return 0;
1032 case ACCESS_EXT:
1033 /* eciwx or ecowx */
1034 return -4;
1035 default:
aliguori93fcfe32009-01-15 22:34:14 +00001036 qemu_log("ERROR: instruction should not need "
bellard9a64fbe2004-01-04 22:58:38 +00001037 "address translation\n");
bellard9a64fbe2004-01-04 22:58:38 +00001038 return -4;
1039 }
j_mayer76a66252007-03-07 08:32:30 +00001040 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
1041 ctx->raddr = eaddr;
bellard9a64fbe2004-01-04 22:58:38 +00001042 ret = 2;
1043 } else {
1044 ret = -2;
1045 }
1046 }
1047
1048 return ret;
1049}
1050
j_mayerc294fc52007-04-24 06:44:14 +00001051/* Generic TLB check function for embedded PowerPC implementations */
Anthony Liguoric227f092009-10-01 16:12:16 -05001052static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
1053 target_phys_addr_t *raddrp,
Blue Swirl636aa202009-08-16 09:06:54 +00001054 target_ulong address, uint32_t pid, int ext,
1055 int i)
j_mayerc294fc52007-04-24 06:44:14 +00001056{
1057 target_ulong mask;
1058
1059 /* Check valid flag */
1060 if (!(tlb->prot & PAGE_VALID)) {
aliguori93fcfe32009-01-15 22:34:14 +00001061 qemu_log("%s: TLB %d not valid\n", __func__, i);
j_mayerc294fc52007-04-24 06:44:14 +00001062 return -1;
1063 }
1064 mask = ~(tlb->size - 1);
Blue Swirl90e189e2009-08-16 11:13:18 +00001065 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
1066 " " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN,
1067 mask, (uint32_t)tlb->PID);
j_mayerc294fc52007-04-24 06:44:14 +00001068 /* Check PID */
j_mayer36081602007-09-17 08:21:54 +00001069 if (tlb->PID != 0 && tlb->PID != pid)
j_mayerc294fc52007-04-24 06:44:14 +00001070 return -1;
1071 /* Check effective address */
1072 if ((address & mask) != tlb->EPN)
1073 return -1;
1074 *raddrp = (tlb->RPN & mask) | (address & ~mask);
j_mayer97062852007-09-21 06:32:17 +00001075#if (TARGET_PHYS_ADDR_BITS >= 36)
j_mayer36081602007-09-17 08:21:54 +00001076 if (ext) {
1077 /* Extend the physical address to 36 bits */
Anthony Liguoric227f092009-10-01 16:12:16 -05001078 *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
j_mayer36081602007-09-17 08:21:54 +00001079 }
j_mayer97062852007-09-21 06:32:17 +00001080#endif
j_mayerc294fc52007-04-24 06:44:14 +00001081
1082 return 0;
1083}
1084
1085/* Generic TLB search function for PowerPC embedded implementations */
j_mayer36081602007-09-17 08:21:54 +00001086int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
j_mayerc294fc52007-04-24 06:44:14 +00001087{
Anthony Liguoric227f092009-10-01 16:12:16 -05001088 ppcemb_tlb_t *tlb;
1089 target_phys_addr_t raddr;
j_mayerc294fc52007-04-24 06:44:14 +00001090 int i, ret;
1091
1092 /* Default return value is no match */
1093 ret = -1;
j_mayera750fc02007-09-26 23:54:22 +00001094 for (i = 0; i < env->nb_tlb; i++) {
j_mayerc294fc52007-04-24 06:44:14 +00001095 tlb = &env->tlb[i].tlbe;
j_mayer36081602007-09-17 08:21:54 +00001096 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
j_mayerc294fc52007-04-24 06:44:14 +00001097 ret = i;
1098 break;
1099 }
1100 }
1101
1102 return ret;
1103}
1104
j_mayerdaf4f962007-10-01 01:51:12 +00001105/* Helpers specific to PowerPC 40x implementations */
Blue Swirl636aa202009-08-16 09:06:54 +00001106static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
j_mayera750fc02007-09-26 23:54:22 +00001107{
Anthony Liguoric227f092009-10-01 16:12:16 -05001108 ppcemb_tlb_t *tlb;
j_mayerdaf4f962007-10-01 01:51:12 +00001109 int i;
1110
1111 for (i = 0; i < env->nb_tlb; i++) {
1112 tlb = &env->tlb[i].tlbe;
1113 tlb->prot &= ~PAGE_VALID;
1114 }
1115 tlb_flush(env, 1);
1116}
1117
Blue Swirl636aa202009-08-16 09:06:54 +00001118static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
1119 target_ulong eaddr, uint32_t pid)
j_mayerdaf4f962007-10-01 01:51:12 +00001120{
1121#if !defined(FLUSH_ALL_TLBS)
Anthony Liguoric227f092009-10-01 16:12:16 -05001122 ppcemb_tlb_t *tlb;
1123 target_phys_addr_t raddr;
j_mayera750fc02007-09-26 23:54:22 +00001124 target_ulong page, end;
1125 int i;
1126
1127 for (i = 0; i < env->nb_tlb; i++) {
1128 tlb = &env->tlb[i].tlbe;
1129 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
1130 end = tlb->EPN + tlb->size;
1131 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
1132 tlb_flush_page(env, page);
1133 tlb->prot &= ~PAGE_VALID;
1134 break;
1135 }
1136 }
j_mayerdaf4f962007-10-01 01:51:12 +00001137#else
1138 ppc4xx_tlb_invalidate_all(env);
j_mayer0a032cb2007-04-16 08:56:52 +00001139#endif
j_mayer0a032cb2007-04-16 08:56:52 +00001140}
1141
Anthony Liguoric227f092009-10-01 16:12:16 -05001142static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
j_mayere96efcf2007-04-14 12:17:09 +00001143 target_ulong address, int rw, int access_type)
j_mayera8dea122007-03-31 11:33:48 +00001144{
Anthony Liguoric227f092009-10-01 16:12:16 -05001145 ppcemb_tlb_t *tlb;
1146 target_phys_addr_t raddr;
j_mayer0411a972007-10-25 21:35:50 +00001147 int i, ret, zsel, zpr, pr;
ths3b46e622007-09-17 08:09:54 +00001148
j_mayerc55e9ae2007-04-16 09:21:46 +00001149 ret = -1;
Anthony Liguoric227f092009-10-01 16:12:16 -05001150 raddr = (target_phys_addr_t)-1ULL;
j_mayer0411a972007-10-25 21:35:50 +00001151 pr = msr_pr;
j_mayera8dea122007-03-31 11:33:48 +00001152 for (i = 0; i < env->nb_tlb; i++) {
1153 tlb = &env->tlb[i].tlbe;
j_mayer36081602007-09-17 08:21:54 +00001154 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1155 env->spr[SPR_40x_PID], 0, i) < 0)
j_mayera8dea122007-03-31 11:33:48 +00001156 continue;
j_mayera8dea122007-03-31 11:33:48 +00001157 zsel = (tlb->attr >> 4) & 0xF;
Edgar E. Iglesiasec5c3e42010-01-11 15:23:58 +01001158 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
aliguorid12d51d2009-01-15 21:48:06 +00001159 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
j_mayera8dea122007-03-31 11:33:48 +00001160 __func__, i, zsel, zpr, rw, tlb->attr);
j_mayerb227a8e2007-10-14 10:21:20 +00001161 /* Check execute enable bit */
1162 switch (zpr) {
1163 case 0x2:
j_mayer0411a972007-10-25 21:35:50 +00001164 if (pr != 0)
j_mayerb227a8e2007-10-14 10:21:20 +00001165 goto check_perms;
1166 /* No break here */
1167 case 0x3:
1168 /* All accesses granted */
1169 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1170 ret = 0;
1171 break;
1172 case 0x0:
j_mayer0411a972007-10-25 21:35:50 +00001173 if (pr != 0) {
Edgar E. Iglesiasdcbc9a72010-01-11 15:32:47 +01001174 /* Raise Zone protection fault. */
1175 env->spr[SPR_40x_ESR] = 1 << 22;
j_mayerb227a8e2007-10-14 10:21:20 +00001176 ctx->prot = 0;
1177 ret = -2;
j_mayera8dea122007-03-31 11:33:48 +00001178 break;
1179 }
j_mayerb227a8e2007-10-14 10:21:20 +00001180 /* No break here */
1181 case 0x1:
1182 check_perms:
1183 /* Check from TLB entry */
1184 /* XXX: there is a problem here or in the TLB fill code... */
1185 ctx->prot = tlb->prot;
1186 ctx->prot |= PAGE_EXEC;
1187 ret = check_prot(ctx->prot, rw, access_type);
Edgar E. Iglesiasdcbc9a72010-01-11 15:32:47 +01001188 if (ret == -2)
1189 env->spr[SPR_40x_ESR] = 0;
j_mayerb227a8e2007-10-14 10:21:20 +00001190 break;
j_mayera8dea122007-03-31 11:33:48 +00001191 }
1192 if (ret >= 0) {
1193 ctx->raddr = raddr;
Blue Swirl90e189e2009-08-16 11:13:18 +00001194 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1195 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1196 ret);
j_mayerc55e9ae2007-04-16 09:21:46 +00001197 return 0;
j_mayera8dea122007-03-31 11:33:48 +00001198 }
1199 }
Blue Swirl90e189e2009-08-16 11:13:18 +00001200 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1201 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
ths3b46e622007-09-17 08:09:54 +00001202
j_mayera8dea122007-03-31 11:33:48 +00001203 return ret;
1204}
1205
j_mayerc294fc52007-04-24 06:44:14 +00001206void store_40x_sler (CPUPPCState *env, uint32_t val)
1207{
1208 /* XXX: TO BE FIXED */
1209 if (val != 0x00000000) {
1210 cpu_abort(env, "Little-endian regions are not supported by now\n");
1211 }
1212 env->spr[SPR_405_SLER] = val;
1213}
1214
Anthony Liguoric227f092009-10-01 16:12:16 -05001215static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
aurel3293220572008-12-11 22:42:33 +00001216 target_ulong address, int rw,
1217 int access_type)
j_mayer5eb79952007-09-19 05:44:04 +00001218{
Anthony Liguoric227f092009-10-01 16:12:16 -05001219 ppcemb_tlb_t *tlb;
1220 target_phys_addr_t raddr;
j_mayer5eb79952007-09-19 05:44:04 +00001221 int i, prot, ret;
1222
1223 ret = -1;
Anthony Liguoric227f092009-10-01 16:12:16 -05001224 raddr = (target_phys_addr_t)-1ULL;
j_mayer5eb79952007-09-19 05:44:04 +00001225 for (i = 0; i < env->nb_tlb; i++) {
1226 tlb = &env->tlb[i].tlbe;
1227 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1228 env->spr[SPR_BOOKE_PID], 1, i) < 0)
1229 continue;
j_mayer0411a972007-10-25 21:35:50 +00001230 if (msr_pr != 0)
j_mayer5eb79952007-09-19 05:44:04 +00001231 prot = tlb->prot & 0xF;
1232 else
1233 prot = (tlb->prot >> 4) & 0xF;
1234 /* Check the address space */
1235 if (access_type == ACCESS_CODE) {
j_mayerd26bfc92007-10-07 14:41:00 +00001236 if (msr_ir != (tlb->attr & 1))
j_mayer5eb79952007-09-19 05:44:04 +00001237 continue;
1238 ctx->prot = prot;
1239 if (prot & PAGE_EXEC) {
1240 ret = 0;
1241 break;
1242 }
1243 ret = -3;
1244 } else {
j_mayerd26bfc92007-10-07 14:41:00 +00001245 if (msr_dr != (tlb->attr & 1))
j_mayer5eb79952007-09-19 05:44:04 +00001246 continue;
1247 ctx->prot = prot;
1248 if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
1249 ret = 0;
1250 break;
1251 }
1252 ret = -2;
1253 }
1254 }
1255 if (ret >= 0)
1256 ctx->raddr = raddr;
1257
1258 return ret;
1259}
1260
Anthony Liguoric227f092009-10-01 16:12:16 -05001261static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
Blue Swirl636aa202009-08-16 09:06:54 +00001262 target_ulong eaddr, int rw)
j_mayer76a66252007-03-07 08:32:30 +00001263{
1264 int in_plb, ret;
ths3b46e622007-09-17 08:09:54 +00001265
j_mayer76a66252007-03-07 08:32:30 +00001266 ctx->raddr = eaddr;
j_mayerb227a8e2007-10-14 10:21:20 +00001267 ctx->prot = PAGE_READ | PAGE_EXEC;
j_mayer76a66252007-03-07 08:32:30 +00001268 ret = 0;
j_mayera750fc02007-09-26 23:54:22 +00001269 switch (env->mmu_model) {
1270 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001271 case POWERPC_MMU_601:
j_mayera750fc02007-09-26 23:54:22 +00001272 case POWERPC_MMU_SOFT_6xx:
j_mayer7dbe11a2007-10-01 05:16:57 +00001273 case POWERPC_MMU_SOFT_74xx:
j_mayera750fc02007-09-26 23:54:22 +00001274 case POWERPC_MMU_SOFT_4xx:
j_mayerb4095fe2007-11-17 22:42:36 +00001275 case POWERPC_MMU_REAL:
j_mayer7dbe11a2007-10-01 05:16:57 +00001276 case POWERPC_MMU_BOOKE:
j_mayer76a66252007-03-07 08:32:30 +00001277 ctx->prot |= PAGE_WRITE;
j_mayercaa40392007-09-19 04:36:02 +00001278 break;
1279#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001280 case POWERPC_MMU_620:
j_mayera750fc02007-09-26 23:54:22 +00001281 case POWERPC_MMU_64B:
j_mayercaa40392007-09-19 04:36:02 +00001282 /* Real address are 60 bits long */
j_mayera750fc02007-09-26 23:54:22 +00001283 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
j_mayercaa40392007-09-19 04:36:02 +00001284 ctx->prot |= PAGE_WRITE;
1285 break;
j_mayer97062852007-09-21 06:32:17 +00001286#endif
j_mayera750fc02007-09-26 23:54:22 +00001287 case POWERPC_MMU_SOFT_4xx_Z:
j_mayercaa40392007-09-19 04:36:02 +00001288 if (unlikely(msr_pe != 0)) {
1289 /* 403 family add some particular protections,
1290 * using PBL/PBU registers for accesses with no translation.
1291 */
1292 in_plb =
1293 /* Check PLB validity */
1294 (env->pb[0] < env->pb[1] &&
1295 /* and address in plb area */
1296 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1297 (env->pb[2] < env->pb[3] &&
1298 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1299 if (in_plb ^ msr_px) {
1300 /* Access in protected area */
1301 if (rw == 1) {
1302 /* Access is not allowed */
1303 ret = -2;
1304 }
1305 } else {
1306 /* Read-write access is allowed */
1307 ctx->prot |= PAGE_WRITE;
1308 }
1309 }
j_mayere1833e12007-09-29 13:06:16 +00001310 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001311 case POWERPC_MMU_MPC8xx:
1312 /* XXX: TODO */
1313 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1314 break;
j_mayera750fc02007-09-26 23:54:22 +00001315 case POWERPC_MMU_BOOKE_FSL:
j_mayercaa40392007-09-19 04:36:02 +00001316 /* XXX: TODO */
1317 cpu_abort(env, "BookE FSL MMU model not implemented\n");
1318 break;
1319 default:
1320 cpu_abort(env, "Unknown or invalid MMU model\n");
1321 return -1;
j_mayer76a66252007-03-07 08:32:30 +00001322 }
1323
1324 return ret;
1325}
1326
Anthony Liguoric227f092009-10-01 16:12:16 -05001327int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
j_mayerfaadf502007-11-03 13:37:12 +00001328 int rw, int access_type)
bellard9a64fbe2004-01-04 22:58:38 +00001329{
1330 int ret;
j_mayer0411a972007-10-25 21:35:50 +00001331
bellard514fb8c2004-06-21 16:57:45 +00001332#if 0
aliguori93fcfe32009-01-15 22:34:14 +00001333 qemu_log("%s\n", __func__);
j_mayerd9bce9d2007-03-17 14:02:15 +00001334#endif
bellard4b3686f2004-05-23 22:18:12 +00001335 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1336 (access_type != ACCESS_CODE && msr_dr == 0)) {
bellard9a64fbe2004-01-04 22:58:38 +00001337 /* No address translation */
j_mayer76a66252007-03-07 08:32:30 +00001338 ret = check_physical(env, ctx, eaddr, rw);
bellard9a64fbe2004-01-04 22:58:38 +00001339 } else {
j_mayerc55e9ae2007-04-16 09:21:46 +00001340 ret = -1;
j_mayera750fc02007-09-26 23:54:22 +00001341 switch (env->mmu_model) {
1342 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001343 case POWERPC_MMU_601:
j_mayera750fc02007-09-26 23:54:22 +00001344 case POWERPC_MMU_SOFT_6xx:
j_mayer7dbe11a2007-10-01 05:16:57 +00001345 case POWERPC_MMU_SOFT_74xx:
blueswir194855932009-03-07 20:58:30 +00001346 /* Try to find a BAT */
1347 if (env->nb_BATs != 0)
1348 ret = get_bat(env, ctx, eaddr, rw, access_type);
j_mayerc55e9ae2007-04-16 09:21:46 +00001349#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001350 case POWERPC_MMU_620:
j_mayera750fc02007-09-26 23:54:22 +00001351 case POWERPC_MMU_64B:
j_mayerc55e9ae2007-04-16 09:21:46 +00001352#endif
j_mayera8dea122007-03-31 11:33:48 +00001353 if (ret < 0) {
j_mayerc55e9ae2007-04-16 09:21:46 +00001354 /* We didn't match any BAT entry or don't have BATs */
j_mayera8dea122007-03-31 11:33:48 +00001355 ret = get_segment(env, ctx, eaddr, rw, access_type);
1356 }
1357 break;
j_mayera750fc02007-09-26 23:54:22 +00001358 case POWERPC_MMU_SOFT_4xx:
1359 case POWERPC_MMU_SOFT_4xx_Z:
j_mayer36081602007-09-17 08:21:54 +00001360 ret = mmu40x_get_physical_address(env, ctx, eaddr,
j_mayera8dea122007-03-31 11:33:48 +00001361 rw, access_type);
1362 break;
j_mayera750fc02007-09-26 23:54:22 +00001363 case POWERPC_MMU_BOOKE:
j_mayer5eb79952007-09-19 05:44:04 +00001364 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1365 rw, access_type);
1366 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001367 case POWERPC_MMU_MPC8xx:
1368 /* XXX: TODO */
1369 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1370 break;
j_mayera750fc02007-09-26 23:54:22 +00001371 case POWERPC_MMU_BOOKE_FSL:
j_mayerc55e9ae2007-04-16 09:21:46 +00001372 /* XXX: TODO */
1373 cpu_abort(env, "BookE FSL MMU model not implemented\n");
1374 return -1;
j_mayerb4095fe2007-11-17 22:42:36 +00001375 case POWERPC_MMU_REAL:
1376 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
j_mayer2662a052007-09-21 05:50:37 +00001377 return -1;
j_mayerc55e9ae2007-04-16 09:21:46 +00001378 default:
1379 cpu_abort(env, "Unknown or invalid MMU model\n");
j_mayera8dea122007-03-31 11:33:48 +00001380 return -1;
bellard9a64fbe2004-01-04 22:58:38 +00001381 }
1382 }
bellard514fb8c2004-06-21 16:57:45 +00001383#if 0
Blue Swirl90e189e2009-08-16 11:13:18 +00001384 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1385 __func__, eaddr, ret, ctx->raddr);
j_mayer76a66252007-03-07 08:32:30 +00001386#endif
j_mayerd9bce9d2007-03-17 14:02:15 +00001387
bellard9a64fbe2004-01-04 22:58:38 +00001388 return ret;
1389}
1390
Anthony Liguoric227f092009-10-01 16:12:16 -05001391target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
bellarda6b025d2004-01-24 15:18:16 +00001392{
Anthony Liguoric227f092009-10-01 16:12:16 -05001393 mmu_ctx_t ctx;
bellarda6b025d2004-01-24 15:18:16 +00001394
j_mayerfaadf502007-11-03 13:37:12 +00001395 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
bellarda6b025d2004-01-24 15:18:16 +00001396 return -1;
j_mayer76a66252007-03-07 08:32:30 +00001397
1398 return ctx.raddr & TARGET_PAGE_MASK;
bellarda6b025d2004-01-24 15:18:16 +00001399}
bellard9a64fbe2004-01-04 22:58:38 +00001400
bellard9a64fbe2004-01-04 22:58:38 +00001401/* Perform address translation */
j_mayere96efcf2007-04-14 12:17:09 +00001402int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
j_mayer6ebbf392007-10-14 07:07:08 +00001403 int mmu_idx, int is_softmmu)
bellard9a64fbe2004-01-04 22:58:38 +00001404{
Anthony Liguoric227f092009-10-01 16:12:16 -05001405 mmu_ctx_t ctx;
bellarda541f292004-04-12 20:39:29 +00001406 int access_type;
bellard9a64fbe2004-01-04 22:58:38 +00001407 int ret = 0;
j_mayerd9bce9d2007-03-17 14:02:15 +00001408
bellardb769d8f2004-10-03 15:07:13 +00001409 if (rw == 2) {
1410 /* code access */
1411 rw = 0;
1412 access_type = ACCESS_CODE;
1413 } else {
1414 /* data access */
aurel32b4cec7b2008-12-08 18:11:33 +00001415 access_type = env->access_type;
bellardb769d8f2004-10-03 15:07:13 +00001416 }
j_mayerfaadf502007-11-03 13:37:12 +00001417 ret = get_physical_address(env, &ctx, address, rw, access_type);
bellard9a64fbe2004-01-04 22:58:38 +00001418 if (ret == 0) {
j_mayerb227a8e2007-10-14 10:21:20 +00001419 ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK,
1420 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1421 mmu_idx, is_softmmu);
bellard9a64fbe2004-01-04 22:58:38 +00001422 } else if (ret < 0) {
aliguorid12d51d2009-01-15 21:48:06 +00001423 LOG_MMU_STATE(env);
bellard9a64fbe2004-01-04 22:58:38 +00001424 if (access_type == ACCESS_CODE) {
bellard9a64fbe2004-01-04 22:58:38 +00001425 switch (ret) {
1426 case -1:
j_mayer76a66252007-03-07 08:32:30 +00001427 /* No matches in page tables or TLB */
j_mayera750fc02007-09-26 23:54:22 +00001428 switch (env->mmu_model) {
1429 case POWERPC_MMU_SOFT_6xx:
j_mayer8f793432007-10-03 20:19:40 +00001430 env->exception_index = POWERPC_EXCP_IFTLB;
1431 env->error_code = 1 << 18;
j_mayer76a66252007-03-07 08:32:30 +00001432 env->spr[SPR_IMISS] = address;
1433 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
j_mayer76a66252007-03-07 08:32:30 +00001434 goto tlb_miss;
j_mayer7dbe11a2007-10-01 05:16:57 +00001435 case POWERPC_MMU_SOFT_74xx:
j_mayer8f793432007-10-03 20:19:40 +00001436 env->exception_index = POWERPC_EXCP_IFTLB;
j_mayer7dbe11a2007-10-01 05:16:57 +00001437 goto tlb_miss_74xx;
j_mayera750fc02007-09-26 23:54:22 +00001438 case POWERPC_MMU_SOFT_4xx:
1439 case POWERPC_MMU_SOFT_4xx_Z:
j_mayer8f793432007-10-03 20:19:40 +00001440 env->exception_index = POWERPC_EXCP_ITLB;
1441 env->error_code = 0;
j_mayera8dea122007-03-31 11:33:48 +00001442 env->spr[SPR_40x_DEAR] = address;
1443 env->spr[SPR_40x_ESR] = 0x00000000;
j_mayerc55e9ae2007-04-16 09:21:46 +00001444 break;
j_mayera750fc02007-09-26 23:54:22 +00001445 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001446 case POWERPC_MMU_601:
j_mayerc55e9ae2007-04-16 09:21:46 +00001447#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001448 case POWERPC_MMU_620:
j_mayera750fc02007-09-26 23:54:22 +00001449 case POWERPC_MMU_64B:
j_mayerc55e9ae2007-04-16 09:21:46 +00001450#endif
j_mayer8f793432007-10-03 20:19:40 +00001451 env->exception_index = POWERPC_EXCP_ISI;
1452 env->error_code = 0x40000000;
1453 break;
j_mayera750fc02007-09-26 23:54:22 +00001454 case POWERPC_MMU_BOOKE:
j_mayerc55e9ae2007-04-16 09:21:46 +00001455 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001456 cpu_abort(env, "BookE MMU model is not implemented\n");
j_mayerc55e9ae2007-04-16 09:21:46 +00001457 return -1;
j_mayera750fc02007-09-26 23:54:22 +00001458 case POWERPC_MMU_BOOKE_FSL:
j_mayerc55e9ae2007-04-16 09:21:46 +00001459 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001460 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
j_mayerc55e9ae2007-04-16 09:21:46 +00001461 return -1;
j_mayerb4095fe2007-11-17 22:42:36 +00001462 case POWERPC_MMU_MPC8xx:
1463 /* XXX: TODO */
1464 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1465 break;
1466 case POWERPC_MMU_REAL:
1467 cpu_abort(env, "PowerPC in real mode should never raise "
1468 "any MMU exceptions\n");
j_mayer2662a052007-09-21 05:50:37 +00001469 return -1;
j_mayerc55e9ae2007-04-16 09:21:46 +00001470 default:
1471 cpu_abort(env, "Unknown or invalid MMU model\n");
1472 return -1;
j_mayer76a66252007-03-07 08:32:30 +00001473 }
bellard9a64fbe2004-01-04 22:58:38 +00001474 break;
1475 case -2:
1476 /* Access rights violation */
j_mayer8f793432007-10-03 20:19:40 +00001477 env->exception_index = POWERPC_EXCP_ISI;
1478 env->error_code = 0x08000000;
bellard9a64fbe2004-01-04 22:58:38 +00001479 break;
1480 case -3:
j_mayer76a66252007-03-07 08:32:30 +00001481 /* No execute protection violation */
j_mayer8f793432007-10-03 20:19:40 +00001482 env->exception_index = POWERPC_EXCP_ISI;
1483 env->error_code = 0x10000000;
bellard9a64fbe2004-01-04 22:58:38 +00001484 break;
1485 case -4:
1486 /* Direct store exception */
1487 /* No code fetch is allowed in direct-store areas */
j_mayer8f793432007-10-03 20:19:40 +00001488 env->exception_index = POWERPC_EXCP_ISI;
1489 env->error_code = 0x10000000;
bellard2be00712005-07-02 22:09:27 +00001490 break;
j_mayere1833e12007-09-29 13:06:16 +00001491#if defined(TARGET_PPC64)
bellard2be00712005-07-02 22:09:27 +00001492 case -5:
1493 /* No match in segment table */
j_mayeradd78952007-11-19 11:41:10 +00001494 if (env->mmu_model == POWERPC_MMU_620) {
1495 env->exception_index = POWERPC_EXCP_ISI;
1496 /* XXX: this might be incorrect */
1497 env->error_code = 0x40000000;
1498 } else {
1499 env->exception_index = POWERPC_EXCP_ISEG;
1500 env->error_code = 0;
1501 }
bellard9a64fbe2004-01-04 22:58:38 +00001502 break;
j_mayere1833e12007-09-29 13:06:16 +00001503#endif
bellard9a64fbe2004-01-04 22:58:38 +00001504 }
1505 } else {
bellard9a64fbe2004-01-04 22:58:38 +00001506 switch (ret) {
1507 case -1:
j_mayer76a66252007-03-07 08:32:30 +00001508 /* No matches in page tables or TLB */
j_mayera750fc02007-09-26 23:54:22 +00001509 switch (env->mmu_model) {
1510 case POWERPC_MMU_SOFT_6xx:
j_mayer76a66252007-03-07 08:32:30 +00001511 if (rw == 1) {
j_mayer8f793432007-10-03 20:19:40 +00001512 env->exception_index = POWERPC_EXCP_DSTLB;
1513 env->error_code = 1 << 16;
j_mayer76a66252007-03-07 08:32:30 +00001514 } else {
j_mayer8f793432007-10-03 20:19:40 +00001515 env->exception_index = POWERPC_EXCP_DLTLB;
1516 env->error_code = 0;
j_mayer76a66252007-03-07 08:32:30 +00001517 }
1518 env->spr[SPR_DMISS] = address;
1519 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1520 tlb_miss:
j_mayer8f793432007-10-03 20:19:40 +00001521 env->error_code |= ctx.key << 19;
j_mayer76a66252007-03-07 08:32:30 +00001522 env->spr[SPR_HASH1] = ctx.pg_addr[0];
1523 env->spr[SPR_HASH2] = ctx.pg_addr[1];
j_mayer8f793432007-10-03 20:19:40 +00001524 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00001525 case POWERPC_MMU_SOFT_74xx:
1526 if (rw == 1) {
j_mayer8f793432007-10-03 20:19:40 +00001527 env->exception_index = POWERPC_EXCP_DSTLB;
j_mayer7dbe11a2007-10-01 05:16:57 +00001528 } else {
j_mayer8f793432007-10-03 20:19:40 +00001529 env->exception_index = POWERPC_EXCP_DLTLB;
j_mayer7dbe11a2007-10-01 05:16:57 +00001530 }
1531 tlb_miss_74xx:
1532 /* Implement LRU algorithm */
j_mayer8f793432007-10-03 20:19:40 +00001533 env->error_code = ctx.key << 19;
j_mayer7dbe11a2007-10-01 05:16:57 +00001534 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1535 ((env->last_way + 1) & (env->nb_ways - 1));
1536 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
j_mayer7dbe11a2007-10-01 05:16:57 +00001537 break;
j_mayera750fc02007-09-26 23:54:22 +00001538 case POWERPC_MMU_SOFT_4xx:
1539 case POWERPC_MMU_SOFT_4xx_Z:
j_mayer8f793432007-10-03 20:19:40 +00001540 env->exception_index = POWERPC_EXCP_DTLB;
1541 env->error_code = 0;
j_mayera8dea122007-03-31 11:33:48 +00001542 env->spr[SPR_40x_DEAR] = address;
1543 if (rw)
1544 env->spr[SPR_40x_ESR] = 0x00800000;
1545 else
1546 env->spr[SPR_40x_ESR] = 0x00000000;
j_mayerc55e9ae2007-04-16 09:21:46 +00001547 break;
j_mayera750fc02007-09-26 23:54:22 +00001548 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001549 case POWERPC_MMU_601:
j_mayerc55e9ae2007-04-16 09:21:46 +00001550#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001551 case POWERPC_MMU_620:
j_mayera750fc02007-09-26 23:54:22 +00001552 case POWERPC_MMU_64B:
j_mayerc55e9ae2007-04-16 09:21:46 +00001553#endif
j_mayer8f793432007-10-03 20:19:40 +00001554 env->exception_index = POWERPC_EXCP_DSI;
1555 env->error_code = 0;
1556 env->spr[SPR_DAR] = address;
1557 if (rw == 1)
1558 env->spr[SPR_DSISR] = 0x42000000;
1559 else
1560 env->spr[SPR_DSISR] = 0x40000000;
1561 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001562 case POWERPC_MMU_MPC8xx:
1563 /* XXX: TODO */
1564 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1565 break;
j_mayera750fc02007-09-26 23:54:22 +00001566 case POWERPC_MMU_BOOKE:
j_mayerc55e9ae2007-04-16 09:21:46 +00001567 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001568 cpu_abort(env, "BookE MMU model is not implemented\n");
j_mayerc55e9ae2007-04-16 09:21:46 +00001569 return -1;
j_mayera750fc02007-09-26 23:54:22 +00001570 case POWERPC_MMU_BOOKE_FSL:
j_mayerc55e9ae2007-04-16 09:21:46 +00001571 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001572 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
j_mayerc55e9ae2007-04-16 09:21:46 +00001573 return -1;
j_mayerb4095fe2007-11-17 22:42:36 +00001574 case POWERPC_MMU_REAL:
1575 cpu_abort(env, "PowerPC in real mode should never raise "
1576 "any MMU exceptions\n");
j_mayer2662a052007-09-21 05:50:37 +00001577 return -1;
j_mayerc55e9ae2007-04-16 09:21:46 +00001578 default:
1579 cpu_abort(env, "Unknown or invalid MMU model\n");
1580 return -1;
j_mayer76a66252007-03-07 08:32:30 +00001581 }
bellard9a64fbe2004-01-04 22:58:38 +00001582 break;
1583 case -2:
1584 /* Access rights violation */
j_mayer8f793432007-10-03 20:19:40 +00001585 env->exception_index = POWERPC_EXCP_DSI;
1586 env->error_code = 0;
Edgar E. Iglesiasdcbc9a72010-01-11 15:32:47 +01001587 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1588 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1589 env->spr[SPR_40x_DEAR] = address;
1590 if (rw) {
1591 env->spr[SPR_40x_ESR] |= 0x00800000;
1592 }
1593 } else {
1594 env->spr[SPR_DAR] = address;
1595 if (rw == 1) {
1596 env->spr[SPR_DSISR] = 0x0A000000;
1597 } else {
1598 env->spr[SPR_DSISR] = 0x08000000;
1599 }
1600 }
bellard9a64fbe2004-01-04 22:58:38 +00001601 break;
1602 case -4:
1603 /* Direct store exception */
1604 switch (access_type) {
1605 case ACCESS_FLOAT:
1606 /* Floating point load/store */
j_mayer8f793432007-10-03 20:19:40 +00001607 env->exception_index = POWERPC_EXCP_ALIGN;
1608 env->error_code = POWERPC_EXCP_ALIGN_FP;
1609 env->spr[SPR_DAR] = address;
bellard9a64fbe2004-01-04 22:58:38 +00001610 break;
1611 case ACCESS_RES:
j_mayer8f793432007-10-03 20:19:40 +00001612 /* lwarx, ldarx or stwcx. */
1613 env->exception_index = POWERPC_EXCP_DSI;
1614 env->error_code = 0;
1615 env->spr[SPR_DAR] = address;
1616 if (rw == 1)
1617 env->spr[SPR_DSISR] = 0x06000000;
1618 else
1619 env->spr[SPR_DSISR] = 0x04000000;
bellard9a64fbe2004-01-04 22:58:38 +00001620 break;
1621 case ACCESS_EXT:
1622 /* eciwx or ecowx */
j_mayer8f793432007-10-03 20:19:40 +00001623 env->exception_index = POWERPC_EXCP_DSI;
1624 env->error_code = 0;
1625 env->spr[SPR_DAR] = address;
1626 if (rw == 1)
1627 env->spr[SPR_DSISR] = 0x06100000;
1628 else
1629 env->spr[SPR_DSISR] = 0x04100000;
bellard9a64fbe2004-01-04 22:58:38 +00001630 break;
1631 default:
j_mayer76a66252007-03-07 08:32:30 +00001632 printf("DSI: invalid exception (%d)\n", ret);
j_mayer8f793432007-10-03 20:19:40 +00001633 env->exception_index = POWERPC_EXCP_PROGRAM;
1634 env->error_code =
1635 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1636 env->spr[SPR_DAR] = address;
bellard9a64fbe2004-01-04 22:58:38 +00001637 break;
1638 }
bellardfdabc362005-07-04 22:17:05 +00001639 break;
j_mayere1833e12007-09-29 13:06:16 +00001640#if defined(TARGET_PPC64)
bellard2be00712005-07-02 22:09:27 +00001641 case -5:
1642 /* No match in segment table */
j_mayeradd78952007-11-19 11:41:10 +00001643 if (env->mmu_model == POWERPC_MMU_620) {
1644 env->exception_index = POWERPC_EXCP_DSI;
1645 env->error_code = 0;
1646 env->spr[SPR_DAR] = address;
1647 /* XXX: this might be incorrect */
1648 if (rw == 1)
1649 env->spr[SPR_DSISR] = 0x42000000;
1650 else
1651 env->spr[SPR_DSISR] = 0x40000000;
1652 } else {
1653 env->exception_index = POWERPC_EXCP_DSEG;
1654 env->error_code = 0;
1655 env->spr[SPR_DAR] = address;
1656 }
bellard2be00712005-07-02 22:09:27 +00001657 break;
j_mayere1833e12007-09-29 13:06:16 +00001658#endif
bellard9a64fbe2004-01-04 22:58:38 +00001659 }
bellard9a64fbe2004-01-04 22:58:38 +00001660 }
1661#if 0
j_mayer8f793432007-10-03 20:19:40 +00001662 printf("%s: set exception to %d %02x\n", __func__,
1663 env->exception, env->error_code);
bellard9a64fbe2004-01-04 22:58:38 +00001664#endif
bellard9a64fbe2004-01-04 22:58:38 +00001665 ret = 1;
1666 }
j_mayer76a66252007-03-07 08:32:30 +00001667
bellard9a64fbe2004-01-04 22:58:38 +00001668 return ret;
1669}
1670
bellard3fc6c082005-07-02 20:59:34 +00001671/*****************************************************************************/
1672/* BATs management */
1673#if !defined(FLUSH_ALL_TLBS)
Blue Swirl636aa202009-08-16 09:06:54 +00001674static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1675 target_ulong mask)
bellard3fc6c082005-07-02 20:59:34 +00001676{
1677 target_ulong base, end, page;
j_mayer76a66252007-03-07 08:32:30 +00001678
bellard3fc6c082005-07-02 20:59:34 +00001679 base = BATu & ~0x0001FFFF;
1680 end = base + mask + 0x00020000;
Blue Swirl90e189e2009-08-16 11:13:18 +00001681 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1682 TARGET_FMT_lx ")\n", base, end, mask);
bellard3fc6c082005-07-02 20:59:34 +00001683 for (page = base; page != end; page += TARGET_PAGE_SIZE)
1684 tlb_flush_page(env, page);
aliguorid12d51d2009-01-15 21:48:06 +00001685 LOG_BATS("Flush done\n");
bellard3fc6c082005-07-02 20:59:34 +00001686}
1687#endif
1688
Blue Swirl636aa202009-08-16 09:06:54 +00001689static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1690 target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001691{
Blue Swirl90e189e2009-08-16 11:13:18 +00001692 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1693 nr, ul == 0 ? 'u' : 'l', value, env->nip);
bellard3fc6c082005-07-02 20:59:34 +00001694}
1695
aurel3245d827d2008-12-07 13:40:29 +00001696void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001697{
1698 target_ulong mask;
1699
1700 dump_store_bat(env, 'I', 0, nr, value);
1701 if (env->IBAT[0][nr] != value) {
1702 mask = (value << 15) & 0x0FFE0000UL;
1703#if !defined(FLUSH_ALL_TLBS)
1704 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1705#endif
1706 /* When storing valid upper BAT, mask BEPI and BRPN
1707 * and invalidate all TLBs covered by this BAT
1708 */
1709 mask = (value << 15) & 0x0FFE0000UL;
1710 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1711 (value & ~0x0001FFFFUL & ~mask);
1712 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1713 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1714#if !defined(FLUSH_ALL_TLBS)
1715 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
j_mayer76a66252007-03-07 08:32:30 +00001716#else
bellard3fc6c082005-07-02 20:59:34 +00001717 tlb_flush(env, 1);
1718#endif
1719 }
1720}
1721
aurel3245d827d2008-12-07 13:40:29 +00001722void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001723{
1724 dump_store_bat(env, 'I', 1, nr, value);
1725 env->IBAT[1][nr] = value;
1726}
1727
aurel3245d827d2008-12-07 13:40:29 +00001728void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001729{
1730 target_ulong mask;
1731
1732 dump_store_bat(env, 'D', 0, nr, value);
1733 if (env->DBAT[0][nr] != value) {
1734 /* When storing valid upper BAT, mask BEPI and BRPN
1735 * and invalidate all TLBs covered by this BAT
1736 */
1737 mask = (value << 15) & 0x0FFE0000UL;
1738#if !defined(FLUSH_ALL_TLBS)
1739 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1740#endif
1741 mask = (value << 15) & 0x0FFE0000UL;
1742 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1743 (value & ~0x0001FFFFUL & ~mask);
1744 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1745 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1746#if !defined(FLUSH_ALL_TLBS)
1747 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1748#else
1749 tlb_flush(env, 1);
1750#endif
1751 }
1752}
1753
aurel3245d827d2008-12-07 13:40:29 +00001754void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001755{
1756 dump_store_bat(env, 'D', 1, nr, value);
1757 env->DBAT[1][nr] = value;
1758}
1759
aurel3245d827d2008-12-07 13:40:29 +00001760void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
j_mayer056401e2007-11-04 02:55:33 +00001761{
1762 target_ulong mask;
1763 int do_inval;
1764
1765 dump_store_bat(env, 'I', 0, nr, value);
1766 if (env->IBAT[0][nr] != value) {
1767 do_inval = 0;
1768 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1769 if (env->IBAT[1][nr] & 0x40) {
1770 /* Invalidate BAT only if it is valid */
1771#if !defined(FLUSH_ALL_TLBS)
1772 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1773#else
1774 do_inval = 1;
1775#endif
1776 }
1777 /* When storing valid upper BAT, mask BEPI and BRPN
1778 * and invalidate all TLBs covered by this BAT
1779 */
1780 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1781 (value & ~0x0001FFFFUL & ~mask);
1782 env->DBAT[0][nr] = env->IBAT[0][nr];
1783 if (env->IBAT[1][nr] & 0x40) {
1784#if !defined(FLUSH_ALL_TLBS)
1785 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1786#else
1787 do_inval = 1;
1788#endif
1789 }
1790#if defined(FLUSH_ALL_TLBS)
1791 if (do_inval)
1792 tlb_flush(env, 1);
1793#endif
1794 }
1795}
1796
aurel3245d827d2008-12-07 13:40:29 +00001797void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
j_mayer056401e2007-11-04 02:55:33 +00001798{
1799 target_ulong mask;
1800 int do_inval;
1801
1802 dump_store_bat(env, 'I', 1, nr, value);
1803 if (env->IBAT[1][nr] != value) {
1804 do_inval = 0;
1805 if (env->IBAT[1][nr] & 0x40) {
1806#if !defined(FLUSH_ALL_TLBS)
1807 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1808 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1809#else
1810 do_inval = 1;
1811#endif
1812 }
1813 if (value & 0x40) {
1814#if !defined(FLUSH_ALL_TLBS)
1815 mask = (value << 17) & 0x0FFE0000UL;
1816 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1817#else
1818 do_inval = 1;
1819#endif
1820 }
1821 env->IBAT[1][nr] = value;
1822 env->DBAT[1][nr] = value;
1823#if defined(FLUSH_ALL_TLBS)
1824 if (do_inval)
1825 tlb_flush(env, 1);
1826#endif
1827 }
1828}
1829
j_mayer0a032cb2007-04-16 08:56:52 +00001830/*****************************************************************************/
1831/* TLB management */
1832void ppc_tlb_invalidate_all (CPUPPCState *env)
1833{
j_mayerdaf4f962007-10-01 01:51:12 +00001834 switch (env->mmu_model) {
1835 case POWERPC_MMU_SOFT_6xx:
j_mayer7dbe11a2007-10-01 05:16:57 +00001836 case POWERPC_MMU_SOFT_74xx:
j_mayer0a032cb2007-04-16 08:56:52 +00001837 ppc6xx_tlb_invalidate_all(env);
j_mayerdaf4f962007-10-01 01:51:12 +00001838 break;
1839 case POWERPC_MMU_SOFT_4xx:
1840 case POWERPC_MMU_SOFT_4xx_Z:
j_mayer0a032cb2007-04-16 08:56:52 +00001841 ppc4xx_tlb_invalidate_all(env);
j_mayerdaf4f962007-10-01 01:51:12 +00001842 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001843 case POWERPC_MMU_REAL:
j_mayer7dbe11a2007-10-01 05:16:57 +00001844 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1845 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001846 case POWERPC_MMU_MPC8xx:
1847 /* XXX: TODO */
1848 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1849 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00001850 case POWERPC_MMU_BOOKE:
1851 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001852 cpu_abort(env, "BookE MMU model is not implemented\n");
j_mayer7dbe11a2007-10-01 05:16:57 +00001853 break;
1854 case POWERPC_MMU_BOOKE_FSL:
1855 /* XXX: TODO */
aliguorida07cf52009-01-15 21:24:24 +00001856 if (!kvm_enabled())
1857 cpu_abort(env, "BookE MMU model is not implemented\n");
j_mayer7dbe11a2007-10-01 05:16:57 +00001858 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00001859 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001860 case POWERPC_MMU_601:
j_mayer00af6852007-10-03 01:05:39 +00001861#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001862 case POWERPC_MMU_620:
j_mayer7dbe11a2007-10-01 05:16:57 +00001863 case POWERPC_MMU_64B:
j_mayer00af6852007-10-03 01:05:39 +00001864#endif /* defined(TARGET_PPC64) */
j_mayer0a032cb2007-04-16 08:56:52 +00001865 tlb_flush(env, 1);
j_mayerdaf4f962007-10-01 01:51:12 +00001866 break;
j_mayer00af6852007-10-03 01:05:39 +00001867 default:
1868 /* XXX: TODO */
j_mayer12de9a32007-10-05 22:06:02 +00001869 cpu_abort(env, "Unknown MMU model\n");
j_mayer00af6852007-10-03 01:05:39 +00001870 break;
j_mayer0a032cb2007-04-16 08:56:52 +00001871 }
1872}
1873
j_mayerdaf4f962007-10-01 01:51:12 +00001874void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
1875{
1876#if !defined(FLUSH_ALL_TLBS)
1877 addr &= TARGET_PAGE_MASK;
1878 switch (env->mmu_model) {
1879 case POWERPC_MMU_SOFT_6xx:
j_mayer7dbe11a2007-10-01 05:16:57 +00001880 case POWERPC_MMU_SOFT_74xx:
j_mayerdaf4f962007-10-01 01:51:12 +00001881 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1882 if (env->id_tlbs == 1)
1883 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1884 break;
1885 case POWERPC_MMU_SOFT_4xx:
1886 case POWERPC_MMU_SOFT_4xx_Z:
1887 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1888 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001889 case POWERPC_MMU_REAL:
j_mayer7dbe11a2007-10-01 05:16:57 +00001890 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1891 break;
j_mayerb4095fe2007-11-17 22:42:36 +00001892 case POWERPC_MMU_MPC8xx:
1893 /* XXX: TODO */
1894 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1895 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00001896 case POWERPC_MMU_BOOKE:
1897 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001898 cpu_abort(env, "BookE MMU model is not implemented\n");
j_mayer7dbe11a2007-10-01 05:16:57 +00001899 break;
1900 case POWERPC_MMU_BOOKE_FSL:
1901 /* XXX: TODO */
j_mayerb4095fe2007-11-17 22:42:36 +00001902 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
j_mayer7dbe11a2007-10-01 05:16:57 +00001903 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00001904 case POWERPC_MMU_32B:
j_mayerfaadf502007-11-03 13:37:12 +00001905 case POWERPC_MMU_601:
j_mayerdaf4f962007-10-01 01:51:12 +00001906 /* tlbie invalidate TLBs for all segments */
j_mayer6f2d8972007-11-12 00:04:48 +00001907 addr &= ~((target_ulong)-1ULL << 28);
j_mayerdaf4f962007-10-01 01:51:12 +00001908 /* XXX: this case should be optimized,
1909 * giving a mask to tlb_flush_page
1910 */
1911 tlb_flush_page(env, addr | (0x0 << 28));
1912 tlb_flush_page(env, addr | (0x1 << 28));
1913 tlb_flush_page(env, addr | (0x2 << 28));
1914 tlb_flush_page(env, addr | (0x3 << 28));
1915 tlb_flush_page(env, addr | (0x4 << 28));
1916 tlb_flush_page(env, addr | (0x5 << 28));
1917 tlb_flush_page(env, addr | (0x6 << 28));
1918 tlb_flush_page(env, addr | (0x7 << 28));
1919 tlb_flush_page(env, addr | (0x8 << 28));
1920 tlb_flush_page(env, addr | (0x9 << 28));
1921 tlb_flush_page(env, addr | (0xA << 28));
1922 tlb_flush_page(env, addr | (0xB << 28));
1923 tlb_flush_page(env, addr | (0xC << 28));
1924 tlb_flush_page(env, addr | (0xD << 28));
1925 tlb_flush_page(env, addr | (0xE << 28));
1926 tlb_flush_page(env, addr | (0xF << 28));
j_mayer7dbe11a2007-10-01 05:16:57 +00001927 break;
j_mayer00af6852007-10-03 01:05:39 +00001928#if defined(TARGET_PPC64)
j_mayeradd78952007-11-19 11:41:10 +00001929 case POWERPC_MMU_620:
j_mayer7dbe11a2007-10-01 05:16:57 +00001930 case POWERPC_MMU_64B:
j_mayer7dbe11a2007-10-01 05:16:57 +00001931 /* tlbie invalidate TLBs for all segments */
1932 /* XXX: given the fact that there are too many segments to invalidate,
j_mayer00af6852007-10-03 01:05:39 +00001933 * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
j_mayer7dbe11a2007-10-01 05:16:57 +00001934 * we just invalidate all TLBs
1935 */
1936 tlb_flush(env, 1);
1937 break;
j_mayer00af6852007-10-03 01:05:39 +00001938#endif /* defined(TARGET_PPC64) */
1939 default:
1940 /* XXX: TODO */
j_mayer12de9a32007-10-05 22:06:02 +00001941 cpu_abort(env, "Unknown MMU model\n");
j_mayer00af6852007-10-03 01:05:39 +00001942 break;
j_mayerdaf4f962007-10-01 01:51:12 +00001943 }
1944#else
1945 ppc_tlb_invalidate_all(env);
1946#endif
1947}
1948
bellard3fc6c082005-07-02 20:59:34 +00001949/*****************************************************************************/
1950/* Special registers manipulation */
j_mayerd9bce9d2007-03-17 14:02:15 +00001951#if defined(TARGET_PPC64)
j_mayerd9bce9d2007-03-17 14:02:15 +00001952void ppc_store_asr (CPUPPCState *env, target_ulong value)
1953{
1954 if (env->asr != value) {
1955 env->asr = value;
1956 tlb_flush(env, 1);
1957 }
1958}
1959#endif
1960
aurel3245d827d2008-12-07 13:40:29 +00001961void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001962{
Blue Swirl90e189e2009-08-16 11:13:18 +00001963 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
bellard3fc6c082005-07-02 20:59:34 +00001964 if (env->sdr1 != value) {
j_mayer12de9a32007-10-05 22:06:02 +00001965 /* XXX: for PowerPC 64, should check that the HTABSIZE value
1966 * is <= 28
1967 */
bellard3fc6c082005-07-02 20:59:34 +00001968 env->sdr1 = value;
j_mayer76a66252007-03-07 08:32:30 +00001969 tlb_flush(env, 1);
bellard3fc6c082005-07-02 20:59:34 +00001970 }
1971}
1972
blueswir1f6b868fc2009-03-07 20:50:01 +00001973#if defined(TARGET_PPC64)
1974target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
1975{
1976 // XXX
1977 return 0;
1978}
1979#endif
1980
aurel3245d827d2008-12-07 13:40:29 +00001981void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
bellard3fc6c082005-07-02 20:59:34 +00001982{
Blue Swirl90e189e2009-08-16 11:13:18 +00001983 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
1984 srnum, value, env->sr[srnum]);
blueswir1f6b868fc2009-03-07 20:50:01 +00001985#if defined(TARGET_PPC64)
1986 if (env->mmu_model & POWERPC_MMU_64) {
1987 uint64_t rb = 0, rs = 0;
1988
1989 /* ESID = srnum */
1990 rb |= ((uint32_t)srnum & 0xf) << 28;
1991 /* Set the valid bit */
1992 rb |= 1 << 27;
1993 /* Index = ESID */
1994 rb |= (uint32_t)srnum;
1995
1996 /* VSID = VSID */
1997 rs |= (value & 0xfffffff) << 12;
1998 /* flags = flags */
1999 rs |= ((value >> 27) & 0xf) << 9;
2000
2001 ppc_store_slb(env, rb, rs);
2002 } else
2003#endif
bellard3fc6c082005-07-02 20:59:34 +00002004 if (env->sr[srnum] != value) {
2005 env->sr[srnum] = value;
aurel32bf1752e2009-03-29 13:36:32 +00002006/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2007 flusing the whole TLB. */
bellard3fc6c082005-07-02 20:59:34 +00002008#if !defined(FLUSH_ALL_TLBS) && 0
2009 {
2010 target_ulong page, end;
2011 /* Invalidate 256 MB of virtual memory */
2012 page = (16 << 20) * srnum;
2013 end = page + (16 << 20);
2014 for (; page != end; page += TARGET_PAGE_SIZE)
2015 tlb_flush_page(env, page);
2016 }
2017#else
j_mayer76a66252007-03-07 08:32:30 +00002018 tlb_flush(env, 1);
bellard3fc6c082005-07-02 20:59:34 +00002019#endif
2020 }
2021}
j_mayer76a66252007-03-07 08:32:30 +00002022#endif /* !defined (CONFIG_USER_ONLY) */
bellard3fc6c082005-07-02 20:59:34 +00002023
j_mayer76a66252007-03-07 08:32:30 +00002024/* GDBstub can read and write MSR... */
j_mayer0411a972007-10-25 21:35:50 +00002025void ppc_store_msr (CPUPPCState *env, target_ulong value)
bellard79aceca2003-11-23 14:55:54 +00002026{
j_mayera4f30712007-11-17 21:14:09 +00002027 hreg_store_msr(env, value, 0);
bellard3fc6c082005-07-02 20:59:34 +00002028}
2029
2030/*****************************************************************************/
2031/* Exception processing */
bellard18fba282005-02-08 21:24:36 +00002032#if defined (CONFIG_USER_ONLY)
bellard9a64fbe2004-01-04 22:58:38 +00002033void do_interrupt (CPUState *env)
bellard79aceca2003-11-23 14:55:54 +00002034{
j_mayere1833e12007-09-29 13:06:16 +00002035 env->exception_index = POWERPC_EXCP_NONE;
2036 env->error_code = 0;
bellard18fba282005-02-08 21:24:36 +00002037}
j_mayer47103572007-03-30 09:38:04 +00002038
j_mayere9df0142007-04-09 22:45:36 +00002039void ppc_hw_interrupt (CPUState *env)
j_mayer47103572007-03-30 09:38:04 +00002040{
j_mayere1833e12007-09-29 13:06:16 +00002041 env->exception_index = POWERPC_EXCP_NONE;
2042 env->error_code = 0;
j_mayer47103572007-03-30 09:38:04 +00002043}
j_mayer76a66252007-03-07 08:32:30 +00002044#else /* defined (CONFIG_USER_ONLY) */
Blue Swirl636aa202009-08-16 09:06:54 +00002045static inline void dump_syscall(CPUState *env)
bellardd0948072005-06-04 22:17:59 +00002046{
Blue Swirlb11ebf62009-08-16 11:54:37 +00002047 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
2048 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
2049 " nip=" TARGET_FMT_lx "\n",
Blue Swirl90e189e2009-08-16 11:13:18 +00002050 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
2051 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
2052 ppc_dump_gpr(env, 6), env->nip);
bellardd0948072005-06-04 22:17:59 +00002053}
2054
j_mayere1833e12007-09-29 13:06:16 +00002055/* Note that this function should be greatly optimized
2056 * when called with a constant excp, from ppc_hw_interrupt
2057 */
Blue Swirl636aa202009-08-16 09:06:54 +00002058static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
bellard18fba282005-02-08 21:24:36 +00002059{
j_mayer0411a972007-10-25 21:35:50 +00002060 target_ulong msr, new_msr, vector;
j_mayere1833e12007-09-29 13:06:16 +00002061 int srr0, srr1, asrr0, asrr1;
j_mayera4f30712007-11-17 21:14:09 +00002062 int lpes0, lpes1, lev;
bellard79aceca2003-11-23 14:55:54 +00002063
j_mayerb172c562007-11-17 01:37:44 +00002064 if (0) {
2065 /* XXX: find a suitable condition to enable the hypervisor mode */
2066 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
2067 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
2068 } else {
2069 /* Those values ensure we won't enter the hypervisor mode */
2070 lpes0 = 0;
2071 lpes1 = 1;
2072 }
2073
Blue Swirl90e189e2009-08-16 11:13:18 +00002074 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
2075 " => %08x (%02x)\n", env->nip, excp, env->error_code);
j_mayer0411a972007-10-25 21:35:50 +00002076 msr = env->msr;
2077 new_msr = msr;
j_mayere1833e12007-09-29 13:06:16 +00002078 srr0 = SPR_SRR0;
2079 srr1 = SPR_SRR1;
2080 asrr0 = -1;
2081 asrr1 = -1;
2082 msr &= ~((target_ulong)0x783F0000);
bellard9a64fbe2004-01-04 22:58:38 +00002083 switch (excp) {
j_mayere1833e12007-09-29 13:06:16 +00002084 case POWERPC_EXCP_NONE:
2085 /* Should never happen */
2086 return;
2087 case POWERPC_EXCP_CRITICAL: /* Critical input */
j_mayer0411a972007-10-25 21:35:50 +00002088 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002089 switch (excp_model) {
j_mayera750fc02007-09-26 23:54:22 +00002090 case POWERPC_EXCP_40x:
j_mayere1833e12007-09-29 13:06:16 +00002091 srr0 = SPR_40x_SRR2;
2092 srr1 = SPR_40x_SRR3;
j_mayerc62db102007-03-31 12:57:57 +00002093 break;
j_mayera750fc02007-09-26 23:54:22 +00002094 case POWERPC_EXCP_BOOKE:
j_mayere1833e12007-09-29 13:06:16 +00002095 srr0 = SPR_BOOKE_CSRR0;
2096 srr1 = SPR_BOOKE_CSRR1;
2097 break;
2098 case POWERPC_EXCP_G2:
j_mayerc62db102007-03-31 12:57:57 +00002099 break;
2100 default:
j_mayere1833e12007-09-29 13:06:16 +00002101 goto excp_invalid;
2102 }
2103 goto store_next;
2104 case POWERPC_EXCP_MCHECK: /* Machine check exception */
2105 if (msr_me == 0) {
j_mayere63ecc62007-10-14 08:48:23 +00002106 /* Machine check exception is not enabled.
2107 * Enter checkstop state.
2108 */
aliguori93fcfe32009-01-15 22:34:14 +00002109 if (qemu_log_enabled()) {
2110 qemu_log("Machine check while not allowed. "
j_mayere63ecc62007-10-14 08:48:23 +00002111 "Entering checkstop state\n");
2112 } else {
2113 fprintf(stderr, "Machine check while not allowed. "
2114 "Entering checkstop state\n");
2115 }
2116 env->halted = 1;
2117 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
j_mayere1833e12007-09-29 13:06:16 +00002118 }
j_mayer0411a972007-10-25 21:35:50 +00002119 new_msr &= ~((target_ulong)1 << MSR_RI);
2120 new_msr &= ~((target_ulong)1 << MSR_ME);
j_mayerb172c562007-11-17 01:37:44 +00002121 if (0) {
2122 /* XXX: find a suitable condition to enable the hypervisor mode */
j_mayera4f30712007-11-17 21:14:09 +00002123 new_msr |= (target_ulong)MSR_HVB;
j_mayerb172c562007-11-17 01:37:44 +00002124 }
j_mayere1833e12007-09-29 13:06:16 +00002125 /* XXX: should also have something loaded in DAR / DSISR */
2126 switch (excp_model) {
2127 case POWERPC_EXCP_40x:
2128 srr0 = SPR_40x_SRR2;
2129 srr1 = SPR_40x_SRR3;
2130 break;
2131 case POWERPC_EXCP_BOOKE:
2132 srr0 = SPR_BOOKE_MCSRR0;
2133 srr1 = SPR_BOOKE_MCSRR1;
2134 asrr0 = SPR_BOOKE_CSRR0;
2135 asrr1 = SPR_BOOKE_CSRR1;
2136 break;
2137 default:
j_mayerc62db102007-03-31 12:57:57 +00002138 break;
bellard2be00712005-07-02 22:09:27 +00002139 }
bellard9a64fbe2004-01-04 22:58:38 +00002140 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002141 case POWERPC_EXCP_DSI: /* Data storage exception */
Blue Swirl90e189e2009-08-16 11:13:18 +00002142 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
2143 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
j_mayer0411a972007-10-25 21:35:50 +00002144 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002145 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002146 new_msr |= (target_ulong)MSR_HVB;
bellarda541f292004-04-12 20:39:29 +00002147 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002148 case POWERPC_EXCP_ISI: /* Instruction storage exception */
Blue Swirl90e189e2009-08-16 11:13:18 +00002149 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
2150 "\n", msr, env->nip);
j_mayer0411a972007-10-25 21:35:50 +00002151 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002152 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002153 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002154 msr |= env->error_code;
bellard9a64fbe2004-01-04 22:58:38 +00002155 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002156 case POWERPC_EXCP_EXTERNAL: /* External input */
j_mayer0411a972007-10-25 21:35:50 +00002157 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002158 if (lpes0 == 1)
j_mayera4f30712007-11-17 21:14:09 +00002159 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002160 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002161 case POWERPC_EXCP_ALIGN: /* Alignment exception */
j_mayer0411a972007-10-25 21:35:50 +00002162 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002163 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002164 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002165 /* XXX: this is false */
2166 /* Get rS/rD and rA from faulting opcode */
2167 env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
bellard9a64fbe2004-01-04 22:58:38 +00002168 goto store_current;
j_mayere1833e12007-09-29 13:06:16 +00002169 case POWERPC_EXCP_PROGRAM: /* Program exception */
bellard9a64fbe2004-01-04 22:58:38 +00002170 switch (env->error_code & ~0xF) {
j_mayere1833e12007-09-29 13:06:16 +00002171 case POWERPC_EXCP_FP:
2172 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
aliguorid12d51d2009-01-15 21:48:06 +00002173 LOG_EXCP("Ignore floating point exception\n");
j_mayer7c580442007-10-27 17:54:30 +00002174 env->exception_index = POWERPC_EXCP_NONE;
2175 env->error_code = 0;
bellard9a64fbe2004-01-04 22:58:38 +00002176 return;
j_mayer76a66252007-03-07 08:32:30 +00002177 }
j_mayer0411a972007-10-25 21:35:50 +00002178 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002179 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002180 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002181 msr |= 0x00100000;
j_mayer5b52b992007-11-02 22:35:33 +00002182 if (msr_fe0 == msr_fe1)
2183 goto store_next;
2184 msr |= 0x00010000;
j_mayer76a66252007-03-07 08:32:30 +00002185 break;
j_mayere1833e12007-09-29 13:06:16 +00002186 case POWERPC_EXCP_INVAL:
Blue Swirl90e189e2009-08-16 11:13:18 +00002187 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
j_mayer0411a972007-10-25 21:35:50 +00002188 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002189 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002190 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002191 msr |= 0x00080000;
j_mayer76a66252007-03-07 08:32:30 +00002192 break;
j_mayere1833e12007-09-29 13:06:16 +00002193 case POWERPC_EXCP_PRIV:
j_mayer0411a972007-10-25 21:35:50 +00002194 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002195 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002196 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002197 msr |= 0x00040000;
j_mayer76a66252007-03-07 08:32:30 +00002198 break;
j_mayere1833e12007-09-29 13:06:16 +00002199 case POWERPC_EXCP_TRAP:
j_mayer0411a972007-10-25 21:35:50 +00002200 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002201 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002202 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002203 msr |= 0x00020000;
2204 break;
2205 default:
2206 /* Should never occur */
j_mayere1833e12007-09-29 13:06:16 +00002207 cpu_abort(env, "Invalid program exception %d. Aborting\n",
2208 env->error_code);
j_mayer76a66252007-03-07 08:32:30 +00002209 break;
2210 }
j_mayer5b52b992007-11-02 22:35:33 +00002211 goto store_current;
j_mayere1833e12007-09-29 13:06:16 +00002212 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
j_mayer0411a972007-10-25 21:35:50 +00002213 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002214 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002215 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002216 goto store_current;
2217 case POWERPC_EXCP_SYSCALL: /* System call exception */
bellardd0948072005-06-04 22:17:59 +00002218 /* NOTE: this is a temporary hack to support graphics OSI
2219 calls from the MOL driver */
j_mayere1833e12007-09-29 13:06:16 +00002220 /* XXX: To be removed */
bellardd0948072005-06-04 22:17:59 +00002221 if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
2222 env->osi_call) {
j_mayer7c580442007-10-27 17:54:30 +00002223 if (env->osi_call(env) != 0) {
2224 env->exception_index = POWERPC_EXCP_NONE;
2225 env->error_code = 0;
bellardd0948072005-06-04 22:17:59 +00002226 return;
j_mayer7c580442007-10-27 17:54:30 +00002227 }
bellardd0948072005-06-04 22:17:59 +00002228 }
aliguori93fcfe32009-01-15 22:34:14 +00002229 dump_syscall(env);
j_mayer0411a972007-10-25 21:35:50 +00002230 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayerf9fdea62007-10-26 00:38:37 +00002231 lev = env->error_code;
j_mayere1833e12007-09-29 13:06:16 +00002232 if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
j_mayera4f30712007-11-17 21:14:09 +00002233 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002234 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002235 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
j_mayer0411a972007-10-25 21:35:50 +00002236 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002237 goto store_current;
2238 case POWERPC_EXCP_DECR: /* Decrementer exception */
j_mayer0411a972007-10-25 21:35:50 +00002239 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002240 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002241 new_msr |= (target_ulong)MSR_HVB;
bellard9a64fbe2004-01-04 22:58:38 +00002242 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002243 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
2244 /* FIT on 4xx */
aliguorid12d51d2009-01-15 21:48:06 +00002245 LOG_EXCP("FIT exception\n");
j_mayer0411a972007-10-25 21:35:50 +00002246 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002247 goto store_next;
2248 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
aliguorid12d51d2009-01-15 21:48:06 +00002249 LOG_EXCP("WDT exception\n");
j_mayere1833e12007-09-29 13:06:16 +00002250 switch (excp_model) {
2251 case POWERPC_EXCP_BOOKE:
2252 srr0 = SPR_BOOKE_CSRR0;
2253 srr1 = SPR_BOOKE_CSRR1;
2254 break;
2255 default:
2256 break;
2257 }
j_mayer0411a972007-10-25 21:35:50 +00002258 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002259 goto store_next;
2260 case POWERPC_EXCP_DTLB: /* Data TLB error */
j_mayer0411a972007-10-25 21:35:50 +00002261 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002262 goto store_next;
2263 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
j_mayer0411a972007-10-25 21:35:50 +00002264 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002265 goto store_next;
2266 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
2267 switch (excp_model) {
2268 case POWERPC_EXCP_BOOKE:
2269 srr0 = SPR_BOOKE_DSRR0;
2270 srr1 = SPR_BOOKE_DSRR1;
2271 asrr0 = SPR_BOOKE_CSRR0;
2272 asrr1 = SPR_BOOKE_CSRR1;
2273 break;
2274 default:
2275 break;
2276 }
2277 /* XXX: TODO */
2278 cpu_abort(env, "Debug exception is not implemented yet !\n");
2279 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002280 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
j_mayer0411a972007-10-25 21:35:50 +00002281 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002282 goto store_current;
2283 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
2284 /* XXX: TODO */
2285 cpu_abort(env, "Embedded floating point data exception "
2286 "is not implemented yet !\n");
2287 goto store_next;
2288 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
2289 /* XXX: TODO */
2290 cpu_abort(env, "Embedded floating point round exception "
2291 "is not implemented yet !\n");
2292 goto store_next;
2293 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
j_mayer0411a972007-10-25 21:35:50 +00002294 new_msr &= ~((target_ulong)1 << MSR_RI);
bellard2be00712005-07-02 22:09:27 +00002295 /* XXX: TODO */
2296 cpu_abort(env,
2297 "Performance counter exception is not implemented yet !\n");
bellard9a64fbe2004-01-04 22:58:38 +00002298 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002299 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
bellard2be00712005-07-02 22:09:27 +00002300 /* XXX: TODO */
j_mayere1833e12007-09-29 13:06:16 +00002301 cpu_abort(env,
2302 "Embedded doorbell interrupt is not implemented yet !\n");
2303 goto store_next;
2304 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
2305 switch (excp_model) {
2306 case POWERPC_EXCP_BOOKE:
2307 srr0 = SPR_BOOKE_CSRR0;
2308 srr1 = SPR_BOOKE_CSRR1;
2309 break;
2310 default:
2311 break;
2312 }
2313 /* XXX: TODO */
2314 cpu_abort(env, "Embedded doorbell critical interrupt "
bellard2be00712005-07-02 22:09:27 +00002315 "is not implemented yet !\n");
2316 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002317 case POWERPC_EXCP_RESET: /* System reset exception */
j_mayer0411a972007-10-25 21:35:50 +00002318 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayera4f30712007-11-17 21:14:09 +00002319 if (0) {
2320 /* XXX: find a suitable condition to enable the hypervisor mode */
2321 new_msr |= (target_ulong)MSR_HVB;
2322 }
j_mayere1833e12007-09-29 13:06:16 +00002323 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002324 case POWERPC_EXCP_DSEG: /* Data segment exception */
j_mayer0411a972007-10-25 21:35:50 +00002325 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002326 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002327 new_msr |= (target_ulong)MSR_HVB;
bellard2be00712005-07-02 22:09:27 +00002328 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002329 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
j_mayer0411a972007-10-25 21:35:50 +00002330 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002331 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002332 new_msr |= (target_ulong)MSR_HVB;
bellard2be00712005-07-02 22:09:27 +00002333 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002334 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
2335 srr0 = SPR_HSRR0;
j_mayerf9fdea62007-10-26 00:38:37 +00002336 srr1 = SPR_HSRR1;
j_mayera4f30712007-11-17 21:14:09 +00002337 new_msr |= (target_ulong)MSR_HVB;
j_mayerb172c562007-11-17 01:37:44 +00002338 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002339 case POWERPC_EXCP_TRACE: /* Trace exception */
j_mayer0411a972007-10-25 21:35:50 +00002340 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002341 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002342 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002343 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002344 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
2345 srr0 = SPR_HSRR0;
j_mayerf9fdea62007-10-26 00:38:37 +00002346 srr1 = SPR_HSRR1;
j_mayera4f30712007-11-17 21:14:09 +00002347 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002348 goto store_next;
2349 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
2350 srr0 = SPR_HSRR0;
j_mayerf9fdea62007-10-26 00:38:37 +00002351 srr1 = SPR_HSRR1;
j_mayera4f30712007-11-17 21:14:09 +00002352 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002353 goto store_next;
2354 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
2355 srr0 = SPR_HSRR0;
j_mayerf9fdea62007-10-26 00:38:37 +00002356 srr1 = SPR_HSRR1;
j_mayera4f30712007-11-17 21:14:09 +00002357 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002358 goto store_next;
2359 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
2360 srr0 = SPR_HSRR0;
j_mayerf9fdea62007-10-26 00:38:37 +00002361 srr1 = SPR_HSRR1;
j_mayera4f30712007-11-17 21:14:09 +00002362 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002363 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002364 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
j_mayer0411a972007-10-25 21:35:50 +00002365 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002366 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002367 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002368 goto store_current;
2369 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
aliguorid12d51d2009-01-15 21:48:06 +00002370 LOG_EXCP("PIT exception\n");
j_mayer0411a972007-10-25 21:35:50 +00002371 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayere1833e12007-09-29 13:06:16 +00002372 goto store_next;
2373 case POWERPC_EXCP_IO: /* IO error exception */
2374 /* XXX: TODO */
2375 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
2376 goto store_next;
2377 case POWERPC_EXCP_RUNM: /* Run mode exception */
2378 /* XXX: TODO */
2379 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
2380 goto store_next;
2381 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
2382 /* XXX: TODO */
2383 cpu_abort(env, "602 emulation trap exception "
2384 "is not implemented yet !\n");
2385 goto store_next;
2386 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
j_mayer0411a972007-10-25 21:35:50 +00002387 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayera4f30712007-11-17 21:14:09 +00002388 if (lpes1 == 0) /* XXX: check this */
2389 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002390 switch (excp_model) {
j_mayera750fc02007-09-26 23:54:22 +00002391 case POWERPC_EXCP_602:
2392 case POWERPC_EXCP_603:
2393 case POWERPC_EXCP_603E:
2394 case POWERPC_EXCP_G2:
j_mayere1833e12007-09-29 13:06:16 +00002395 goto tlb_miss_tgpr;
j_mayera750fc02007-09-26 23:54:22 +00002396 case POWERPC_EXCP_7x5:
j_mayer76a66252007-03-07 08:32:30 +00002397 goto tlb_miss;
j_mayer7dbe11a2007-10-01 05:16:57 +00002398 case POWERPC_EXCP_74xx:
2399 goto tlb_miss_74xx;
bellard2be00712005-07-02 22:09:27 +00002400 default:
j_mayere1833e12007-09-29 13:06:16 +00002401 cpu_abort(env, "Invalid instruction TLB miss exception\n");
bellard2be00712005-07-02 22:09:27 +00002402 break;
2403 }
j_mayere1833e12007-09-29 13:06:16 +00002404 break;
2405 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
j_mayer0411a972007-10-25 21:35:50 +00002406 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayera4f30712007-11-17 21:14:09 +00002407 if (lpes1 == 0) /* XXX: check this */
2408 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002409 switch (excp_model) {
j_mayera750fc02007-09-26 23:54:22 +00002410 case POWERPC_EXCP_602:
2411 case POWERPC_EXCP_603:
2412 case POWERPC_EXCP_603E:
2413 case POWERPC_EXCP_G2:
j_mayere1833e12007-09-29 13:06:16 +00002414 goto tlb_miss_tgpr;
j_mayera750fc02007-09-26 23:54:22 +00002415 case POWERPC_EXCP_7x5:
j_mayer76a66252007-03-07 08:32:30 +00002416 goto tlb_miss;
j_mayer7dbe11a2007-10-01 05:16:57 +00002417 case POWERPC_EXCP_74xx:
2418 goto tlb_miss_74xx;
bellard2be00712005-07-02 22:09:27 +00002419 default:
j_mayere1833e12007-09-29 13:06:16 +00002420 cpu_abort(env, "Invalid data load TLB miss exception\n");
bellard2be00712005-07-02 22:09:27 +00002421 break;
2422 }
j_mayere1833e12007-09-29 13:06:16 +00002423 break;
2424 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
j_mayer0411a972007-10-25 21:35:50 +00002425 new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
j_mayera4f30712007-11-17 21:14:09 +00002426 if (lpes1 == 0) /* XXX: check this */
2427 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002428 switch (excp_model) {
j_mayera750fc02007-09-26 23:54:22 +00002429 case POWERPC_EXCP_602:
2430 case POWERPC_EXCP_603:
2431 case POWERPC_EXCP_603E:
2432 case POWERPC_EXCP_G2:
j_mayere1833e12007-09-29 13:06:16 +00002433 tlb_miss_tgpr:
j_mayer76a66252007-03-07 08:32:30 +00002434 /* Swap temporary saved registers with GPRs */
j_mayer0411a972007-10-25 21:35:50 +00002435 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2436 new_msr |= (target_ulong)1 << MSR_TGPR;
2437 hreg_swap_gpr_tgpr(env);
2438 }
j_mayere1833e12007-09-29 13:06:16 +00002439 goto tlb_miss;
2440 case POWERPC_EXCP_7x5:
2441 tlb_miss:
bellard2be00712005-07-02 22:09:27 +00002442#if defined (DEBUG_SOFTWARE_TLB)
aliguori93fcfe32009-01-15 22:34:14 +00002443 if (qemu_log_enabled()) {
Blue Swirl0bf9e312009-07-20 17:19:25 +00002444 const char *es;
j_mayer76a66252007-03-07 08:32:30 +00002445 target_ulong *miss, *cmp;
2446 int en;
j_mayer1e6784f2007-09-30 15:19:48 +00002447 if (excp == POWERPC_EXCP_IFTLB) {
j_mayer76a66252007-03-07 08:32:30 +00002448 es = "I";
2449 en = 'I';
2450 miss = &env->spr[SPR_IMISS];
2451 cmp = &env->spr[SPR_ICMP];
2452 } else {
j_mayer1e6784f2007-09-30 15:19:48 +00002453 if (excp == POWERPC_EXCP_DLTLB)
j_mayer76a66252007-03-07 08:32:30 +00002454 es = "DL";
2455 else
2456 es = "DS";
2457 en = 'D';
2458 miss = &env->spr[SPR_DMISS];
2459 cmp = &env->spr[SPR_DCMP];
2460 }
Blue Swirl90e189e2009-08-16 11:13:18 +00002461 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2462 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
2463 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2464 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
2465 env->error_code);
bellard2be00712005-07-02 22:09:27 +00002466 }
2467#endif
bellard2be00712005-07-02 22:09:27 +00002468 msr |= env->crf[0] << 28;
2469 msr |= env->error_code; /* key, D/I, S/L bits */
2470 /* Set way using a LRU mechanism */
j_mayer76a66252007-03-07 08:32:30 +00002471 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
j_mayerc62db102007-03-31 12:57:57 +00002472 break;
j_mayer7dbe11a2007-10-01 05:16:57 +00002473 case POWERPC_EXCP_74xx:
2474 tlb_miss_74xx:
2475#if defined (DEBUG_SOFTWARE_TLB)
aliguori93fcfe32009-01-15 22:34:14 +00002476 if (qemu_log_enabled()) {
Blue Swirl0bf9e312009-07-20 17:19:25 +00002477 const char *es;
j_mayer7dbe11a2007-10-01 05:16:57 +00002478 target_ulong *miss, *cmp;
2479 int en;
2480 if (excp == POWERPC_EXCP_IFTLB) {
2481 es = "I";
2482 en = 'I';
j_mayer0411a972007-10-25 21:35:50 +00002483 miss = &env->spr[SPR_TLBMISS];
2484 cmp = &env->spr[SPR_PTEHI];
j_mayer7dbe11a2007-10-01 05:16:57 +00002485 } else {
2486 if (excp == POWERPC_EXCP_DLTLB)
2487 es = "DL";
2488 else
2489 es = "DS";
2490 en = 'D';
2491 miss = &env->spr[SPR_TLBMISS];
2492 cmp = &env->spr[SPR_PTEHI];
2493 }
Blue Swirl90e189e2009-08-16 11:13:18 +00002494 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2495 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2496 env->error_code);
j_mayer7dbe11a2007-10-01 05:16:57 +00002497 }
2498#endif
2499 msr |= env->error_code; /* key bit */
2500 break;
bellard2be00712005-07-02 22:09:27 +00002501 default:
j_mayere1833e12007-09-29 13:06:16 +00002502 cpu_abort(env, "Invalid data store TLB miss exception\n");
bellard2be00712005-07-02 22:09:27 +00002503 break;
2504 }
j_mayere1833e12007-09-29 13:06:16 +00002505 goto store_next;
2506 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
2507 /* XXX: TODO */
2508 cpu_abort(env, "Floating point assist exception "
2509 "is not implemented yet !\n");
2510 goto store_next;
j_mayerb4095fe2007-11-17 22:42:36 +00002511 case POWERPC_EXCP_DABR: /* Data address breakpoint */
2512 /* XXX: TODO */
2513 cpu_abort(env, "DABR exception is not implemented yet !\n");
2514 goto store_next;
j_mayere1833e12007-09-29 13:06:16 +00002515 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
2516 /* XXX: TODO */
2517 cpu_abort(env, "IABR exception is not implemented yet !\n");
2518 goto store_next;
2519 case POWERPC_EXCP_SMI: /* System management interrupt */
2520 /* XXX: TODO */
2521 cpu_abort(env, "SMI exception is not implemented yet !\n");
2522 goto store_next;
2523 case POWERPC_EXCP_THERM: /* Thermal interrupt */
2524 /* XXX: TODO */
2525 cpu_abort(env, "Thermal management exception "
2526 "is not implemented yet !\n");
2527 goto store_next;
2528 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
j_mayer0411a972007-10-25 21:35:50 +00002529 new_msr &= ~((target_ulong)1 << MSR_RI);
j_mayere1833e12007-09-29 13:06:16 +00002530 if (lpes1 == 0)
j_mayera4f30712007-11-17 21:14:09 +00002531 new_msr |= (target_ulong)MSR_HVB;
j_mayere1833e12007-09-29 13:06:16 +00002532 /* XXX: TODO */
2533 cpu_abort(env,
2534 "Performance counter exception is not implemented yet !\n");
2535 goto store_next;
2536 case POWERPC_EXCP_VPUA: /* Vector assist exception */
2537 /* XXX: TODO */
2538 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
2539 goto store_next;
2540 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
2541 /* XXX: TODO */
2542 cpu_abort(env,
2543 "970 soft-patch exception is not implemented yet !\n");
2544 goto store_next;
2545 case POWERPC_EXCP_MAINT: /* Maintenance exception */
2546 /* XXX: TODO */
2547 cpu_abort(env,
2548 "970 maintenance exception is not implemented yet !\n");
2549 goto store_next;
j_mayerb4095fe2007-11-17 22:42:36 +00002550 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
2551 /* XXX: TODO */
2552 cpu_abort(env, "Maskable external exception "
2553 "is not implemented yet !\n");
2554 goto store_next;
2555 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
2556 /* XXX: TODO */
2557 cpu_abort(env, "Non maskable external exception "
2558 "is not implemented yet !\n");
2559 goto store_next;
bellard2be00712005-07-02 22:09:27 +00002560 default:
j_mayere1833e12007-09-29 13:06:16 +00002561 excp_invalid:
2562 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
2563 break;
bellard9a64fbe2004-01-04 22:58:38 +00002564 store_current:
bellard2be00712005-07-02 22:09:27 +00002565 /* save current instruction location */
j_mayere1833e12007-09-29 13:06:16 +00002566 env->spr[srr0] = env->nip - 4;
bellard9a64fbe2004-01-04 22:58:38 +00002567 break;
2568 store_next:
bellard2be00712005-07-02 22:09:27 +00002569 /* save next instruction location */
j_mayere1833e12007-09-29 13:06:16 +00002570 env->spr[srr0] = env->nip;
bellard9a64fbe2004-01-04 22:58:38 +00002571 break;
2572 }
j_mayere1833e12007-09-29 13:06:16 +00002573 /* Save MSR */
2574 env->spr[srr1] = msr;
2575 /* If any alternate SRR register are defined, duplicate saved values */
2576 if (asrr0 != -1)
2577 env->spr[asrr0] = env->spr[srr0];
2578 if (asrr1 != -1)
2579 env->spr[asrr1] = env->spr[srr1];
bellard2be00712005-07-02 22:09:27 +00002580 /* If we disactivated any translation, flush TLBs */
j_mayer0411a972007-10-25 21:35:50 +00002581 if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
bellard2be00712005-07-02 22:09:27 +00002582 tlb_flush(env, 1);
bellard9a64fbe2004-01-04 22:58:38 +00002583 /* reload MSR with correct bits */
j_mayer0411a972007-10-25 21:35:50 +00002584 new_msr &= ~((target_ulong)1 << MSR_EE);
2585 new_msr &= ~((target_ulong)1 << MSR_PR);
2586 new_msr &= ~((target_ulong)1 << MSR_FP);
2587 new_msr &= ~((target_ulong)1 << MSR_FE0);
2588 new_msr &= ~((target_ulong)1 << MSR_SE);
2589 new_msr &= ~((target_ulong)1 << MSR_BE);
2590 new_msr &= ~((target_ulong)1 << MSR_FE1);
2591 new_msr &= ~((target_ulong)1 << MSR_IR);
2592 new_msr &= ~((target_ulong)1 << MSR_DR);
j_mayere1833e12007-09-29 13:06:16 +00002593#if 0 /* Fix this: not on all targets */
j_mayer0411a972007-10-25 21:35:50 +00002594 new_msr &= ~((target_ulong)1 << MSR_PMM);
j_mayerc62db102007-03-31 12:57:57 +00002595#endif
j_mayer0411a972007-10-25 21:35:50 +00002596 new_msr &= ~((target_ulong)1 << MSR_LE);
2597 if (msr_ile)
2598 new_msr |= (target_ulong)1 << MSR_LE;
2599 else
2600 new_msr &= ~((target_ulong)1 << MSR_LE);
bellard9a64fbe2004-01-04 22:58:38 +00002601 /* Jump to handler */
j_mayere1833e12007-09-29 13:06:16 +00002602 vector = env->excp_vectors[excp];
j_mayer6f2d8972007-11-12 00:04:48 +00002603 if (vector == (target_ulong)-1ULL) {
j_mayere1833e12007-09-29 13:06:16 +00002604 cpu_abort(env, "Raised an exception without defined vector %d\n",
2605 excp);
2606 }
2607 vector |= env->excp_prefix;
2608#if defined(TARGET_PPC64)
2609 if (excp_model == POWERPC_EXCP_BOOKE) {
j_mayer0411a972007-10-25 21:35:50 +00002610 if (!msr_icm) {
2611 new_msr &= ~((target_ulong)1 << MSR_CM);
j_mayere1833e12007-09-29 13:06:16 +00002612 vector = (uint32_t)vector;
j_mayer0411a972007-10-25 21:35:50 +00002613 } else {
2614 new_msr |= (target_ulong)1 << MSR_CM;
2615 }
j_mayere1833e12007-09-29 13:06:16 +00002616 } else {
blueswir16ce0ca12009-03-07 20:54:59 +00002617 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
j_mayer0411a972007-10-25 21:35:50 +00002618 new_msr &= ~((target_ulong)1 << MSR_SF);
j_mayere1833e12007-09-29 13:06:16 +00002619 vector = (uint32_t)vector;
j_mayer0411a972007-10-25 21:35:50 +00002620 } else {
2621 new_msr |= (target_ulong)1 << MSR_SF;
2622 }
j_mayere1833e12007-09-29 13:06:16 +00002623 }
2624#endif
j_mayer0411a972007-10-25 21:35:50 +00002625 /* XXX: we don't use hreg_store_msr here as already have treated
2626 * any special case that could occur. Just store MSR and update hflags
2627 */
j_mayera4f30712007-11-17 21:14:09 +00002628 env->msr = new_msr & env->msr_mask;
j_mayer0411a972007-10-25 21:35:50 +00002629 hreg_compute_hflags(env);
j_mayere1833e12007-09-29 13:06:16 +00002630 env->nip = vector;
2631 /* Reset exception state */
2632 env->exception_index = POWERPC_EXCP_NONE;
2633 env->error_code = 0;
2634}
2635
2636void do_interrupt (CPUState *env)
2637{
2638 powerpc_excp(env, env->excp_model, env->exception_index);
bellardfb0eaff2004-01-04 14:57:11 +00002639}
j_mayer47103572007-03-30 09:38:04 +00002640
j_mayere9df0142007-04-09 22:45:36 +00002641void ppc_hw_interrupt (CPUPPCState *env)
j_mayer47103572007-03-30 09:38:04 +00002642{
j_mayerf9fdea62007-10-26 00:38:37 +00002643 int hdice;
j_mayerf9fdea62007-10-26 00:38:37 +00002644
j_mayer0411a972007-10-25 21:35:50 +00002645#if 0
aliguori93fcfe32009-01-15 22:34:14 +00002646 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
j_mayera4967752007-04-16 07:10:48 +00002647 __func__, env, env->pending_interrupts,
j_mayer0411a972007-10-25 21:35:50 +00002648 env->interrupt_request, (int)msr_me, (int)msr_ee);
j_mayer47103572007-03-30 09:38:04 +00002649#endif
j_mayere1833e12007-09-29 13:06:16 +00002650 /* External reset */
j_mayer47103572007-03-30 09:38:04 +00002651 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
j_mayer47103572007-03-30 09:38:04 +00002652 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
j_mayere1833e12007-09-29 13:06:16 +00002653 powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
2654 return;
j_mayer47103572007-03-30 09:38:04 +00002655 }
j_mayere1833e12007-09-29 13:06:16 +00002656 /* Machine check exception */
2657 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
2658 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
2659 powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
2660 return;
j_mayer47103572007-03-30 09:38:04 +00002661 }
j_mayere1833e12007-09-29 13:06:16 +00002662#if 0 /* TODO */
2663 /* External debug exception */
2664 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
2665 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
2666 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
2667 return;
2668 }
2669#endif
j_mayerb172c562007-11-17 01:37:44 +00002670 if (0) {
2671 /* XXX: find a suitable condition to enable the hypervisor mode */
2672 hdice = env->spr[SPR_LPCR] & 1;
2673 } else {
2674 hdice = 0;
2675 }
j_mayerf9fdea62007-10-26 00:38:37 +00002676 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
j_mayer47103572007-03-30 09:38:04 +00002677 /* Hypervisor decrementer exception */
2678 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
j_mayer47103572007-03-30 09:38:04 +00002679 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
j_mayere1833e12007-09-29 13:06:16 +00002680 powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
2681 return;
2682 }
2683 }
j_mayere1833e12007-09-29 13:06:16 +00002684 if (msr_ce != 0) {
2685 /* External critical interrupt */
2686 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
2687 /* Taking a critical external interrupt does not clear the external
2688 * critical interrupt status
2689 */
2690#if 0
2691 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
2692#endif
2693 powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
2694 return;
2695 }
2696 }
2697 if (msr_ee != 0) {
j_mayer47103572007-03-30 09:38:04 +00002698 /* Watchdog timer on embedded PowerPC */
j_mayere1833e12007-09-29 13:06:16 +00002699 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
j_mayer47103572007-03-30 09:38:04 +00002700 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
j_mayere1833e12007-09-29 13:06:16 +00002701 powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
2702 return;
2703 }
j_mayere1833e12007-09-29 13:06:16 +00002704 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
2705 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
2706 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
2707 return;
2708 }
j_mayere1833e12007-09-29 13:06:16 +00002709 /* Fixed interval timer on embedded PowerPC */
2710 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
2711 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
2712 powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
2713 return;
2714 }
2715 /* Programmable interval timer on embedded PowerPC */
2716 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
2717 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
2718 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
2719 return;
2720 }
2721 /* Decrementer exception */
2722 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
2723 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
2724 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
2725 return;
2726 }
j_mayere1833e12007-09-29 13:06:16 +00002727 /* External interrupt */
2728 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
2729 /* Taking an external interrupt does not clear the external
2730 * interrupt status
2731 */
2732#if 0
2733 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
2734#endif
2735 powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
2736 return;
2737 }
j_mayere1833e12007-09-29 13:06:16 +00002738 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
2739 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
2740 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
2741 return;
2742 }
j_mayere1833e12007-09-29 13:06:16 +00002743 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
2744 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
2745 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
2746 return;
2747 }
2748 /* Thermal interrupt */
2749 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
2750 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
2751 powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
2752 return;
2753 }
j_mayer47103572007-03-30 09:38:04 +00002754 }
j_mayer47103572007-03-30 09:38:04 +00002755}
bellard18fba282005-02-08 21:24:36 +00002756#endif /* !CONFIG_USER_ONLY */
j_mayera4967752007-04-16 07:10:48 +00002757
j_mayer4a057712007-04-19 08:42:21 +00002758void cpu_dump_rfi (target_ulong RA, target_ulong msr)
2759{
Blue Swirl90e189e2009-08-16 11:13:18 +00002760 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
2761 TARGET_FMT_lx "\n", RA, msr);
j_mayera4967752007-04-16 07:10:48 +00002762}
2763
Blue Swirld84bda42009-11-07 10:36:04 +00002764void cpu_reset(CPUPPCState *env)
j_mayer0a032cb2007-04-16 08:56:52 +00002765{
j_mayer0411a972007-10-25 21:35:50 +00002766 target_ulong msr;
j_mayer0a032cb2007-04-16 08:56:52 +00002767
aliguorieca1bdf2009-01-26 19:54:31 +00002768 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
2769 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
2770 log_cpu_state(env, 0);
2771 }
2772
j_mayer0411a972007-10-25 21:35:50 +00002773 msr = (target_ulong)0;
j_mayera4f30712007-11-17 21:14:09 +00002774 if (0) {
2775 /* XXX: find a suitable condition to enable the hypervisor mode */
2776 msr |= (target_ulong)MSR_HVB;
2777 }
j_mayer0411a972007-10-25 21:35:50 +00002778 msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
2779 msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
2780 msr |= (target_ulong)1 << MSR_EP;
j_mayer0a032cb2007-04-16 08:56:52 +00002781#if defined (DO_SINGLE_STEP) && 0
2782 /* Single step trace mode */
j_mayer0411a972007-10-25 21:35:50 +00002783 msr |= (target_ulong)1 << MSR_SE;
2784 msr |= (target_ulong)1 << MSR_BE;
j_mayer0a032cb2007-04-16 08:56:52 +00002785#endif
j_mayer0a032cb2007-04-16 08:56:52 +00002786#if defined(CONFIG_USER_ONLY)
j_mayer0411a972007-10-25 21:35:50 +00002787 msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
aurel324c2ab982008-12-10 15:02:33 +00002788 msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
2789 msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
j_mayer0411a972007-10-25 21:35:50 +00002790 msr |= (target_ulong)1 << MSR_PR;
j_mayer0a032cb2007-04-16 08:56:52 +00002791#else
Blue Swirlfc1c67b2009-04-28 18:00:30 +00002792 env->excp_prefix = env->hreset_excp_prefix;
j_mayer1c27f8f2007-10-05 13:09:54 +00002793 env->nip = env->hreset_vector | env->excp_prefix;
j_mayerb4095fe2007-11-17 22:42:36 +00002794 if (env->mmu_model != POWERPC_MMU_REAL)
j_mayer141c8ae2007-10-08 02:44:11 +00002795 ppc_tlb_invalidate_all(env);
j_mayer0a032cb2007-04-16 08:56:52 +00002796#endif
blueswir107c485c2009-02-21 17:29:14 +00002797 env->msr = msr & env->msr_mask;
blueswir16ce0ca12009-03-07 20:54:59 +00002798#if defined(TARGET_PPC64)
2799 if (env->mmu_model & POWERPC_MMU_64)
2800 env->msr |= (1ULL << MSR_SF);
2801#endif
j_mayer0411a972007-10-25 21:35:50 +00002802 hreg_compute_hflags(env);
Nathan Froyd18b21a22009-08-03 08:43:25 -07002803 env->reserve_addr = (target_ulong)-1ULL;
j_mayer5eb79952007-09-19 05:44:04 +00002804 /* Be sure no exception or interrupt is pending */
2805 env->pending_interrupts = 0;
j_mayere1833e12007-09-29 13:06:16 +00002806 env->exception_index = POWERPC_EXCP_NONE;
2807 env->error_code = 0;
j_mayer5eb79952007-09-19 05:44:04 +00002808 /* Flush all TLBs */
2809 tlb_flush(env, 1);
j_mayer0a032cb2007-04-16 08:56:52 +00002810}
2811
bellardaaed9092007-11-10 15:15:54 +00002812CPUPPCState *cpu_ppc_init (const char *cpu_model)
j_mayer0a032cb2007-04-16 08:56:52 +00002813{
2814 CPUPPCState *env;
Anthony Liguoric227f092009-10-01 16:12:16 -05002815 const ppc_def_t *def;
bellardaaed9092007-11-10 15:15:54 +00002816
2817 def = cpu_ppc_find_by_name(cpu_model);
2818 if (!def)
2819 return NULL;
j_mayer0a032cb2007-04-16 08:56:52 +00002820
2821 env = qemu_mallocz(sizeof(CPUPPCState));
j_mayer0a032cb2007-04-16 08:56:52 +00002822 cpu_exec_init(env);
pbrook2e70f6e2008-06-29 01:03:05 +00002823 ppc_translate_init();
ths01ba9812007-12-09 02:22:57 +00002824 env->cpu_model_str = cpu_model;
bellardaaed9092007-11-10 15:15:54 +00002825 cpu_ppc_register_internal(env, def);
aurel32d76d1652008-12-16 10:43:58 +00002826
aliguori0bf46a42009-04-24 18:03:41 +00002827 qemu_init_vcpu(env);
aurel32d76d1652008-12-16 10:43:58 +00002828
j_mayer0a032cb2007-04-16 08:56:52 +00002829 return env;
2830}
2831
2832void cpu_ppc_close (CPUPPCState *env)
2833{
2834 /* Should also remove all opcode tables... */
bellardaaed9092007-11-10 15:15:54 +00002835 qemu_free(env);
j_mayer0a032cb2007-04-16 08:56:52 +00002836}