Revision e1833e1f target-ppc/helper.c
b/target-ppc/helper.c | ||
---|---|---|
44 | 44 |
int exception, error_code; |
45 | 45 |
|
46 | 46 |
if (rw == 2) { |
47 |
exception = EXCP_ISI; |
|
47 |
exception = POWERPC_EXCP_ISI;
|
|
48 | 48 |
error_code = 0; |
49 | 49 |
} else { |
50 |
exception = EXCP_DSI; |
|
50 |
exception = POWERPC_EXCP_DSI;
|
|
51 | 51 |
error_code = 0; |
52 | 52 |
if (rw) |
53 | 53 |
error_code |= 0x02000000; |
... | ... | |
1128 | 1128 |
ctx->prot |= PAGE_WRITE; |
1129 | 1129 |
} |
1130 | 1130 |
} |
1131 |
break; |
|
1131 | 1132 |
case POWERPC_MMU_BOOKE: |
1132 | 1133 |
ctx->prot |= PAGE_WRITE; |
1133 | 1134 |
break; |
... | ... | |
1250 | 1251 |
cpu_dump_state(env, logfile, fprintf, 0); |
1251 | 1252 |
#endif |
1252 | 1253 |
if (access_type == ACCESS_CODE) { |
1253 |
exception = EXCP_ISI; |
|
1254 |
exception = POWERPC_EXCP_ISI;
|
|
1254 | 1255 |
switch (ret) { |
1255 | 1256 |
case -1: |
1256 | 1257 |
/* No matches in page tables or TLB */ |
1257 | 1258 |
switch (env->mmu_model) { |
1258 | 1259 |
case POWERPC_MMU_SOFT_6xx: |
1259 |
exception = EXCP_I_TLBMISS;
|
|
1260 |
exception = POWERPC_EXCP_IFTLB;
|
|
1260 | 1261 |
env->spr[SPR_IMISS] = address; |
1261 | 1262 |
env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; |
1262 | 1263 |
error_code = 1 << 18; |
1263 | 1264 |
goto tlb_miss; |
1264 | 1265 |
case POWERPC_MMU_SOFT_4xx: |
1265 | 1266 |
case POWERPC_MMU_SOFT_4xx_Z: |
1266 |
exception = EXCP_40x_ITLBMISS;
|
|
1267 |
exception = POWERPC_EXCP_ITLB;
|
|
1267 | 1268 |
error_code = 0; |
1268 | 1269 |
env->spr[SPR_40x_DEAR] = address; |
1269 | 1270 |
env->spr[SPR_40x_ESR] = 0x00000000; |
... | ... | |
1315 | 1316 |
/* No code fetch is allowed in direct-store areas */ |
1316 | 1317 |
error_code = 0x10000000; |
1317 | 1318 |
break; |
1319 |
#if defined(TARGET_PPC64) |
|
1318 | 1320 |
case -5: |
1319 | 1321 |
/* No match in segment table */ |
1320 |
exception = EXCP_ISEG; |
|
1322 |
exception = POWERPC_EXCP_ISEG;
|
|
1321 | 1323 |
error_code = 0; |
1322 | 1324 |
break; |
1325 |
#endif |
|
1323 | 1326 |
} |
1324 | 1327 |
} else { |
1325 |
exception = EXCP_DSI; |
|
1328 |
exception = POWERPC_EXCP_DSI;
|
|
1326 | 1329 |
switch (ret) { |
1327 | 1330 |
case -1: |
1328 | 1331 |
/* No matches in page tables or TLB */ |
1329 | 1332 |
switch (env->mmu_model) { |
1330 | 1333 |
case POWERPC_MMU_SOFT_6xx: |
1331 | 1334 |
if (rw == 1) { |
1332 |
exception = EXCP_DS_TLBMISS;
|
|
1335 |
exception = POWERPC_EXCP_DSTLB;
|
|
1333 | 1336 |
error_code = 1 << 16; |
1334 | 1337 |
} else { |
1335 |
exception = EXCP_DL_TLBMISS;
|
|
1338 |
exception = POWERPC_EXCP_DLTLB;
|
|
1336 | 1339 |
error_code = 0; |
1337 | 1340 |
} |
1338 | 1341 |
env->spr[SPR_DMISS] = address; |
... | ... | |
1345 | 1348 |
goto out; |
1346 | 1349 |
case POWERPC_MMU_SOFT_4xx: |
1347 | 1350 |
case POWERPC_MMU_SOFT_4xx_Z: |
1348 |
exception = EXCP_40x_DTLBMISS;
|
|
1351 |
exception = POWERPC_EXCP_DTLB;
|
|
1349 | 1352 |
error_code = 0; |
1350 | 1353 |
env->spr[SPR_40x_DEAR] = address; |
1351 | 1354 |
if (rw) |
... | ... | |
1396 | 1399 |
switch (access_type) { |
1397 | 1400 |
case ACCESS_FLOAT: |
1398 | 1401 |
/* Floating point load/store */ |
1399 |
exception = EXCP_ALIGN; |
|
1400 |
error_code = EXCP_ALIGN_FP; |
|
1402 |
exception = POWERPC_EXCP_ALIGN;
|
|
1403 |
error_code = POWERPC_EXCP_ALIGN_FP;
|
|
1401 | 1404 |
break; |
1402 | 1405 |
case ACCESS_RES: |
1403 | 1406 |
/* lwarx, ldarx or srwcx. */ |
... | ... | |
1409 | 1412 |
break; |
1410 | 1413 |
default: |
1411 | 1414 |
printf("DSI: invalid exception (%d)\n", ret); |
1412 |
exception = EXCP_PROGRAM; |
|
1413 |
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
|
|
1415 |
exception = POWERPC_EXCP_PROGRAM;
|
|
1416 |
error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
|
|
1414 | 1417 |
break; |
1415 | 1418 |
} |
1416 | 1419 |
break; |
1420 |
#if defined(TARGET_PPC64) |
|
1417 | 1421 |
case -5: |
1418 | 1422 |
/* No match in segment table */ |
1419 |
exception = EXCP_DSEG; |
|
1423 |
exception = POWERPC_EXCP_DSEG;
|
|
1420 | 1424 |
error_code = 0; |
1421 | 1425 |
break; |
1426 |
#endif |
|
1422 | 1427 |
} |
1423 |
if (exception == EXCP_DSI && rw == 1) |
|
1428 |
if (exception == POWERPC_EXCP_DSI && rw == 1)
|
|
1424 | 1429 |
error_code |= 0x02000000; |
1425 | 1430 |
/* Store fault address */ |
1426 | 1431 |
env->spr[SPR_DAR] = address; |
... | ... | |
1830 | 1835 |
#if defined (CONFIG_USER_ONLY) |
1831 | 1836 |
void do_interrupt (CPUState *env) |
1832 | 1837 |
{ |
1833 |
env->exception_index = -1; |
|
1838 |
env->exception_index = POWERPC_EXCP_NONE; |
|
1839 |
env->error_code = 0; |
|
1834 | 1840 |
} |
1835 | 1841 |
|
1836 | 1842 |
void ppc_hw_interrupt (CPUState *env) |
1837 | 1843 |
{ |
1838 |
env->exception_index = -1; |
|
1844 |
env->exception_index = POWERPC_EXCP_NONE; |
|
1845 |
env->error_code = 0; |
|
1839 | 1846 |
} |
1840 | 1847 |
#else /* defined (CONFIG_USER_ONLY) */ |
1841 | 1848 |
static void dump_syscall (CPUState *env) |
... | ... | |
1846 | 1853 |
env->gpr[5], env->gpr[6], env->nip); |
1847 | 1854 |
} |
1848 | 1855 |
|
1849 |
void do_interrupt (CPUState *env) |
|
1856 |
/* Note that this function should be greatly optimized |
|
1857 |
* when called with a constant excp, from ppc_hw_interrupt |
|
1858 |
*/ |
|
1859 |
static always_inline void powerpc_excp (CPUState *env, |
|
1860 |
int excp_model, int excp) |
|
1850 | 1861 |
{ |
1851 |
target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1;
|
|
1852 |
int excp, idx;
|
|
1862 |
target_ulong msr, vector;
|
|
1863 |
int srr0, srr1, asrr0, asrr1;
|
|
1853 | 1864 |
|
1854 |
excp = env->exception_index; |
|
1855 |
msr = do_load_msr(env); |
|
1856 |
/* The default is to use SRR0 & SRR1 to save the exception context */ |
|
1857 |
srr_0 = &env->spr[SPR_SRR0]; |
|
1858 |
srr_1 = &env->spr[SPR_SRR1]; |
|
1859 |
asrr_0 = NULL; |
|
1860 |
asrr_1 = NULL; |
|
1861 |
#if defined (DEBUG_EXCEPTIONS) |
|
1862 |
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { |
|
1863 |
if (loglevel != 0) { |
|
1864 |
fprintf(logfile, |
|
1865 |
"Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", |
|
1866 |
env->nip, excp, env->error_code); |
|
1867 |
cpu_dump_state(env, logfile, fprintf, 0); |
|
1868 |
} |
|
1869 |
} |
|
1870 |
#endif |
|
1871 | 1865 |
if (loglevel & CPU_LOG_INT) { |
1872 | 1866 |
fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", |
1873 | 1867 |
env->nip, excp, env->error_code); |
1874 | 1868 |
} |
1875 |
msr_pow = 0; |
|
1876 |
idx = -1; |
|
1877 |
/* Generate informations in save/restore registers */ |
|
1869 |
msr = do_load_msr(env); |
|
1870 |
srr0 = SPR_SRR0; |
|
1871 |
srr1 = SPR_SRR1; |
|
1872 |
asrr0 = -1; |
|
1873 |
asrr1 = -1; |
|
1874 |
msr &= ~((target_ulong)0x783F0000); |
|
1878 | 1875 |
switch (excp) { |
1879 |
/* Generic PowerPC exceptions */ |
|
1880 |
case EXCP_RESET: /* 0x0100 */ |
|
1881 |
switch (env->excp_model) { |
|
1876 |
case POWERPC_EXCP_NONE: |
|
1877 |
/* Should never happen */ |
|
1878 |
return; |
|
1879 |
case POWERPC_EXCP_CRITICAL: /* Critical input */ |
|
1880 |
msr_ri = 0; /* XXX: check this */ |
|
1881 |
switch (excp_model) { |
|
1882 | 1882 |
case POWERPC_EXCP_40x: |
1883 |
srr_0 = &env->spr[SPR_40x_SRR2];
|
|
1884 |
srr_1 = &env->spr[SPR_40x_SRR3];
|
|
1883 |
srr0 = SPR_40x_SRR2;
|
|
1884 |
srr1 = SPR_40x_SRR3;
|
|
1885 | 1885 |
break; |
1886 | 1886 |
case POWERPC_EXCP_BOOKE: |
1887 |
idx = 0; |
|
1888 |
srr_0 = &env->spr[SPR_BOOKE_CSRR0]; |
|
1889 |
srr_1 = &env->spr[SPR_BOOKE_CSRR1]; |
|
1887 |
srr0 = SPR_BOOKE_CSRR0; |
|
1888 |
srr1 = SPR_BOOKE_CSRR1; |
|
1890 | 1889 |
break; |
1891 |
default: |
|
1892 |
if (msr_ip) |
|
1893 |
excp += 0xFFC00; |
|
1894 |
excp |= 0xFFC00000; |
|
1890 |
case POWERPC_EXCP_G2: |
|
1895 | 1891 |
break; |
1892 |
default: |
|
1893 |
goto excp_invalid; |
|
1896 | 1894 |
} |
1897 | 1895 |
goto store_next; |
1898 |
case EXCP_MACHINE_CHECK: /* 0x0200 */ |
|
1899 |
switch (env->excp_model) { |
|
1896 |
case POWERPC_EXCP_MCHECK: /* Machine check exception */ |
|
1897 |
if (msr_me == 0) { |
|
1898 |
/* Machine check exception is not enabled */ |
|
1899 |
/* XXX: we may just stop the processor here, to allow debugging */ |
|
1900 |
excp = POWERPC_EXCP_RESET; |
|
1901 |
goto excp_reset; |
|
1902 |
} |
|
1903 |
msr_ri = 0; |
|
1904 |
msr_me = 0; |
|
1905 |
#if defined(TARGET_PPC64H) |
|
1906 |
msr_hv = 1; |
|
1907 |
#endif |
|
1908 |
/* XXX: should also have something loaded in DAR / DSISR */ |
|
1909 |
switch (excp_model) { |
|
1900 | 1910 |
case POWERPC_EXCP_40x: |
1901 |
srr_0 = &env->spr[SPR_40x_SRR2];
|
|
1902 |
srr_1 = &env->spr[SPR_40x_SRR3];
|
|
1911 |
srr0 = SPR_40x_SRR2;
|
|
1912 |
srr1 = SPR_40x_SRR3;
|
|
1903 | 1913 |
break; |
1904 | 1914 |
case POWERPC_EXCP_BOOKE: |
1905 |
idx = 1; |
|
1906 |
srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; |
|
1907 |
srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; |
|
1908 |
asrr_0 = &env->spr[SPR_BOOKE_CSRR0]; |
|
1909 |
asrr_1 = &env->spr[SPR_BOOKE_CSRR1]; |
|
1910 |
msr_ce = 0; |
|
1915 |
srr0 = SPR_BOOKE_MCSRR0; |
|
1916 |
srr1 = SPR_BOOKE_MCSRR1; |
|
1917 |
asrr0 = SPR_BOOKE_CSRR0; |
|
1918 |
asrr1 = SPR_BOOKE_CSRR1; |
|
1911 | 1919 |
break; |
1912 | 1920 |
default: |
1913 | 1921 |
break; |
1914 | 1922 |
} |
1915 |
msr_me = 0; |
|
1916 |
break; |
|
1917 |
case EXCP_DSI: /* 0x0300 */ |
|
1918 |
/* Store exception cause */ |
|
1919 |
/* data location address has been stored |
|
1920 |
* when the fault has been detected |
|
1921 |
*/ |
|
1922 |
idx = 2; |
|
1923 |
msr &= ~0xFFFF0000; |
|
1923 |
goto store_next; |
|
1924 |
case POWERPC_EXCP_DSI: /* Data storage exception */ |
|
1924 | 1925 |
#if defined (DEBUG_EXCEPTIONS) |
1925 | 1926 |
if (loglevel != 0) { |
1926 | 1927 |
fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX |
1927 | 1928 |
"\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); |
1928 | 1929 |
} |
1929 | 1930 |
#endif |
1931 |
msr_ri = 0; |
|
1932 |
#if defined(TARGET_PPC64H) |
|
1933 |
if (lpes1 == 0) |
|
1934 |
msr_hv = 1; |
|
1935 |
#endif |
|
1930 | 1936 |
goto store_next; |
1931 |
case EXCP_ISI: /* 0x0400 */ |
|
1932 |
/* Store exception cause */ |
|
1933 |
idx = 3; |
|
1934 |
msr &= ~0xFFFF0000; |
|
1935 |
msr |= env->error_code; |
|
1937 |
case POWERPC_EXCP_ISI: /* Instruction storage exception */ |
|
1936 | 1938 |
#if defined (DEBUG_EXCEPTIONS) |
1937 | 1939 |
if (loglevel != 0) { |
1938 | 1940 |
fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX |
1939 | 1941 |
"\n", msr, env->nip); |
1940 | 1942 |
} |
1941 | 1943 |
#endif |
1944 |
msr_ri = 0; |
|
1945 |
#if defined(TARGET_PPC64H) |
|
1946 |
if (lpes1 == 0) |
|
1947 |
msr_hv = 1; |
|
1948 |
#endif |
|
1949 |
msr |= env->error_code; |
|
1942 | 1950 |
goto store_next; |
1943 |
case EXCP_EXTERNAL: /* 0x0500 */ |
|
1944 |
idx = 4; |
|
1951 |
case POWERPC_EXCP_EXTERNAL: /* External input */ |
|
1952 |
msr_ri = 0; |
|
1953 |
#if defined(TARGET_PPC64H) |
|
1954 |
if (lpes0 == 1) |
|
1955 |
msr_hv = 1; |
|
1956 |
#endif |
|
1945 | 1957 |
goto store_next; |
1946 |
case EXCP_ALIGN: /* 0x0600 */ |
|
1947 |
if (likely(env->excp_model != POWERPC_EXCP_601)) { |
|
1948 |
/* Store exception cause */ |
|
1949 |
idx = 5; |
|
1950 |
/* Get rS/rD and rA from faulting opcode */ |
|
1951 |
env->spr[SPR_DSISR] |= |
|
1952 |
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; |
|
1953 |
/* data location address has been stored |
|
1954 |
* when the fault has been detected |
|
1955 |
*/ |
|
1956 |
} else { |
|
1957 |
/* IO error exception on PowerPC 601 */ |
|
1958 |
/* XXX: TODO */ |
|
1959 |
cpu_abort(env, |
|
1960 |
"601 IO error exception is not implemented yet !\n"); |
|
1961 |
} |
|
1958 |
case POWERPC_EXCP_ALIGN: /* Alignment exception */ |
|
1959 |
msr_ri = 0; |
|
1960 |
#if defined(TARGET_PPC64H) |
|
1961 |
if (lpes1 == 0) |
|
1962 |
msr_hv = 1; |
|
1963 |
#endif |
|
1964 |
/* XXX: this is false */ |
|
1965 |
/* Get rS/rD and rA from faulting opcode */ |
|
1966 |
env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; |
|
1962 | 1967 |
goto store_current; |
1963 |
case EXCP_PROGRAM: /* 0x0700 */ |
|
1964 |
idx = 6; |
|
1965 |
msr &= ~0xFFFF0000; |
|
1968 |
case POWERPC_EXCP_PROGRAM: /* Program exception */ |
|
1966 | 1969 |
switch (env->error_code & ~0xF) { |
1967 |
case EXCP_FP: |
|
1968 |
if (msr_fe0 == 0 && msr_fe1 == 0) {
|
|
1970 |
case POWERPC_EXCP_FP:
|
|
1971 |
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
|
|
1969 | 1972 |
#if defined (DEBUG_EXCEPTIONS) |
1970 | 1973 |
if (loglevel != 0) { |
1971 | 1974 |
fprintf(logfile, "Ignore floating point exception\n"); |
... | ... | |
1973 | 1976 |
#endif |
1974 | 1977 |
return; |
1975 | 1978 |
} |
1979 |
msr_ri = 0; |
|
1980 |
#if defined(TARGET_PPC64H) |
|
1981 |
if (lpes1 == 0) |
|
1982 |
msr_hv = 1; |
|
1983 |
#endif |
|
1976 | 1984 |
msr |= 0x00100000; |
1977 | 1985 |
/* Set FX */ |
1978 | 1986 |
env->fpscr[7] |= 0x8; |
... | ... | |
1980 | 1988 |
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & |
1981 | 1989 |
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) |
1982 | 1990 |
env->fpscr[7] |= 0x4; |
1991 |
if (msr_fe0 != msr_fe1) { |
|
1992 |
msr |= 0x00010000; |
|
1993 |
goto store_current; |
|
1994 |
} |
|
1983 | 1995 |
break; |
1984 |
case EXCP_INVAL: |
|
1996 |
case POWERPC_EXCP_INVAL:
|
|
1985 | 1997 |
#if defined (DEBUG_EXCEPTIONS) |
1986 | 1998 |
if (loglevel != 0) { |
1987 | 1999 |
fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n", |
1988 | 2000 |
env->nip); |
1989 | 2001 |
} |
1990 | 2002 |
#endif |
2003 |
msr_ri = 0; |
|
2004 |
#if defined(TARGET_PPC64H) |
|
2005 |
if (lpes1 == 0) |
|
2006 |
msr_hv = 1; |
|
2007 |
#endif |
|
1991 | 2008 |
msr |= 0x00080000; |
1992 | 2009 |
break; |
1993 |
case EXCP_PRIV: |
|
2010 |
case POWERPC_EXCP_PRIV: |
|
2011 |
msr_ri = 0; |
|
2012 |
#if defined(TARGET_PPC64H) |
|
2013 |
if (lpes1 == 0) |
|
2014 |
msr_hv = 1; |
|
2015 |
#endif |
|
1994 | 2016 |
msr |= 0x00040000; |
1995 | 2017 |
break; |
1996 |
case EXCP_TRAP: |
|
1997 |
idx = 15; |
|
2018 |
case POWERPC_EXCP_TRAP: |
|
2019 |
msr_ri = 0; |
|
2020 |
#if defined(TARGET_PPC64H) |
|
2021 |
if (lpes1 == 0) |
|
2022 |
msr_hv = 1; |
|
2023 |
#endif |
|
1998 | 2024 |
msr |= 0x00020000; |
1999 | 2025 |
break; |
2000 | 2026 |
default: |
2001 | 2027 |
/* Should never occur */ |
2028 |
cpu_abort(env, "Invalid program exception %d. Aborting\n", |
|
2029 |
env->error_code); |
|
2002 | 2030 |
break; |
2003 | 2031 |
} |
2004 |
msr |= 0x00010000; |
|
2005 |
goto store_current; |
|
2006 |
case EXCP_NO_FP: /* 0x0800 */ |
|
2007 |
idx = 7; |
|
2008 |
msr &= ~0xFFFF0000; |
|
2009 |
goto store_current; |
|
2010 |
case EXCP_DECR: |
|
2011 | 2032 |
goto store_next; |
2012 |
case EXCP_SYSCALL: /* 0x0C00 */ |
|
2013 |
idx = 8; |
|
2033 |
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ |
|
2034 |
msr_ri = 0; |
|
2035 |
#if defined(TARGET_PPC64H) |
|
2036 |
if (lpes1 == 0) |
|
2037 |
msr_hv = 1; |
|
2038 |
#endif |
|
2039 |
goto store_current; |
|
2040 |
case POWERPC_EXCP_SYSCALL: /* System call exception */ |
|
2014 | 2041 |
/* NOTE: this is a temporary hack to support graphics OSI |
2015 | 2042 |
calls from the MOL driver */ |
2043 |
/* XXX: To be removed */ |
|
2016 | 2044 |
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && |
2017 | 2045 |
env->osi_call) { |
2018 | 2046 |
if (env->osi_call(env) != 0) |
... | ... | |
2021 | 2049 |
if (loglevel & CPU_LOG_INT) { |
2022 | 2050 |
dump_syscall(env); |
2023 | 2051 |
} |
2052 |
msr_ri = 0; |
|
2053 |
#if defined(TARGET_PPC64H) |
|
2054 |
if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) |
|
2055 |
msr_hv = 1; |
|
2056 |
#endif |
|
2057 |
goto store_next; |
|
2058 |
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ |
|
2059 |
msr_ri = 0; |
|
2060 |
goto store_current; |
|
2061 |
case POWERPC_EXCP_DECR: /* Decrementer exception */ |
|
2062 |
msr_ri = 0; |
|
2063 |
#if defined(TARGET_PPC64H) |
|
2064 |
if (lpes1 == 0) |
|
2065 |
msr_hv = 1; |
|
2066 |
#endif |
|
2067 |
goto store_next; |
|
2068 |
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ |
|
2069 |
/* FIT on 4xx */ |
|
2070 |
#if defined (DEBUG_EXCEPTIONS) |
|
2071 |
if (loglevel != 0) |
|
2072 |
fprintf(logfile, "FIT exception\n"); |
|
2073 |
#endif |
|
2074 |
msr_ri = 0; /* XXX: check this */ |
|
2024 | 2075 |
goto store_next; |
2025 |
case EXCP_TRACE: /* 0x0D00 */ |
|
2076 |
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ |
|
2077 |
#if defined (DEBUG_EXCEPTIONS) |
|
2078 |
if (loglevel != 0) |
|
2079 |
fprintf(logfile, "WDT exception\n"); |
|
2080 |
#endif |
|
2081 |
switch (excp_model) { |
|
2082 |
case POWERPC_EXCP_BOOKE: |
|
2083 |
srr0 = SPR_BOOKE_CSRR0; |
|
2084 |
srr1 = SPR_BOOKE_CSRR1; |
|
2085 |
break; |
|
2086 |
default: |
|
2087 |
break; |
|
2088 |
} |
|
2089 |
msr_ri = 0; /* XXX: check this */ |
|
2026 | 2090 |
goto store_next; |
2027 |
case EXCP_PERF: /* 0x0F00 */ |
|
2091 |
case POWERPC_EXCP_DTLB: /* Data TLB error */ |
|
2092 |
msr_ri = 0; /* XXX: check this */ |
|
2093 |
goto store_next; |
|
2094 |
case POWERPC_EXCP_ITLB: /* Instruction TLB error */ |
|
2095 |
msr_ri = 0; /* XXX: check this */ |
|
2096 |
goto store_next; |
|
2097 |
case POWERPC_EXCP_DEBUG: /* Debug interrupt */ |
|
2098 |
switch (excp_model) { |
|
2099 |
case POWERPC_EXCP_BOOKE: |
|
2100 |
srr0 = SPR_BOOKE_DSRR0; |
|
2101 |
srr1 = SPR_BOOKE_DSRR1; |
|
2102 |
asrr0 = SPR_BOOKE_CSRR0; |
|
2103 |
asrr1 = SPR_BOOKE_CSRR1; |
|
2104 |
break; |
|
2105 |
default: |
|
2106 |
break; |
|
2107 |
} |
|
2028 | 2108 |
/* XXX: TODO */ |
2029 |
cpu_abort(env, |
|
2030 |
"Performance counter exception is not implemented yet !\n"); |
|
2109 |
cpu_abort(env, "Debug exception is not implemented yet !\n"); |
|
2031 | 2110 |
goto store_next; |
2032 |
/* 32 bits PowerPC specific exceptions */ |
|
2033 |
case EXCP_FP_ASSIST: /* 0x0E00 */ |
|
2111 |
#if defined(TARGET_PPCEMB) |
|
2112 |
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ |
|
2113 |
msr_ri = 0; /* XXX: check this */ |
|
2114 |
goto store_current; |
|
2115 |
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ |
|
2034 | 2116 |
/* XXX: TODO */ |
2035 |
cpu_abort(env, "Floating point assist exception "
|
|
2117 |
cpu_abort(env, "Embedded floating point data exception "
|
|
2036 | 2118 |
"is not implemented yet !\n"); |
2037 | 2119 |
goto store_next; |
2038 |
/* 64 bits PowerPC exceptions */ |
|
2039 |
case EXCP_DSEG: /* 0x0380 */ |
|
2120 |
case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ |
|
2040 | 2121 |
/* XXX: TODO */ |
2041 |
cpu_abort(env, "Data segment exception is not implemented yet !\n"); |
|
2122 |
cpu_abort(env, "Embedded floating point round exception " |
|
2123 |
"is not implemented yet !\n"); |
|
2042 | 2124 |
goto store_next; |
2043 |
case EXCP_ISEG: /* 0x0480 */ |
|
2125 |
case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ |
|
2126 |
msr_ri = 0; |
|
2044 | 2127 |
/* XXX: TODO */ |
2045 | 2128 |
cpu_abort(env, |
2046 |
"Instruction segment exception is not implemented yet !\n");
|
|
2129 |
"Performance counter exception is not implemented yet !\n");
|
|
2047 | 2130 |
goto store_next; |
2048 |
case EXCP_HDECR: /* 0x0980 */
|
|
2131 |
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
|
|
2049 | 2132 |
/* XXX: TODO */ |
2050 |
cpu_abort(env, "Hypervisor decrementer exception is not implemented "
|
|
2051 |
"yet !\n"); |
|
2133 |
cpu_abort(env, |
|
2134 |
"Embedded doorbell interrupt is not implemented yet !\n");
|
|
2052 | 2135 |
goto store_next; |
2053 |
/* Implementation specific exceptions */ |
|
2054 |
case 0x0A00: |
|
2055 |
switch (env->excp_model) { |
|
2056 |
case POWERPC_EXCP_G2: |
|
2057 |
/* Critical interrupt on G2 */ |
|
2058 |
/* XXX: TODO */ |
|
2059 |
cpu_abort(env, "G2 critical interrupt is not implemented yet !\n"); |
|
2060 |
goto store_next; |
|
2061 |
default: |
|
2062 |
cpu_abort(env, "Invalid exception 0x0A00 !\n"); |
|
2136 |
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ |
|
2137 |
switch (excp_model) { |
|
2138 |
case POWERPC_EXCP_BOOKE: |
|
2139 |
srr0 = SPR_BOOKE_CSRR0; |
|
2140 |
srr1 = SPR_BOOKE_CSRR1; |
|
2063 | 2141 |
break; |
2064 |
} |
|
2065 |
return; |
|
2066 |
case 0x0F20: |
|
2067 |
idx = 9; |
|
2068 |
switch (env->excp_model) { |
|
2069 |
case POWERPC_EXCP_40x: |
|
2070 |
/* APU unavailable on 405 */ |
|
2071 |
/* XXX: TODO */ |
|
2072 |
cpu_abort(env, |
|
2073 |
"APU unavailable exception is not implemented yet !\n"); |
|
2074 |
goto store_next; |
|
2075 |
case POWERPC_EXCP_74xx: |
|
2076 |
/* Altivec unavailable */ |
|
2077 |
/* XXX: TODO */ |
|
2078 |
cpu_abort(env, "Altivec unavailable exception " |
|
2079 |
"is not implemented yet !\n"); |
|
2080 |
goto store_next; |
|
2081 | 2142 |
default: |
2082 |
cpu_abort(env, "Invalid exception 0x0F20 !\n"); |
|
2083 | 2143 |
break; |
2084 | 2144 |
} |
2085 |
return; |
|
2086 |
case 0x1000: |
|
2087 |
idx = 10; |
|
2088 |
switch (env->excp_model) { |
|
2089 |
case POWERPC_EXCP_40x: |
|
2090 |
/* PIT on 4xx */ |
|
2091 |
msr &= ~0xFFFF0000; |
|
2145 |
/* XXX: TODO */ |
|
2146 |
cpu_abort(env, "Embedded doorbell critical interrupt " |
|
2147 |
"is not implemented yet !\n"); |
|
2148 |
goto store_next; |
|
2149 |
#endif /* defined(TARGET_PPCEMB) */ |
|
2150 |
case POWERPC_EXCP_RESET: /* System reset exception */ |
|
2151 |
msr_ri = 0; |
|
2152 |
#if defined(TARGET_PPC64H) |
|
2153 |
msr_hv = 1; |
|
2154 |
#endif |
|
2155 |
excp_reset: |
|
2156 |
goto store_next; |
|
2157 |
#if defined(TARGET_PPC64) |
|
2158 |
case POWERPC_EXCP_DSEG: /* Data segment exception */ |
|
2159 |
msr_ri = 0; |
|
2160 |
#if defined(TARGET_PPC64H) |
|
2161 |
if (lpes1 == 0) |
|
2162 |
msr_hv = 1; |
|
2163 |
#endif |
|
2164 |
/* XXX: TODO */ |
|
2165 |
cpu_abort(env, "Data segment exception is not implemented yet !\n"); |
|
2166 |
goto store_next; |
|
2167 |
case POWERPC_EXCP_ISEG: /* Instruction segment exception */ |
|
2168 |
msr_ri = 0; |
|
2169 |
#if defined(TARGET_PPC64H) |
|
2170 |
if (lpes1 == 0) |
|
2171 |
msr_hv = 1; |
|
2172 |
#endif |
|
2173 |
/* XXX: TODO */ |
|
2174 |
cpu_abort(env, |
|
2175 |
"Instruction segment exception is not implemented yet !\n"); |
|
2176 |
goto store_next; |
|
2177 |
#endif /* defined(TARGET_PPC64) */ |
|
2178 |
#if defined(TARGET_PPC64H) |
|
2179 |
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ |
|
2180 |
srr0 = SPR_HSRR0; |
|
2181 |
srr1 = SPR_HSSR1; |
|
2182 |
msr_hv = 1; |
|
2183 |
goto store_next; |
|
2184 |
#endif |
|
2185 |
case POWERPC_EXCP_TRACE: /* Trace exception */ |
|
2186 |
msr_ri = 0; |
|
2187 |
#if defined(TARGET_PPC64H) |
|
2188 |
if (lpes1 == 0) |
|
2189 |
msr_hv = 1; |
|
2190 |
#endif |
|
2191 |
goto store_next; |
|
2192 |
#if defined(TARGET_PPC64H) |
|
2193 |
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ |
|
2194 |
srr0 = SPR_HSRR0; |
|
2195 |
srr1 = SPR_HSSR1; |
|
2196 |
msr_hv = 1; |
|
2197 |
goto store_next; |
|
2198 |
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ |
|
2199 |
srr0 = SPR_HSRR0; |
|
2200 |
srr1 = SPR_HSSR1; |
|
2201 |
msr_hv = 1; |
|
2202 |
/* XXX: TODO */ |
|
2203 |
cpu_abort(env, "Hypervisor instruction storage exception " |
|
2204 |
"is not implemented yet !\n"); |
|
2205 |
goto store_next; |
|
2206 |
case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ |
|
2207 |
srr0 = SPR_HSRR0; |
|
2208 |
srr1 = SPR_HSSR1; |
|
2209 |
msr_hv = 1; |
|
2210 |
goto store_next; |
|
2211 |
case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ |
|
2212 |
srr0 = SPR_HSRR0; |
|
2213 |
srr1 = SPR_HSSR1; |
|
2214 |
msr_hv = 1; |
|
2215 |
goto store_next; |
|
2216 |
#endif /* defined(TARGET_PPC64H) */ |
|
2217 |
case POWERPC_EXCP_VPU: /* Vector unavailable exception */ |
|
2218 |
msr_ri = 0; |
|
2219 |
#if defined(TARGET_PPC64H) |
|
2220 |
if (lpes1 == 0) |
|
2221 |
msr_hv = 1; |
|
2222 |
#endif |
|
2223 |
goto store_current; |
|
2224 |
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ |
|
2092 | 2225 |
#if defined (DEBUG_EXCEPTIONS) |
2093 |
if (loglevel != 0) |
|
2094 |
fprintf(logfile, "PIT exception\n"); |
|
2226 |
if (loglevel != 0) |
|
2227 |
fprintf(logfile, "PIT exception\n"); |
|
2228 |
#endif |
|
2229 |
msr_ri = 0; /* XXX: check this */ |
|
2230 |
goto store_next; |
|
2231 |
case POWERPC_EXCP_IO: /* IO error exception */ |
|
2232 |
/* XXX: TODO */ |
|
2233 |
cpu_abort(env, "601 IO error exception is not implemented yet !\n"); |
|
2234 |
goto store_next; |
|
2235 |
case POWERPC_EXCP_RUNM: /* Run mode exception */ |
|
2236 |
/* XXX: TODO */ |
|
2237 |
cpu_abort(env, "601 run mode exception is not implemented yet !\n"); |
|
2238 |
goto store_next; |
|
2239 |
case POWERPC_EXCP_EMUL: /* Emulation trap exception */ |
|
2240 |
/* XXX: TODO */ |
|
2241 |
cpu_abort(env, "602 emulation trap exception " |
|
2242 |
"is not implemented yet !\n"); |
|
2243 |
goto store_next; |
|
2244 |
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ |
|
2245 |
msr_ri = 0; /* XXX: check this */ |
|
2246 |
#if defined(TARGET_PPC64H) /* XXX: check this */ |
|
2247 |
if (lpes1 == 0) |
|
2248 |
msr_hv = 1; |
|
2095 | 2249 |
#endif |
2096 |
goto store_next;
|
|
2250 |
switch (excp_model) {
|
|
2097 | 2251 |
case POWERPC_EXCP_602: |
2098 | 2252 |
case POWERPC_EXCP_603: |
2099 | 2253 |
case POWERPC_EXCP_603E: |
2100 | 2254 |
case POWERPC_EXCP_G2: |
2101 |
/* ITLBMISS on 602/603 */ |
|
2102 |
goto store_gprs; |
|
2255 |
goto tlb_miss_tgpr; |
|
2103 | 2256 |
case POWERPC_EXCP_7x5: |
2104 |
/* ITLBMISS on 745/755 */ |
|
2105 | 2257 |
goto tlb_miss; |
2106 | 2258 |
default: |
2107 |
cpu_abort(env, "Invalid exception 0x1000 !\n"); |
|
2108 |
break; |
|
2109 |
} |
|
2110 |
return; |
|
2111 |
case 0x1010: |
|
2112 |
idx = 11; |
|
2113 |
switch (env->excp_model) { |
|
2114 |
case POWERPC_EXCP_40x: |
|
2115 |
/* FIT on 4xx */ |
|
2116 |
msr &= ~0xFFFF0000; |
|
2117 |
#if defined (DEBUG_EXCEPTIONS) |
|
2118 |
if (loglevel != 0) |
|
2119 |
fprintf(logfile, "FIT exception\n"); |
|
2120 |
#endif |
|
2121 |
goto store_next; |
|
2122 |
default: |
|
2123 |
cpu_abort(env, "Invalid exception 0x1010 !\n"); |
|
2259 |
cpu_abort(env, "Invalid instruction TLB miss exception\n"); |
|
2124 | 2260 |
break; |
2125 | 2261 |
} |
2126 |
return; |
|
2127 |
case 0x1020: |
|
2128 |
idx = 12; |
|
2129 |
switch (env->excp_model) { |
|
2130 |
case POWERPC_EXCP_40x: |
|
2131 |
/* Watchdog on 4xx */ |
|
2132 |
msr &= ~0xFFFF0000; |
|
2133 |
#if defined (DEBUG_EXCEPTIONS) |
|
2134 |
if (loglevel != 0) |
|
2135 |
fprintf(logfile, "WDT exception\n"); |
|
2262 |
break; |
|
2263 |
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ |
|
2264 |
msr_ri = 0; /* XXX: check this */ |
|
2265 |
#if defined(TARGET_PPC64H) /* XXX: check this */ |
|
2266 |
if (lpes1 == 0) |
|
2267 |
msr_hv = 1; |
|
2136 | 2268 |
#endif |
2137 |
goto store_next; |
|
2138 |
case POWERPC_EXCP_BOOKE: |
|
2139 |
srr_0 = &env->spr[SPR_BOOKE_CSRR0]; |
|
2140 |
srr_1 = &env->spr[SPR_BOOKE_CSRR1]; |
|
2141 |
break; |
|
2142 |
default: |
|
2143 |
cpu_abort(env, "Invalid exception 0x1020 !\n"); |
|
2144 |
break; |
|
2145 |
} |
|
2146 |
return; |
|
2147 |
case 0x1100: |
|
2148 |
idx = 13; |
|
2149 |
switch (env->excp_model) { |
|
2150 |
case POWERPC_EXCP_40x: |
|
2151 |
/* DTLBMISS on 4xx */ |
|
2152 |
msr &= ~0xFFFF0000; |
|
2153 |
goto store_next; |
|
2269 |
switch (excp_model) { |
|
2154 | 2270 |
case POWERPC_EXCP_602: |
2155 | 2271 |
case POWERPC_EXCP_603: |
2156 | 2272 |
case POWERPC_EXCP_603E: |
2157 | 2273 |
case POWERPC_EXCP_G2: |
2158 |
/* DLTLBMISS on 602/603 */ |
|
2159 |
goto store_gprs; |
|
2274 |
goto tlb_miss_tgpr; |
|
2160 | 2275 |
case POWERPC_EXCP_7x5: |
2161 |
/* DLTLBMISS on 745/755 */ |
|
2162 | 2276 |
goto tlb_miss; |
2163 | 2277 |
default: |
2164 |
cpu_abort(env, "Invalid exception 0x1100 !\n");
|
|
2278 |
cpu_abort(env, "Invalid data load TLB miss exception\n");
|
|
2165 | 2279 |
break; |
2166 | 2280 |
} |
2167 |
return;
|
|
2168 |
case 0x1200:
|
|
2169 |
idx = 14;
|
|
2170 |
switch (env->excp_model) {
|
|
2171 |
case POWERPC_EXCP_40x:
|
|
2172 |
/* ITLBMISS on 4xx */
|
|
2173 |
msr &= ~0xFFFF0000;
|
|
2174 |
goto store_next;
|
|
2281 |
break;
|
|
2282 |
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
|
|
2283 |
msr_ri = 0; /* XXX: check this */
|
|
2284 |
#if defined(TARGET_PPC64H) /* XXX: check this */
|
|
2285 |
if (lpes1 == 0)
|
|
2286 |
msr_hv = 1;
|
|
2287 |
#endif
|
|
2288 |
switch (excp_model) {
|
|
2175 | 2289 |
case POWERPC_EXCP_602: |
2176 | 2290 |
case POWERPC_EXCP_603: |
2177 | 2291 |
case POWERPC_EXCP_603E: |
2178 | 2292 |
case POWERPC_EXCP_G2: |
2179 |
/* DSTLBMISS on 602/603 */ |
|
2180 |
store_gprs: |
|
2293 |
tlb_miss_tgpr: |
|
2181 | 2294 |
/* Swap temporary saved registers with GPRs */ |
2182 | 2295 |
swap_gpr_tgpr(env); |
2183 | 2296 |
msr_tgpr = 1; |
2297 |
goto tlb_miss; |
|
2298 |
case POWERPC_EXCP_7x5: |
|
2299 |
tlb_miss: |
|
2184 | 2300 |
#if defined (DEBUG_SOFTWARE_TLB) |
2185 | 2301 |
if (loglevel != 0) { |
2186 | 2302 |
const unsigned char *es; |
... | ... | |
2207 | 2323 |
env->error_code); |
2208 | 2324 |
} |
2209 | 2325 |
#endif |
2210 |
goto tlb_miss; |
|
2211 |
case POWERPC_EXCP_7x5: |
|
2212 |
/* DSTLBMISS on 745/755 */ |
|
2213 |
tlb_miss: |
|
2214 |
msr &= ~0xF83F0000; |
|
2215 | 2326 |
msr |= env->crf[0] << 28; |
2216 | 2327 |
msr |= env->error_code; /* key, D/I, S/L bits */ |
2217 | 2328 |
/* Set way using a LRU mechanism */ |
2218 | 2329 |
msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; |
2219 |
goto store_next; |
|
2220 |
default: |
|
2221 |
cpu_abort(env, "Invalid exception 0x1200 !\n"); |
|
2222 |
break; |
|
2223 |
} |
|
2224 |
return; |
|
2225 |
case 0x1300: |
|
2226 |
switch (env->excp_model) { |
|
2227 |
case POWERPC_EXCP_601: |
|
2228 |
case POWERPC_EXCP_602: |
|
2229 |
case POWERPC_EXCP_603: |
|
2230 |
case POWERPC_EXCP_603E: |
|
2231 |
case POWERPC_EXCP_G2: |
|
2232 |
case POWERPC_EXCP_604: |
|
2233 |
case POWERPC_EXCP_7x0: |
|
2234 |
case POWERPC_EXCP_7x5: |
|
2235 |
/* IABR on 6xx/7xx */ |
|
2236 |
/* XXX: TODO */ |
|
2237 |
cpu_abort(env, "IABR exception is not implemented yet !\n"); |
|
2238 |
goto store_next; |
|
2239 |
default: |
|
2240 |
cpu_abort(env, "Invalid exception 0x1300 !\n"); |
|
2241 |
break; |
|
2242 |
} |
|
2243 |
return; |
|
2244 |
case 0x1400: |
|
2245 |
switch (env->excp_model) { |
|
2246 |
case POWERPC_EXCP_601: |
|
2247 |
case POWERPC_EXCP_602: |
|
2248 |
case POWERPC_EXCP_603: |
|
2249 |
case POWERPC_EXCP_603E: |
|
2250 |
case POWERPC_EXCP_G2: |
|
2251 |
case POWERPC_EXCP_604: |
|
2252 |
case POWERPC_EXCP_7x0: |
|
2253 |
case POWERPC_EXCP_7x5: |
|
2254 |
/* SMI on 6xx/7xx */ |
|
2255 |
/* XXX: TODO */ |
|
2256 |
cpu_abort(env, "SMI exception is not implemented yet !\n"); |
|
2257 |
goto store_next; |
|
2258 |
default: |
|
2259 |
cpu_abort(env, "Invalid exception 0x1400 !\n"); |
|
2260 |
break; |
|
2261 |
} |
|
2262 |
return; |
|
2263 |
case 0x1500: |
|
2264 |
switch (env->excp_model) { |
|
2265 |
case POWERPC_EXCP_602: |
|
2266 |
/* Watchdog on 602 */ |
|
2267 |
/* XXX: TODO */ |
|
2268 |
cpu_abort(env, |
|
2269 |
"602 watchdog exception is not implemented yet !\n"); |
|
2270 |
goto store_next; |
|
2271 |
case POWERPC_EXCP_970: |
|
2272 |
/* Soft patch exception on 970 */ |
|
2273 |
/* XXX: TODO */ |
|
2274 |
cpu_abort(env, |
|
2275 |
"970 soft-patch exception is not implemented yet !\n"); |
|
2276 |
goto store_next; |
|
2277 |
case POWERPC_EXCP_74xx: |
|
2278 |
/* VPU assist on 74xx */ |
|
2279 |
/* XXX: TODO */ |
|
2280 |
cpu_abort(env, "VPU assist exception is not implemented yet !\n"); |
|
2281 |
goto store_next; |
|
2282 |
default: |
|
2283 |
cpu_abort(env, "Invalid exception 0x1500 !\n"); |
|
2284 |
break; |
|
2285 |
} |
|
2286 |
return; |
|
2287 |
case 0x1600: |
|
2288 |
switch (env->excp_model) { |
|
2289 |
case POWERPC_EXCP_602: |
|
2290 |
/* Emulation trap on 602 */ |
|
2291 |
/* XXX: TODO */ |
|
2292 |
cpu_abort(env, "602 emulation trap exception " |
|
2293 |
"is not implemented yet !\n"); |
|
2294 |
goto store_next; |
|
2295 |
case POWERPC_EXCP_970: |
|
2296 |
/* Maintenance exception on 970 */ |
|
2297 |
/* XXX: TODO */ |
|
2298 |
cpu_abort(env, |
|
2299 |
"970 maintenance exception is not implemented yet !\n"); |
|
2300 |
goto store_next; |
|
2301 |
default: |
|
2302 |
cpu_abort(env, "Invalid exception 0x1600 !\n"); |
|
2303 |
break; |
|
2304 |
} |
|
2305 |
return; |
|
2306 |
case 0x1700: |
|
2307 |
switch (env->excp_model) { |
|
2308 |
case POWERPC_EXCP_7x0: |
|
2309 |
case POWERPC_EXCP_7x5: |
|
2310 |
/* Thermal management interrupt on G3 */ |
|
2311 |
/* XXX: TODO */ |
|
2312 |
cpu_abort(env, "G3 thermal management exception " |
|
2313 |
"is not implemented yet !\n"); |
|
2314 |
goto store_next; |
|
2315 |
case POWERPC_EXCP_970: |
|
2316 |
/* VPU assist on 970 */ |
|
2317 |
/* XXX: TODO */ |
|
2318 |
cpu_abort(env, |
|
2319 |
"970 VPU assist exception is not implemented yet !\n"); |
|
2320 |
goto store_next; |
|
2321 |
default: |
|
2322 |
cpu_abort(env, "Invalid exception 0x1700 !\n"); |
|
2323 |
break; |
|
2324 |
} |
|
2325 |
return; |
|
2326 |
case 0x1800: |
|
2327 |
switch (env->excp_model) { |
|
2328 |
case POWERPC_EXCP_970: |
|
2329 |
/* Thermal exception on 970 */ |
|
2330 |
/* XXX: TODO */ |
|
2331 |
cpu_abort(env, "970 thermal management exception " |
|
2332 |
"is not implemented yet !\n"); |
|
2333 |
goto store_next; |
|
2334 |
default: |
|
2335 |
cpu_abort(env, "Invalid exception 0x1800 !\n"); |
|
2336 |
break; |
|
2337 |
} |
|
2338 |
return; |
|
2339 |
case 0x2000: |
|
2340 |
switch (env->excp_model) { |
|
2341 |
case POWERPC_EXCP_40x: |
|
2342 |
/* DEBUG on 4xx */ |
|
2343 |
/* XXX: TODO */ |
|
2344 |
cpu_abort(env, "40x debug exception is not implemented yet !\n"); |
|
2345 |
goto store_next; |
|
2346 |
case POWERPC_EXCP_601: |
|
2347 |
/* Run mode exception on 601 */ |
|
2348 |
/* XXX: TODO */ |
|
2349 |
cpu_abort(env, |
|
2350 |
"601 run mode exception is not implemented yet !\n"); |
|
2351 |
goto store_next; |
|
2352 |
case POWERPC_EXCP_BOOKE: |
|
2353 |
srr_0 = &env->spr[SPR_BOOKE_CSRR0]; |
|
2354 |
srr_1 = &env->spr[SPR_BOOKE_CSRR1]; |
|
2355 | 2330 |
break; |
2356 | 2331 |
default: |
2357 |
cpu_abort(env, "Invalid exception 0x1800 !\n");
|
|
2332 |
cpu_abort(env, "Invalid data store TLB miss exception\n");
|
|
2358 | 2333 |
break; |
2359 | 2334 |
} |
2360 |
return; |
|
2361 |
/* Other exceptions */ |
|
2362 |
/* Qemu internal exceptions: |
|
2363 |
* we should never come here with those values: abort execution |
|
2364 |
*/ |
|
2335 |
goto store_next; |
|
2336 |
case POWERPC_EXCP_FPA: /* Floating-point assist exception */ |
|
2337 |
/* XXX: TODO */ |
|
2338 |
cpu_abort(env, "Floating point assist exception " |
|
2339 |
"is not implemented yet !\n"); |
|
2340 |
goto store_next; |
|
2341 |
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ |
|
2342 |
/* XXX: TODO */ |
|
2343 |
cpu_abort(env, "IABR exception is not implemented yet !\n"); |
|
2344 |
goto store_next; |
|
2345 |
case POWERPC_EXCP_SMI: /* System management interrupt */ |
|
2346 |
/* XXX: TODO */ |
|
2347 |
cpu_abort(env, "SMI exception is not implemented yet !\n"); |
|
2348 |
goto store_next; |
|
2349 |
case POWERPC_EXCP_THERM: /* Thermal interrupt */ |
|
2350 |
/* XXX: TODO */ |
|
2351 |
cpu_abort(env, "Thermal management exception " |
|
2352 |
"is not implemented yet !\n"); |
|
2353 |
goto store_next; |
|
2354 |
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ |
|
2355 |
msr_ri = 0; |
|
2356 |
#if defined(TARGET_PPC64H) |
|
2357 |
if (lpes1 == 0) |
|
2358 |
msr_hv = 1; |
|
2359 |
#endif |
|
2360 |
/* XXX: TODO */ |
|
2361 |
cpu_abort(env, |
|
2362 |
"Performance counter exception is not implemented yet !\n"); |
|
2363 |
goto store_next; |
|
2364 |
case POWERPC_EXCP_VPUA: /* Vector assist exception */ |
|
2365 |
/* XXX: TODO */ |
|
2366 |
cpu_abort(env, "VPU assist exception is not implemented yet !\n"); |
|
2367 |
goto store_next; |
|
2368 |
case POWERPC_EXCP_SOFTP: /* Soft patch exception */ |
|
2369 |
/* XXX: TODO */ |
|
2370 |
cpu_abort(env, |
|
2371 |
"970 soft-patch exception is not implemented yet !\n"); |
|
2372 |
goto store_next; |
|
2373 |
case POWERPC_EXCP_MAINT: /* Maintenance exception */ |
|
2374 |
/* XXX: TODO */ |
|
2375 |
cpu_abort(env, |
|
2376 |
"970 maintenance exception is not implemented yet !\n"); |
|
2377 |
goto store_next; |
|
2365 | 2378 |
default: |
2366 |
cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp); |
|
2367 |
return; |
|
2379 |
excp_invalid: |
|
2380 |
cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp); |
|
2381 |
break; |
|
2368 | 2382 |
store_current: |
2369 | 2383 |
/* save current instruction location */ |
2370 |
*srr_0 = env->nip - 4;
|
|
2384 |
env->spr[srr0] = env->nip - 4;
|
|
2371 | 2385 |
break; |
2372 | 2386 |
store_next: |
2373 | 2387 |
/* save next instruction location */ |
2374 |
*srr_0 = env->nip;
|
|
2388 |
env->spr[srr0] = env->nip;
|
|
2375 | 2389 |
break; |
2376 | 2390 |
} |
2377 |
/* Save msr */ |
|
2378 |
*srr_1 = msr; |
|
2379 |
if (asrr_0 != NULL) |
|
2380 |
*asrr_0 = *srr_0; |
|
2381 |
if (asrr_1 != NULL) |
|
2382 |
*asrr_1 = *srr_1; |
|
2391 |
/* Save MSR */ |
|
2392 |
env->spr[srr1] = msr; |
|
2393 |
/* If any alternate SRR register are defined, duplicate saved values */ |
|
2394 |
if (asrr0 != -1) |
|
2395 |
env->spr[asrr0] = env->spr[srr0]; |
|
2396 |
if (asrr1 != -1) |
|
2397 |
env->spr[asrr1] = env->spr[srr1]; |
|
2383 | 2398 |
/* If we disactivated any translation, flush TLBs */ |
2384 |
if (msr_ir || msr_dr) {
|
|
2399 |
if (msr_ir || msr_dr) |
|
2385 | 2400 |
tlb_flush(env, 1); |
2386 |
} |
|
2387 | 2401 |
/* reload MSR with correct bits */ |
2388 | 2402 |
msr_ee = 0; |
2389 | 2403 |
msr_pr = 0; |
... | ... | |
2394 | 2408 |
msr_fe1 = 0; |
2395 | 2409 |
msr_ir = 0; |
2396 | 2410 |
msr_dr = 0; |
2397 |
msr_ri = 0; |
|
2411 |
#if 0 /* Fix this: not on all targets */ |
|
2412 |
msr_pmm = 0; |
|
2413 |
#endif |
|
2398 | 2414 |
msr_le = msr_ile; |
2399 |
if (env->excp_model == POWERPC_EXCP_BOOKE) { |
|
2400 |
msr_cm = msr_icm; |
|
2401 |
if (idx == -1 || (idx >= 16 && idx < 32)) { |
|
2402 |
cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", |
|
2403 |
excp, excp, idx); |
|
2404 |
} |
|
2415 |
do_compute_hflags(env); |
|
2416 |
/* Jump to handler */ |
|
2417 |
vector = env->excp_vectors[excp]; |
|
2418 |
if (vector == (target_ulong)-1) { |
|
2419 |
cpu_abort(env, "Raised an exception without defined vector %d\n", |
|
2420 |
excp); |
|
2421 |
} |
|
2422 |
vector |= env->excp_prefix; |
|
2405 | 2423 |
#if defined(TARGET_PPC64) |
2406 |
if (msr_cm) |
|
2407 |
env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR]; |
|
2408 |
else |
|
2409 |
#endif |
|
2410 |
env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR]; |
|
2411 |
if (idx < 16) |
|
2412 |
env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx]; |
|
2413 |
else if (idx < 38) |
|
2414 |
env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32]; |
|
2424 |
if (excp_model == POWERPC_EXCP_BOOKE) { |
|
2425 |
msr_cm = msr_icm; |
|
2426 |
if (!msr_cm) |
|
2427 |
vector = (uint32_t)vector; |
|
2415 | 2428 |
} else { |
2416 | 2429 |
msr_sf = msr_isf; |
2417 |
env->nip = excp; |
|
2430 |
if (!msr_sf) |
|
2431 |
vector = (uint32_t)vector; |
|
2418 | 2432 |
} |
2419 |
do_compute_hflags(env); |
|
2420 |
/* Jump to handler */ |
|
2421 |
env->exception_index = EXCP_NONE; |
|
2433 |
#endif |
|
2434 |
env->nip = vector; |
|
2435 |
/* Reset exception state */ |
|
2436 |
env->exception_index = POWERPC_EXCP_NONE; |
|
2437 |
env->error_code = 0; |
|
2422 | 2438 |
} |
2423 | 2439 |
|
2424 |
void ppc_hw_interrupt (CPUPPCState *env)
|
|
2440 |
void do_interrupt (CPUState *env)
|
|
2425 | 2441 |
{ |
2426 |
int raised = 0; |
|
2442 |
powerpc_excp(env, env->excp_model, env->exception_index); |
|
2443 |
} |
|
2427 | 2444 |
|
2445 |
void ppc_hw_interrupt (CPUPPCState *env) |
|
2446 |
{ |
|
2428 | 2447 |
#if 1 |
2429 | 2448 |
if (loglevel & CPU_LOG_INT) { |
2430 | 2449 |
fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", |
... | ... | |
2432 | 2451 |
env->interrupt_request, msr_me, msr_ee); |
2433 | 2452 |
} |
2434 | 2453 |
#endif |
2435 |
/* Raise it */
|
|
2454 |
/* External reset */
|
|
2436 | 2455 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { |
2437 |
/* External reset / critical input */ |
|
2438 |
/* XXX: critical input should be handled another way. |
|
2439 |
* This code is not correct ! |
|
2440 |
*/ |
|
2441 |
env->exception_index = EXCP_RESET; |
|
2442 | 2456 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); |
2443 |
raised = 1; |
|
2444 |
} |
|
2445 |
if (raised == 0 && msr_me != 0) { |
|
2446 |
/* Machine check exception */ |
|
2447 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { |
|
2448 |
env->exception_index = EXCP_MACHINE_CHECK; |
|
2449 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); |
|
2450 |
raised = 1; |
|
2451 |
} |
|
2457 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET); |
|
2458 |
return; |
|
2459 |
} |
|
2460 |
/* Machine check exception */ |
|
2461 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { |
|
2462 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); |
|
2463 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK); |
|
2464 |
return; |
|
2452 | 2465 |
} |
2453 |
if (raised == 0 && msr_ee != 0) { |
|
2454 |
#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ |
|
2466 |
#if 0 /* TODO */ |
|
2467 |
/* External debug exception */ |
|
2468 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { |
|
2469 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); |
|
2470 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG); |
|
2471 |
return; |
|
2472 |
} |
|
2473 |
#endif |
|
2474 |
#if defined(TARGET_PPC64H) |
|
2475 |
if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) { |
|
2455 | 2476 |
/* Hypervisor decrementer exception */ |
2456 | 2477 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { |
2457 |
env->exception_index = EXCP_HDECR; |
|
2458 | 2478 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); |
2459 |
raised = 1; |
|
2460 |
} else |
|
2479 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR); |
|
2480 |
return; |
|
2481 |
} |
|
2482 |
} |
|
2483 |
#endif |
|
2484 |
if (msr_ce != 0) { |
|
2485 |
/* External critical interrupt */ |
|
2486 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { |
|
2487 |
/* Taking a critical external interrupt does not clear the external |
|
2488 |
* critical interrupt status |
|
2489 |
*/ |
|
2490 |
#if 0 |
|
2491 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); |
|
2461 | 2492 |
#endif |
2493 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL); |
|
2494 |
return; |
|
2495 |
} |
|
2496 |
} |
|
2497 |
if (msr_ee != 0) { |
|
2498 |
/* Watchdog timer on embedded PowerPC */ |
|
2499 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { |
|
2500 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); |
|
2501 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT); |
|
2502 |
return; |
|
2503 |
} |
|
2504 |
#if defined(TARGET_PPCEMB) |
|
2505 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { |
|
2506 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); |
|
2507 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI); |
|
2508 |
return; |
|
2509 |
} |
|
2510 |
#endif |
|
2511 |
#if defined(TARGET_PPCEMB) |
|
2512 |
/* External interrupt */ |
|
2513 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { |
|
2514 |
/* Taking an external interrupt does not clear the external |
|
2515 |
* interrupt status |
|
2516 |
*/ |
|
2517 |
#if 0 |
|
2518 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); |
|
2519 |
#endif |
|
2520 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); |
|
2521 |
return; |
|
2522 |
} |
|
2523 |
#endif |
|
2524 |
/* Fixed interval timer on embedded PowerPC */ |
|
2525 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { |
|
2526 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); |
|
2527 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT); |
|
2528 |
return; |
|
2529 |
} |
|
2530 |
/* Programmable interval timer on embedded PowerPC */ |
|
2531 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { |
|
2532 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); |
|
2533 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT); |
|
2534 |
return; |
|
2535 |
} |
|
2462 | 2536 |
/* Decrementer exception */ |
2463 | 2537 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { |
2464 |
env->exception_index = EXCP_DECR; |
|
2465 | 2538 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); |
2466 |
raised = 1; |
|
2467 |
/* Programmable interval timer on embedded PowerPC */ |
|
2468 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { |
|
2469 |
env->exception_index = EXCP_40x_PIT; |
|
2470 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); |
|
2471 |
raised = 1; |
|
2472 |
/* Fixed interval timer on embedded PowerPC */ |
|
2473 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { |
|
2474 |
env->exception_index = EXCP_40x_FIT; |
|
2475 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); |
|
2476 |
raised = 1; |
|
2477 |
/* Watchdog timer on embedded PowerPC */ |
|
2478 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { |
|
2479 |
env->exception_index = EXCP_40x_WATCHDOG; |
|
2480 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); |
|
2481 |
raised = 1; |
|
2539 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR); |
|
2540 |
return; |
|
2541 |
} |
|
2542 |
#if !defined(TARGET_PPCEMB) |
|
2482 | 2543 |
/* External interrupt */ |
2483 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { |
|
2484 |
env->exception_index = EXCP_EXTERNAL; |
|
2544 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { |
|
2485 | 2545 |
/* Taking an external interrupt does not clear the external |
2486 | 2546 |
* interrupt status |
2487 | 2547 |
*/ |
2488 | 2548 |
#if 0 |
2489 | 2549 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); |
2490 | 2550 |
#endif |
2491 |
raised = 1; |
|
2492 |
#if 0 // TODO |
|
2493 |
/* Thermal interrupt */ |
|
2494 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { |
|
2495 |
env->exception_index = EXCP_970_THRM; |
|
2496 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); |
|
2497 |
raised = 1; |
|
2551 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); |
|
2552 |
return; |
|
2553 |
} |
|
2498 | 2554 |
#endif |
2555 |
#if defined(TARGET_PPCEMB) |
|
2556 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { |
|
2557 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); |
|
2558 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI); |
|
2559 |
return; |
|
2499 | 2560 |
} |
2500 |
#if 0 // TODO |
|
2501 |
/* External debug exception */ |
|
2502 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { |
|
2503 |
env->exception_index = EXCP_xxx; |
|
2504 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); |
|
2505 |
raised = 1; |
|
2506 | 2561 |
#endif |
2507 |
} |
|
2508 |
if (raised != 0) { |
|
2509 |
env->error_code = 0; |
|
2510 |
do_interrupt(env); |
|
2562 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { |
|
2563 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); |
|
2564 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM); |
|
2565 |
return; |
|
2566 |
} |
|
2567 |
/* Thermal interrupt */ |
|
2568 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { |
|
2569 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); |
|
2570 |
powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM); |
|
2571 |
return; |
|
2572 |
} |
|
2511 | 2573 |
} |
2512 | 2574 |
} |
2513 | 2575 |
#endif /* !CONFIG_USER_ONLY */ |
... | ... | |
2572 | 2634 |
env->reserve = -1; |
2573 | 2635 |
/* Be sure no exception or interrupt is pending */ |
2574 | 2636 |
env->pending_interrupts = 0; |
2575 |
env->exception_index = EXCP_NONE; |
|
2637 |
env->exception_index = POWERPC_EXCP_NONE; |
|
2638 |
env->error_code = 0; |
|
2576 | 2639 |
/* Flush all TLBs */ |
2577 | 2640 |
tlb_flush(env, 1); |
2578 | 2641 |
} |
Also available in: Unified diff