Commit c62db10577295ed4dc26fa9acd6e6f30cea7ffd0
1 parent
636aaad7
Support for PowerPC BookE exception model.
No need to requeue timer exceptions. Fix nip saving for 64 bits PowerPC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2556 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
92 additions
and
49 deletions
target-ppc/helper.c
... | ... | @@ -1340,11 +1340,12 @@ void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) |
1340 | 1340 | void do_compute_hflags (CPUPPCState *env) |
1341 | 1341 | { |
1342 | 1342 | /* Compute current hflags */ |
1343 | - env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | | |
1344 | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | | |
1345 | - (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | | |
1346 | - (msr_se << MSR_SE) | (msr_be << MSR_BE); | |
1343 | + env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) | | |
1344 | + (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | | |
1345 | + (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | | |
1346 | + (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); | |
1347 | 1347 | #if defined (TARGET_PPC64) |
1348 | + /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */ | |
1348 | 1349 | env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32)); |
1349 | 1350 | #endif |
1350 | 1351 | } |
... | ... | @@ -1374,14 +1375,16 @@ static void dump_syscall(CPUState *env) |
1374 | 1375 | |
1375 | 1376 | void do_interrupt (CPUState *env) |
1376 | 1377 | { |
1377 | - target_ulong msr, *srr_0, *srr_1; | |
1378 | - int excp; | |
1378 | + target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1; | |
1379 | + int excp, idx; | |
1379 | 1380 | |
1380 | 1381 | excp = env->exception_index; |
1381 | 1382 | msr = do_load_msr(env); |
1382 | 1383 | /* The default is to use SRR0 & SRR1 to save the exception context */ |
1383 | 1384 | srr_0 = &env->spr[SPR_SRR0]; |
1384 | 1385 | srr_1 = &env->spr[SPR_SRR1]; |
1386 | + asrr_0 = NULL; | |
1387 | + asrr_1 = NULL; | |
1385 | 1388 | #if defined (DEBUG_EXCEPTIONS) |
1386 | 1389 | if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { |
1387 | 1390 | if (loglevel != 0) { |
... | ... | @@ -1397,26 +1400,44 @@ void do_interrupt (CPUState *env) |
1397 | 1400 | env->nip, excp, env->error_code); |
1398 | 1401 | } |
1399 | 1402 | msr_pow = 0; |
1403 | + idx = -1; | |
1400 | 1404 | /* Generate informations in save/restore registers */ |
1401 | 1405 | switch (excp) { |
1402 | 1406 | /* Generic PowerPC exceptions */ |
1403 | 1407 | case EXCP_RESET: /* 0x0100 */ |
1404 | - if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { | |
1408 | + switch (PPC_EXCP(env)) { | |
1409 | + case PPC_FLAGS_EXCP_40x: | |
1410 | + srr_0 = &env->spr[SPR_40x_SRR2]; | |
1411 | + srr_1 = &env->spr[SPR_40x_SRR3]; | |
1412 | + break; | |
1413 | + case PPC_FLAGS_EXCP_BOOKE: | |
1414 | + idx = 0; | |
1415 | + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; | |
1416 | + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; | |
1417 | + break; | |
1418 | + default: | |
1405 | 1419 | if (msr_ip) |
1406 | 1420 | excp += 0xFFC00; |
1407 | 1421 | excp |= 0xFFC00000; |
1408 | - } else { | |
1409 | - srr_0 = &env->spr[SPR_40x_SRR2]; | |
1410 | - srr_1 = &env->spr[SPR_40x_SRR3]; | |
1422 | + break; | |
1411 | 1423 | } |
1412 | 1424 | goto store_next; |
1413 | 1425 | case EXCP_MACHINE_CHECK: /* 0x0200 */ |
1414 | - if (msr_me == 0) { | |
1415 | - cpu_abort(env, "Machine check exception while not allowed\n"); | |
1416 | - } | |
1417 | - if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) { | |
1426 | + switch (PPC_EXCP(env)) { | |
1427 | + case PPC_FLAGS_EXCP_40x: | |
1418 | 1428 | srr_0 = &env->spr[SPR_40x_SRR2]; |
1419 | 1429 | srr_1 = &env->spr[SPR_40x_SRR3]; |
1430 | + break; | |
1431 | + case PPC_FLAGS_EXCP_BOOKE: | |
1432 | + idx = 1; | |
1433 | + srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; | |
1434 | + srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; | |
1435 | + asrr_0 = &env->spr[SPR_BOOKE_CSRR0]; | |
1436 | + asrr_1 = &env->spr[SPR_BOOKE_CSRR1]; | |
1437 | + msr_ce = 0; | |
1438 | + break; | |
1439 | + default: | |
1440 | + break; | |
1420 | 1441 | } |
1421 | 1442 | msr_me = 0; |
1422 | 1443 | break; |
... | ... | @@ -1425,6 +1446,7 @@ void do_interrupt (CPUState *env) |
1425 | 1446 | /* data location address has been stored |
1426 | 1447 | * when the fault has been detected |
1427 | 1448 | */ |
1449 | + idx = 2; | |
1428 | 1450 | msr &= ~0xFFFF0000; |
1429 | 1451 | #if defined (DEBUG_EXCEPTIONS) |
1430 | 1452 | if (loglevel) { |
... | ... | @@ -1438,6 +1460,7 @@ void do_interrupt (CPUState *env) |
1438 | 1460 | goto store_next; |
1439 | 1461 | case EXCP_ISI: /* 0x0400 */ |
1440 | 1462 | /* Store exception cause */ |
1463 | + idx = 3; | |
1441 | 1464 | msr &= ~0xFFFF0000; |
1442 | 1465 | msr |= env->error_code; |
1443 | 1466 | #if defined (DEBUG_EXCEPTIONS) |
... | ... | @@ -1448,20 +1471,12 @@ void do_interrupt (CPUState *env) |
1448 | 1471 | #endif |
1449 | 1472 | goto store_next; |
1450 | 1473 | case EXCP_EXTERNAL: /* 0x0500 */ |
1451 | - if (msr_ee == 0) { | |
1452 | -#if defined (DEBUG_EXCEPTIONS) | |
1453 | - if (loglevel > 0) { | |
1454 | - fprintf(logfile, "Skipping hardware interrupt\n"); | |
1455 | - } | |
1456 | -#endif | |
1457 | - /* Requeue it */ | |
1458 | - env->interrupt_request |= CPU_INTERRUPT_HARD; | |
1459 | - return; | |
1460 | - } | |
1474 | + idx = 4; | |
1461 | 1475 | goto store_next; |
1462 | 1476 | case EXCP_ALIGN: /* 0x0600 */ |
1463 | 1477 | if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) { |
1464 | 1478 | /* Store exception cause */ |
1479 | + idx = 5; | |
1465 | 1480 | /* Get rS/rD and rA from faulting opcode */ |
1466 | 1481 | env->spr[SPR_DSISR] |= |
1467 | 1482 | (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; |
... | ... | @@ -1476,6 +1491,7 @@ void do_interrupt (CPUState *env) |
1476 | 1491 | } |
1477 | 1492 | goto store_current; |
1478 | 1493 | case EXCP_PROGRAM: /* 0x0700 */ |
1494 | + idx = 6; | |
1479 | 1495 | msr &= ~0xFFFF0000; |
1480 | 1496 | switch (env->error_code & ~0xF) { |
1481 | 1497 | case EXCP_FP: |
... | ... | @@ -1501,6 +1517,7 @@ void do_interrupt (CPUState *env) |
1501 | 1517 | msr |= 0x00040000; |
1502 | 1518 | break; |
1503 | 1519 | case EXCP_TRAP: |
1520 | + idx = 15; | |
1504 | 1521 | msr |= 0x00020000; |
1505 | 1522 | break; |
1506 | 1523 | default: |
... | ... | @@ -1510,18 +1527,13 @@ void do_interrupt (CPUState *env) |
1510 | 1527 | msr |= 0x00010000; |
1511 | 1528 | goto store_current; |
1512 | 1529 | case EXCP_NO_FP: /* 0x0800 */ |
1530 | + idx = 7; | |
1513 | 1531 | msr &= ~0xFFFF0000; |
1514 | 1532 | goto store_current; |
1515 | 1533 | case EXCP_DECR: |
1516 | - if (msr_ee == 0) { | |
1517 | -#if 1 | |
1518 | - /* Requeue it */ | |
1519 | - env->interrupt_request |= CPU_INTERRUPT_TIMER; | |
1520 | -#endif | |
1521 | - return; | |
1522 | - } | |
1523 | 1534 | goto store_next; |
1524 | 1535 | case EXCP_SYSCALL: /* 0x0C00 */ |
1536 | + idx = 8; | |
1525 | 1537 | /* NOTE: this is a temporary hack to support graphics OSI |
1526 | 1538 | calls from the MOL driver */ |
1527 | 1539 | if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && |
... | ... | @@ -1557,13 +1569,6 @@ void do_interrupt (CPUState *env) |
1557 | 1569 | "Instruction segment exception is not implemented yet !\n"); |
1558 | 1570 | goto store_next; |
1559 | 1571 | case EXCP_HDECR: /* 0x0980 */ |
1560 | - if (msr_ee == 0) { | |
1561 | -#if 1 | |
1562 | - /* Requeue it */ | |
1563 | - env->interrupt_request |= CPU_INTERRUPT_TIMER; | |
1564 | -#endif | |
1565 | - return; | |
1566 | - } | |
1567 | 1572 | /* XXX: TODO */ |
1568 | 1573 | cpu_abort(env, "Hypervisor decrementer exception is not implemented " |
1569 | 1574 | "yet !\n"); |
... | ... | @@ -1581,6 +1586,7 @@ void do_interrupt (CPUState *env) |
1581 | 1586 | } |
1582 | 1587 | return; |
1583 | 1588 | case 0x0F20: |
1589 | + idx = 9; | |
1584 | 1590 | switch (PPC_EXCP(env)) { |
1585 | 1591 | case PPC_FLAGS_EXCP_40x: |
1586 | 1592 | /* APU unavailable on 405 */ |
... | ... | @@ -1600,11 +1606,13 @@ void do_interrupt (CPUState *env) |
1600 | 1606 | } |
1601 | 1607 | return; |
1602 | 1608 | case 0x1000: |
1609 | + idx = 10; | |
1603 | 1610 | switch (PPC_EXCP(env)) { |
1604 | 1611 | case PPC_FLAGS_EXCP_40x: |
1605 | 1612 | /* PIT on 4xx */ |
1606 | - /* XXX: TODO */ | |
1607 | - cpu_abort(env, "40x PIT exception is not implemented yet !\n"); | |
1613 | + msr &= ~0xFFFF0000; | |
1614 | + if (loglevel != 0) | |
1615 | + fprintf(logfile, "PIT exception\n"); | |
1608 | 1616 | goto store_next; |
1609 | 1617 | case PPC_FLAGS_EXCP_602: |
1610 | 1618 | case PPC_FLAGS_EXCP_603: |
... | ... | @@ -1619,11 +1627,13 @@ void do_interrupt (CPUState *env) |
1619 | 1627 | } |
1620 | 1628 | return; |
1621 | 1629 | case 0x1010: |
1630 | + idx = 11; | |
1622 | 1631 | switch (PPC_EXCP(env)) { |
1623 | 1632 | case PPC_FLAGS_EXCP_40x: |
1624 | 1633 | /* FIT on 4xx */ |
1625 | - /* XXX: TODO */ | |
1626 | - cpu_abort(env, "40x FIT exception is not implemented yet !\n"); | |
1634 | + msr &= ~0xFFFF0000; | |
1635 | + if (loglevel != 0) | |
1636 | + fprintf(logfile, "FIT exception\n"); | |
1627 | 1637 | goto store_next; |
1628 | 1638 | default: |
1629 | 1639 | cpu_abort(env, "Invalid exception 0x1010 !\n"); |
... | ... | @@ -1631,19 +1641,25 @@ void do_interrupt (CPUState *env) |
1631 | 1641 | } |
1632 | 1642 | return; |
1633 | 1643 | case 0x1020: |
1644 | + idx = 12; | |
1634 | 1645 | switch (PPC_EXCP(env)) { |
1635 | 1646 | case PPC_FLAGS_EXCP_40x: |
1636 | 1647 | /* Watchdog on 4xx */ |
1637 | - /* XXX: TODO */ | |
1638 | - cpu_abort(env, | |
1639 | - "40x watchdog exception is not implemented yet !\n"); | |
1648 | + msr &= ~0xFFFF0000; | |
1649 | + if (loglevel != 0) | |
1650 | + fprintf(logfile, "WDT exception\n"); | |
1640 | 1651 | goto store_next; |
1652 | + case PPC_FLAGS_EXCP_BOOKE: | |
1653 | + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; | |
1654 | + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; | |
1655 | + break; | |
1641 | 1656 | default: |
1642 | 1657 | cpu_abort(env, "Invalid exception 0x1020 !\n"); |
1643 | 1658 | break; |
1644 | 1659 | } |
1645 | 1660 | return; |
1646 | 1661 | case 0x1100: |
1662 | + idx = 13; | |
1647 | 1663 | switch (PPC_EXCP(env)) { |
1648 | 1664 | case PPC_FLAGS_EXCP_40x: |
1649 | 1665 | /* DTLBMISS on 4xx */ |
... | ... | @@ -1662,6 +1678,7 @@ void do_interrupt (CPUState *env) |
1662 | 1678 | } |
1663 | 1679 | return; |
1664 | 1680 | case 0x1200: |
1681 | + idx = 14; | |
1665 | 1682 | switch (PPC_EXCP(env)) { |
1666 | 1683 | case PPC_FLAGS_EXCP_40x: |
1667 | 1684 | /* ITLBMISS on 4xx */ |
... | ... | @@ -1838,6 +1855,10 @@ void do_interrupt (CPUState *env) |
1838 | 1855 | cpu_abort(env, |
1839 | 1856 | "601 run mode exception is not implemented yet !\n"); |
1840 | 1857 | goto store_next; |
1858 | + case PPC_FLAGS_EXCP_BOOKE: | |
1859 | + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; | |
1860 | + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; | |
1861 | + break; | |
1841 | 1862 | default: |
1842 | 1863 | cpu_abort(env, "Invalid exception 0x1800 !\n"); |
1843 | 1864 | break; |
... | ... | @@ -1852,15 +1873,19 @@ void do_interrupt (CPUState *env) |
1852 | 1873 | return; |
1853 | 1874 | store_current: |
1854 | 1875 | /* save current instruction location */ |
1855 | - *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL; | |
1876 | + *srr_0 = env->nip - 4; | |
1856 | 1877 | break; |
1857 | 1878 | store_next: |
1858 | 1879 | /* save next instruction location */ |
1859 | - *srr_0 = env->nip & 0xFFFFFFFFULL; | |
1880 | + *srr_0 = env->nip; | |
1860 | 1881 | break; |
1861 | 1882 | } |
1862 | 1883 | /* Save msr */ |
1863 | 1884 | *srr_1 = msr; |
1885 | + if (asrr_0 != NULL) | |
1886 | + *asrr_0 = *srr_0; | |
1887 | + if (asrr_1 != NULL) | |
1888 | + *asrr_1 = *srr_1; | |
1864 | 1889 | /* If we disactivated any translation, flush TLBs */ |
1865 | 1890 | if (msr_ir || msr_dr) { |
1866 | 1891 | tlb_flush(env, 1); |
... | ... | @@ -1877,10 +1902,28 @@ void do_interrupt (CPUState *env) |
1877 | 1902 | msr_dr = 0; |
1878 | 1903 | msr_ri = 0; |
1879 | 1904 | msr_le = msr_ile; |
1880 | - msr_sf = msr_isf; | |
1905 | + if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) { | |
1906 | + msr_cm = msr_icm; | |
1907 | + if (idx == -1 || (idx >= 16 && idx < 32)) { | |
1908 | + cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", | |
1909 | + excp, excp, idx); | |
1910 | + } | |
1911 | +#if defined(TARGET_PPC64) | |
1912 | + if (msr_cm) | |
1913 | + env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR]; | |
1914 | + else | |
1915 | +#endif | |
1916 | + env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR]; | |
1917 | + if (idx < 16) | |
1918 | + env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx]; | |
1919 | + else if (idx < 38) | |
1920 | + env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32]; | |
1921 | + } else { | |
1922 | + msr_sf = msr_isf; | |
1923 | + env->nip = excp; | |
1924 | + } | |
1881 | 1925 | do_compute_hflags(env); |
1882 | 1926 | /* Jump to handler */ |
1883 | - env->nip = excp; | |
1884 | 1927 | env->exception_index = EXCP_NONE; |
1885 | 1928 | } |
1886 | 1929 | ... | ... |