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 | ... | ... |