Commit c62db10577295ed4dc26fa9acd6e6f30cea7ffd0

Authored by j_mayer
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  
... ...