Compare commits

..

115 Commits

Author SHA1 Message Date
(no author)
1909e1ca09 This commit was manufactured by cvs2svn to create tag
'release_0_7_1'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_7_1@1535 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:44:57 +00:00
bellard
f5a8510c7c copyright
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1534 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:44:56 +00:00
bellard
93856aac7b update tarbin target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1533 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:44:35 +00:00
bellard
5cedb46460 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1532 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:14:03 +00:00
bellard
0f4c64157f kqemu info
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1531 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:10:56 +00:00
bellard
90cb949352 s390 bits
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1530 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 15:11:38 +00:00
bellard
db6e6ed77e do not export fls_bit
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1529 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 14:56:40 +00:00
bellard
57e4c06ed7 fscale fix (bug noticed by Kuwanger, fix by malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1528 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 14:33:17 +00:00
bellard
09d459a1db temporary work around for 16 bit code in kqemu
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1527 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 14:14:53 +00:00
bellard
108c49b8a2 allow more than 32 bit of physical memory
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1526 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 12:55:09 +00:00
bellard
90f18422d9 64 bit virtual addressing fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1525 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 10:17:31 +00:00
bellard
9529397248 open OSS audio device as write only (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1524 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 09:05:18 +00:00
bellard
a2458627f9 ppc64 target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1523 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 22:39:53 +00:00
bellard
b1fc0348b1 EXTINT delivery mode support for I/O APIC (Filip Navara)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1522 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 21:43:15 +00:00
bellard
45bbbb466c added overflow exceptions in divisions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 20:21:38 +00:00
bellard
d592d3033d IOAPIC support (initial patch by Filip Navara)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1520 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 19:05:37 +00:00
bellard
1ff5c1a68e prevent window resizing
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1519 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 17:54:50 +00:00
bellard
e5d80f94c5 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1518 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 17:43:14 +00:00
bellard
8f091a5960 x86_64 fixes (initial patch by Filip Navara)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1517 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 17:41:26 +00:00
bellard
2efbe911d3 more set/getsockopt values
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1516 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 15:10:20 +00:00
bellard
667f38b167 [f]truncate64 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1515 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 14:46:27 +00:00
bellard
8346901560 sparc64 fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1514 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 14:27:54 +00:00
bellard
b7c7b18129 fixed VIA irq register access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1513 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-23 14:01:47 +00:00
bellard
9835236910 specific mac-io PCI device_id for paddington/heathrow - fixed atapi requests - reset IDE drives in quiesce - added heathrow nvram OF description
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1512 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 22:38:00 +00:00
bellard
e573335624 heathrow nvram support - use different device ids for different macios
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1511 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 21:47:27 +00:00
bellard
4e588a4d0e negative decr fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1510 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 21:46:29 +00:00
bellard
a368741bf2 suppressed ppc ide hack - fixed read toc for Darwin/PPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1509 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 21:46:09 +00:00
bellard
61271e5c2d more precise cuda timers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1508 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 21:45:18 +00:00
bellard
aefce9af41 compilation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1507 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-07 19:07:52 +00:00
bellard
ee5bbe38b1 correct split between helper.c and op_helper.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1506 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-04 22:18:23 +00:00
bellard
e37e863f5e correct split between helper.c and op_helper.c - cosmetics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1505 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-04 22:17:33 +00:00
bellard
fdabc366bd correct split between helper.c and op_helper.c - moved some uops to op_helper.c (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1504 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-04 22:17:05 +00:00
bellard
2157fa0682 better fpu state dump
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1503 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 21:29:17 +00:00
bellard
d24b15a8d8 no need to dump CCOP
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1502 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 21:28:00 +00:00
bellard
9d0a8e6f8f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1501 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 17:34:05 +00:00
bellard
51a36cb2cb win32 compile fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1500 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 17:08:43 +00:00
bellard
33d084399c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1499 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 16:45:42 +00:00
bellard
e0727e17f3 removed bogus include
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1498 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 16:44:10 +00:00
bellard
97067eb5bc temporary version with better Darwin/Mac OS X support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1497 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 16:25:26 +00:00
bellard
4157a66212 allow variable bios size
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1496 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 16:00:49 +00:00
bellard
0289b2c1df changed machine names
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1495 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 16:00:32 +00:00
bellard
d5295253b0 VGA bios support for PowerPC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1494 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 14:00:51 +00:00
bellard
fb3444b86c endian register support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1493 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-03 13:57:11 +00:00
bellard
2be0071f22 simplified PowerPC exception handling (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1492 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 22:09:27 +00:00
bellard
f68c781c2d simplified
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1491 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 22:07:19 +00:00
bellard
fa296b0fb4 PIC fix - changed back TB frequency to 100 MHz
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1490 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 22:04:06 +00:00
bellard
3fc6c082e3 preliminary patch to support more PowerPC CPUs (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1489 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 20:59:34 +00:00
bellard
2f636b458f Cirrus fix (Magnus Damm)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1488 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 20:12:37 +00:00
bellard
3de388f676 more generic i8259 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1487 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 18:11:44 +00:00
bellard
73133662c6 i8259 PIC support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1486 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 18:11:03 +00:00
bellard
bf82d81801 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1485 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 18:07:26 +00:00
bellard
b195775fef update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1484 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:39:14 +00:00
bellard
1b351e5291 moved CALL_FROM_TBx definitions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1483 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:39:04 +00:00
bellard
d325856010 MIPS support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1482 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:37:12 +00:00
bellard
0d8aca8c67 TLB reload exception vector (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1481 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:35:03 +00:00
bellard
8549850891 fixed c0_context in tlb exception (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1480 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:34:05 +00:00
bellard
7a962d3087 use MIPS_TLB_NB constant (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1479 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:31:15 +00:00
bellard
e1d9a50836 use mask in C0_status (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1478 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:29:46 +00:00
bellard
568b600d85 report C0 status correctly (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1477 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:28:16 +00:00
bellard
bc2c390907 fixed priviledgees for CP0 use (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1476 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:27:11 +00:00
bellard
9827e95c78 added NE2000 (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1475 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:26:04 +00:00
bellard
51e11d9e6c fixed eret insn (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1474 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:23:21 +00:00
bellard
90b37806ba fixed C0 status codes (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1473 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:22:34 +00:00
bellard
0699b54839 init cleanup (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1472 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:20:29 +00:00
bellard
9d1d106a3d unaligned load fix (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1471 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:20:06 +00:00
bellard
ae022501f2 soft irq are just irqs (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1470 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:16:15 +00:00
bellard
899abcf513 fixed random register (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1469 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:13:42 +00:00
bellard
dfae6487c0 remove nonsense exception code (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1468 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:12:18 +00:00
bellard
de12d6369b kernel load fix (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1467 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:11:25 +00:00
bellard
bc9ed47b12 fixed jump mask (Ralf Baechle)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1466 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:10:44 +00:00
bellard
9fb63ac281 MIPS_USES_R4K_TLB typo
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1465 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 15:07:44 +00:00
bellard
6af0bf9c7c MIPS target (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1464 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 14:58:51 +00:00
bellard
6643d27ea0 MIPS disas support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1463 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 14:45:34 +00:00
bellard
3475187dd8 sparc64 marge (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1462 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 14:31:34 +00:00
bellard
8979b2277d VMDK disk image creation (Filip Navara)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1461 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 14:02:54 +00:00
bellard
97ccc689e6 Configure check for graphical output (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1460 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 13:32:17 +00:00
bellard
c98baaac2f correct __builtin_expect definition - increased code gen buffer size for x86
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1459 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-02 13:31:24 +00:00
bellard
101c593562 64 bit fixes (initial patch by Gwenole Beauchesne)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1458 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 17:11:42 +00:00
bellard
b685369795 added HOST_LONG_BITS in configure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1457 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 17:10:39 +00:00
bellard
3f1a88f450 added help on -nics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1456 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 16:48:41 +00:00
bellard
a84eaf0c9b add missing definitions in the ppc linker script (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1455 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:57:04 +00:00
bellard
6e20a45f53 comma separated list of targets in --target-list (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1454 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:56:02 +00:00
bellard
cadae95f33 IER behavior change - better IRQ handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1453 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:24:23 +00:00
bellard
e68b9b2b10 added Heathrow PIC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1452 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:21:57 +00:00
bellard
c0e564d53b use new machine API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1451 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:17:28 +00:00
bellard
384d887691 correct PCI ID for PREP PCI host bridge - added Grackle PCI host bridge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1450 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:16:50 +00:00
bellard
5457c8ceeb added CMD646 PCI IDE controller support - better IRQ handling - added IDE flush cache command - added work around for Darwin/PPC to select IDE drive
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1449 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:15:26 +00:00
bellard
0aa6a4a250 added Heathrow PowerMAC machine - added UniN memory fake controller for Mac99 - added temporary frame buffer OSI calls to keep Mac OS X happy
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1448 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 15:11:17 +00:00
bellard
938828a263 use new machine API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1447 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:54:40 +00:00
bellard
b5ff2d6e2d PC machine support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1446 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:51:11 +00:00
bellard
54fa5af546 more generic IRQ support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1445 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:50:39 +00:00
bellard
cc1daa40f1 added -M machine option - permit to put CDROM on hdb on PPC to handle the case where a single IDE controller is present
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1444 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:49:17 +00:00
bellard
2d61879305 simplified end of page handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1443 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:39:02 +00:00
bellard
7c48011b45 added back loglevel test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1442 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-05 14:38:00 +00:00
bellard
8dd4983c4e fixed lsw[ix] / stsw[ix] potential exception bug - mtcrf workaround for Mac OS X 10.4 - use direct jump at page boundary
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1441 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:22:27 +00:00
bellard
71be0fc3eb removed dynamic test of traces
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1440 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:19:46 +00:00
bellard
30aec8768f xec_bc mask fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1439 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:19:19 +00:00
bellard
8993433789 bctr and blr must ignore the two lsb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1438 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:19:02 +00:00
bellard
d094807b9b MMU fix - temporary osi_call support - xec_bc mask fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1437 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:17:59 +00:00
bellard
6d506e6dc2 added temporary osi_call callback
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1436 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 22:16:41 +00:00
bellard
43ef9eb267 use fprintf_func callback to print code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1435 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 20:34:16 +00:00
bellard
e4cf1adc80 added sum command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1434 c046a42c-6fe2-441c-8c8c-71466251a162
2005-06-04 20:15:57 +00:00
bellard
72cc6cfeef handle the case where several PCI irqs share the same PIC irq
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1433 c046a42c-6fe2-441c-8c8c-71466251a162
2005-05-13 23:08:13 +00:00
bellard
bc380d1719 ARM VFP dump fix (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1432 c046a42c-6fe2-441c-8c8c-71466251a162
2005-05-13 22:50:47 +00:00
bellard
ff8263a951 ARM saturating arithmetic fixes (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1431 c046a42c-6fe2-441c-8c8c-71466251a162
2005-05-13 22:45:23 +00:00
bellard
04d81be884 open fix (Paul Brook)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1430 c046a42c-6fe2-441c-8c8c-71466251a162
2005-05-13 22:42:37 +00:00
bellard
2d5262f991 dcbz fix (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1429 c046a42c-6fe2-441c-8c8c-71466251a162
2005-05-12 18:46:11 +00:00
bellard
a09db21f71 Windows 2000 install disk full hack (original idea from Vladimir N. Oleynik)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1428 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-30 16:10:35 +00:00
bellard
b671f9ed2d typos
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1427 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-30 15:08:33 +00:00
bellard
de167e416f Virtual VFAT support (Johannes Schindelin)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1426 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 21:15:08 +00:00
bellard
712e78744e probing fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1425 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 21:09:32 +00:00
bellard
7c35359cbf raw dmg support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1424 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 20:49:23 +00:00
bellard
d37282add1 added --enable-adlib in help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1423 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 20:41:53 +00:00
bellard
a343df1659 ne2000 reset fix - start/stop registers read access (aka OS/2 Warp V4 fix) (lukewarm)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1422 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 19:45:10 +00:00
bellard
98ff7d30f2 BMDMA interrupt fix (aka Solaris x86 IDE bug fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1421 c046a42c-6fe2-441c-8c8c-71466251a162
2005-04-28 19:26:35 +00:00
110 changed files with 24020 additions and 3622 deletions

View File

@@ -6,6 +6,7 @@ i386
i386-softmmu
i386-user
ppc-softmmu
ppc64-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
@@ -19,3 +20,4 @@ sparc-softmmu
x86_64-softmmu
sparc64-user
sparc64-softmmu
mips-softmmu

View File

@@ -1,3 +1,14 @@
version 0.7.1:
- read-only Virtual FAT support (Johannes Schindelin)
- Windows 2000 install disk full hack (original idea from Vladimir
N. Oleynik)
- VMDK disk image creation (Filip Navara)
- SPARC64 progress (Blue Swirl)
- initial MIPS support (Jocelyn mayer)
- MIPS improvements (Ralf Baechle)
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
version 0.7.0:
- better BIOS translation and HDD geometry auto-detection

View File

@@ -25,7 +25,7 @@ else
endif
endif
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
dyngen$(EXESUF): dyngen.c
@@ -59,7 +59,7 @@ install: all
mkdir -p "$(datadir)"
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
pc-bios/vgabios-cirrus.bin \
pc-bios/ppc_rom.bin \
pc-bios/ppc_rom.bin pc-bios/video.x \
pc-bios/proll.elf \
pc-bios/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
@@ -112,6 +112,7 @@ tarbin:
$(bindir)/qemu-system-ppc \
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-sparc \
@@ -121,6 +122,7 @@ tarbin:
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/proll.elf \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \

View File

@@ -4,6 +4,9 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH)
ifeq ($(TARGET_ARCH), x86_64)
TARGET_BASE_ARCH:=i386
endif
ifeq ($(TARGET_ARCH), ppc64)
TARGET_BASE_ARCH:=ppc
endif
ifeq ($(TARGET_ARCH), sparc64)
TARGET_BASE_ARCH:=sparc
endif
@@ -44,74 +47,10 @@ endif
ifdef CONFIG_USER_ONLY
PROGS=$(QEMU_USER)
else
ifeq ($(TARGET_ARCH), i386)
ifeq ($(ARCH), i386)
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
else
# the system emulator using soft mmu is portable
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH != i386
endif # TARGET_ARCH = i386
ifeq ($(TARGET_ARCH), x86_64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # TARGET_ARCH = x86_64
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = i386
ifeq ($(ARCH), x86_64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = x86_64
endif # TARGET_ARCH = ppc
ifeq ($(TARGET_ARCH), sparc)
ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = i386
ifeq ($(ARCH), x86_64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = x86_64
endif # TARGET_ARCH = sparc
ifeq ($(TARGET_ARCH), sparc64)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
endif
endif # TARGET_ARCH = sparc64
endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
@@ -259,7 +198,11 @@ ifeq ($(TARGET_ARCH), x86_64)
LIBOBJS+=helper.o helper2.o
endif
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(TARGET_BASE_ARCH), ppc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_ARCH), mips)
LIBOBJS+= op_helper.o helper.o
endif
@@ -285,9 +228,12 @@ endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
@@ -314,7 +260,7 @@ endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
@@ -343,13 +289,24 @@ VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
endif
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o
#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
VL_OBJS+= magic-load.o
else
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
endif
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
@@ -442,12 +399,19 @@ op.o: op.c op_template.h
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
op.o: op.c op_template.h op_mem.h
op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
magic_load.o: elf_op.h
endif
ifeq ($(TARGET_ARCH), ppc)
ifeq ($(TARGET_BASE_ARCH), ppc)
op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
translate.o: translate.c translate_init.c
endif
ifeq ($(TARGET_ARCH), mips)
op.o: op.c op_template.c op_mem.c
op_helper.o: op_helper_mem.c
endif
mixeng.o: mixeng.c mixeng.h mixeng_template.h

View File

@@ -1 +1 @@
0.7.0
0.7.1

View File

@@ -127,7 +127,7 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
int fmt, freq, nchannels;
const char *dspname = conf.dspname;
fd = open (dspname, O_RDWR | O_NONBLOCK);
fd = open (dspname, O_WRONLY | O_NONBLOCK);
if (-1 == fd) {
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",

View File

@@ -54,7 +54,8 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const struct cow_header_v2 *cow_header = (const void *)buf;
if (be32_to_cpu(cow_header->magic) == COW_MAGIC &&
if (buf_size >= sizeof(struct cow_header_v2) &&
be32_to_cpu(cow_header->magic) == COW_MAGIC &&
be32_to_cpu(cow_header->version) == COW_VERSION)
return 100;
else

View File

@@ -91,7 +91,9 @@ static int dmg_open(BlockDriverState *bs, const char *filename)
if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
dmg_close:
close(s->fd);
return -1;
/* open raw instead */
bs->drv=&bdrv_raw;
return bs->drv->bdrv_open(bs,filename);
}
info_begin=read_off(s->fd);
if(info_begin==0)

View File

@@ -80,8 +80,9 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const QCowHeader *cow_header = (const void *)buf;
if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
return 100;
else
@@ -551,9 +552,19 @@ static int qcow_create(const char *filename, int64_t total_size,
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
const char *p;
/* XXX: this is a hack: we do not attempt to check for URL
like syntax */
p = strchr(backing_file, ':');
if (p && (p - backing_file) >= 2) {
/* URL like but exclude "c:" like filenames */
pstrcpy(backing_filename, sizeof(backing_filename),
backing_file);
} else {
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
}
}
header.mtime = cpu_to_be32(st.st_mtime);
header.backing_file_offset = cpu_to_be64(header_size);

View File

@@ -315,6 +315,109 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
return 0;
}
static int vmdk_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd, i;
VMDK4Header header;
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
char *desc_template =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=ffffffff\n"
"createType=\"monolithicSparse\"\n"
"\n"
"# Extent description\n"
"RW %lu SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n"
"ddb.virtualHWVersion = \"3\"\n"
"ddb.geometry.cylinders = \"%lu\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"ide\"\n";
char desc[1024];
const char *real_filename, *temp_str;
/* XXX: add support for backing file */
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -1;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
header.version = cpu_to_le32(1);
header.flags = cpu_to_le32(3); /* ?? */
header.capacity = cpu_to_le64(total_size);
header.granularity = cpu_to_le64(128);
header.num_gtes_per_gte = cpu_to_le32(512);
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
header.desc_offset = 1;
header.desc_size = 20;
header.rgd_offset = header.desc_offset + header.desc_size;
header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
header.grain_offset =
((header.gd_offset + gd_size + (gt_size * gt_count) +
header.granularity - 1) / header.granularity) *
header.granularity;
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
header.gd_offset = cpu_to_le64(header.gd_offset);
header.grain_offset = cpu_to_le64(header.grain_offset);
header.check_bytes[0] = 0xa;
header.check_bytes[1] = 0x20;
header.check_bytes[2] = 0xd;
header.check_bytes[3] = 0xa;
/* write all the data */
write(fd, &magic, sizeof(magic));
write(fd, &header, sizeof(header));
ftruncate(fd, header.grain_offset << 9);
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.rgd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* write backup grain directory */
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
for (i = 0, tmp = header.gd_offset + gd_size;
i < gt_count; i++, tmp += gt_size)
write(fd, &tmp, sizeof(tmp));
/* compose the descriptor */
real_filename = filename;
if ((temp_str = strrchr(real_filename, '\\')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, '/')) != NULL)
real_filename = temp_str + 1;
if ((temp_str = strrchr(real_filename, ':')) != NULL)
real_filename = temp_str + 1;
sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
real_filename, total_size / (63 * 16));
/* write the descriptor */
lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
write(fd, desc, strlen(desc));
close(fd);
return 0;
}
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
@@ -331,6 +434,6 @@ BlockDriver bdrv_vmdk = {
vmdk_read,
vmdk_write,
vmdk_close,
NULL, /* no create yet */
vmdk_create,
vmdk_is_allocated,
};

View File

@@ -81,9 +81,8 @@ typedef struct BDRVVPCState {
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (!strncmp(buf, "conectix", 8))
if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
return 100;
return 0;
}

1742
block-vvfat.c Normal file

File diff suppressed because it is too large Load Diff

42
block.c
View File

@@ -106,26 +106,29 @@ static BlockDriver *find_image_format(const char *filename)
size_t bufsize = 1024;
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return NULL;
if (fd < 0) {
buf = NULL;
ret = 0;
} else {
#ifdef DIOCGSECTORSIZE
{
unsigned int sectorsize = 512;
if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
sectorsize > bufsize)
bufsize = sectorsize;
}
{
unsigned int sectorsize = 512;
if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
sectorsize > bufsize)
bufsize = sectorsize;
}
#endif
buf = malloc(bufsize);
if (!buf)
return NULL;
ret = read(fd, buf, bufsize);
if (ret < 0) {
buf = qemu_malloc(bufsize);
if (!buf)
return NULL;
ret = read(fd, buf, bufsize);
if (ret < 0) {
close(fd);
qemu_free(buf);
return NULL;
}
close(fd);
free(buf);
return NULL;
}
close(fd);
drv = NULL;
score_max = 0;
@@ -136,7 +139,7 @@ static BlockDriver *find_image_format(const char *filename)
drv = drv1;
}
}
free(buf);
qemu_free(buf);
return drv;
}
@@ -154,7 +157,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
bs->read_only = 0;
bs->is_temporary = 0;
bs->encrypted = 0;
if (snapshot) {
BlockDriverState *bs1;
int64_t total_size;
@@ -183,7 +186,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
filename = tmp_filename;
bs->is_temporary = 1;
}
pstrcpy(bs->filename, sizeof(bs->filename), filename);
if (!drv) {
drv = find_image_format(filename);
@@ -653,4 +656,5 @@ void bdrv_init(void)
bdrv_register(&bdrv_dmg);
bdrv_register(&bdrv_bochs);
bdrv_register(&bdrv_vpc);
bdrv_register(&bdrv_vvfat);
}

38
configure vendored
View File

@@ -84,6 +84,7 @@ linux="no"
kqemu="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
# OS specific
targetos=`uname -s`
@@ -152,6 +153,8 @@ for opt do
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
@@ -186,6 +189,8 @@ for opt do
;;
--enable-cocoa) cocoa="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
;;
esac
done
@@ -210,11 +215,13 @@ fi
if test -z "$target_list" ; then
# these targets are portable
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu"
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
# the following are Linux specific
if [ "$linux" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
fi
else
target_list=$(echo "$target_list" | sed -e 's/,/ /g')
fi
if test -z "$cross_prefix" ; then
@@ -244,6 +251,12 @@ fi
fi
# host long bits test
hostlongbits="32"
if test "$cpu" = "sparc64" -o "$cpu" = "ia64" -o "$cpu" = "x86_64" -o "$cpu" = "alpha"; then
hostlongbits="64"
fi
# check gcc options support
cat > $TMPC <<EOF
int main(void) {
@@ -328,9 +341,11 @@ echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc."
echo " --make=MAKE use specified make [$make]"
echo " --static enable static build [$static]"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-adlib enable Adlib emulation"
echo " --enable-fmod enable FMOD audio output driver"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
@@ -408,6 +423,7 @@ echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
echo "make $make"
echo "host CPU $cpu"
echo "host big endian $bigendian"
@@ -517,6 +533,7 @@ if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
fi
echo "#define HOST_LONG_BITS $hostlongbits" >> $config_h
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> $config_mak
echo "#define CONFIG_WIN32 1" >> $config_h
@@ -594,6 +611,8 @@ target_bigendian="no"
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -603,6 +622,14 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU with graphical output configure with --disable-gfx-check"
echo "Note that this will disable all output from the virtual graphics card."
exit 1;
fi
#echo "Creating $config_mak, $config_h and $target_dir/Makefile"
mkdir -p $target_dir
@@ -650,6 +677,11 @@ elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
elif test "$target_cpu" = "ppc64" ; then
echo "TARGET_ARCH=ppc64" >> $config_mak
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
elif test "$target_cpu" = "x86_64" ; then
echo "TARGET_ARCH=x86_64" >> $config_mak
echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
@@ -658,6 +690,10 @@ elif test "$target_cpu" = "x86_64" ; then
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then
echo "#define USE_KQEMU 1" >> $config_h
fi
elif test "$target_cpu" = "mips" ; then
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1

View File

@@ -617,6 +617,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_signal_handler cpu_ppc_signal_handler
#elif defined(TARGET_MIPS)
#define CPUState CPUMIPSState
#define cpu_init cpu_mips_init
#define cpu_exec cpu_mips_exec
#define cpu_gen_code cpu_mips_gen_code
#define cpu_signal_handler cpu_mips_signal_handler
#else
#error unsupported target CPU

View File

@@ -29,12 +29,6 @@
#error TARGET_LONG_BITS must be defined before including this header
#endif
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define HOST_LONG_BITS 64
#else
#define HOST_LONG_BITS 32
#endif
#ifndef TARGET_PHYS_ADDR_BITS
#if TARGET_LONG_BITS >= HOST_LONG_BITS
#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
@@ -74,9 +68,9 @@ typedef uint64_t target_phys_addr_t;
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define MAX_BREAKPOINTS 32

View File

@@ -47,6 +47,9 @@ void cpu_loop_exit(void)
longjmp(env->jmp_env, 1);
}
#endif
#ifndef TARGET_SPARC
#define reg_T2
#endif
/* exit the current TB from a signal handler. The host registers are
restored in a state compatible with the CPU emulator
@@ -74,8 +77,12 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
int cpu_exec(CPUState *env1)
{
int saved_T0, saved_T1, saved_T2;
int saved_T0, saved_T1;
#if defined(reg_T2)
int saved_T2;
#endif
CPUState *saved_env;
#if defined(TARGET_I386)
#ifdef reg_EAX
int saved_EAX;
#endif
@@ -100,6 +107,11 @@ int cpu_exec(CPUState *env1)
#ifdef reg_EDI
int saved_EDI;
#endif
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
uint32_t *saved_regwptr;
#endif
#endif
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
@@ -115,7 +127,9 @@ int cpu_exec(CPUState *env1)
env = env1;
saved_T0 = T0;
saved_T1 = T1;
#if defined(reg_T2)
saved_T2 = T2;
#endif
#ifdef __sparc__
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
@@ -164,7 +178,11 @@ int cpu_exec(CPUState *env1)
env->cpsr = psr & ~CACHED_CPSR_BITS;
}
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
saved_regwptr = REGWPTR;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@@ -203,6 +221,8 @@ int cpu_exec(CPUState *env1)
env->exception_next_eip, 0);
#elif defined(TARGET_PPC)
do_interrupt(env);
#elif defined(TARGET_MIPS)
do_interrupt(env);
#elif defined(TARGET_SPARC)
do_interrupt(env->exception_index);
#endif
@@ -284,6 +304,19 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
}
#elif defined(TARGET_MIPS)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
(env->CP0_Cause & 0x0000FF00) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM)) {
/* Raise it */
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
#elif defined(TARGET_SPARC)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psret != 0)) {
@@ -354,9 +387,13 @@ int cpu_exec(CPUState *env1)
cpu_dump_state(env, logfile, fprintf, 0);
env->cpsr &= ~CACHED_CPSR_BITS;
#elif defined(TARGET_SPARC)
cpu_dump_state (env, logfile, fprintf, 0);
REGWPTR = env->regbase + (env->cwp * 16);
env->regwptr = REGWPTR;
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_PPC)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_MIPS)
cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
@@ -376,7 +413,11 @@ int cpu_exec(CPUState *env1)
cs_base = 0;
pc = env->regs[15];
#elif defined(TARGET_SPARC)
flags = 0;
#ifdef TARGET_SPARC64
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
#else
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
#endif
cs_base = env->npc;
pc = env->pc;
#elif defined(TARGET_PPC)
@@ -384,6 +425,10 @@ int cpu_exec(CPUState *env1)
(msr_se << MSR_SE) | (msr_le << MSR_LE);
cs_base = 0;
pc = env->nip;
#elif defined(TARGET_MIPS)
flags = env->hflags & MIPS_HFLAGS_TMASK;
cs_base = NULL;
pc = env->PC;
#else
#error unsupported CPU
#endif
@@ -657,7 +702,11 @@ int cpu_exec(CPUState *env1)
env->cpsr = compute_cpsr();
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
REGWPTR = saved_regwptr;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@@ -666,7 +715,9 @@ int cpu_exec(CPUState *env1)
#endif
T0 = saved_T0;
T1 = saved_T1;
#if defined(reg_T2)
T2 = saved_T2;
#endif
env = saved_env;
return ret;
}
@@ -907,6 +958,57 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* never comes here */
return 1;
}
#elif defined (TARGET_MIPS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
do_raise_exception_err(env->exception_index, env->error_code);
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif
@@ -1178,6 +1280,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
&uc->uc_sigmask, puc);
}
#elif defined(__s390__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
pc = uc->uc_mcontext.psw.addr;
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask, puc);
}
#else
#error host CPU specific signal handler needed

View File

@@ -126,6 +126,24 @@ enum bfd_architecture
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
#define bfd_mach_ppc 0
#define bfd_mach_ppc64 1
#define bfd_mach_ppc_403 403
#define bfd_mach_ppc_403gc 4030
#define bfd_mach_ppc_505 505
#define bfd_mach_ppc_601 601
#define bfd_mach_ppc_602 602
#define bfd_mach_ppc_603 603
#define bfd_mach_ppc_ec603e 6031
#define bfd_mach_ppc_604 604
#define bfd_mach_ppc_620 620
#define bfd_mach_ppc_630 630
#define bfd_mach_ppc_750 750
#define bfd_mach_ppc_860 860
#define bfd_mach_ppc_a35 35
#define bfd_mach_ppc_rs64ii 642
#define bfd_mach_ppc_rs64iii 643
#define bfd_mach_ppc_7400 7400
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
@@ -404,6 +422,8 @@ extern int generic_symbol_at_address
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
bfd_vma bfd_getl16 (const bfd_byte *addr);
bfd_vma bfd_getb16 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */

39
disas.c
View File

@@ -108,6 +108,24 @@ bfd_vma bfd_getb32 (const bfd_byte *addr)
return (bfd_vma) v;
}
bfd_vma bfd_getl16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
return (bfd_vma) v;
}
bfd_vma bfd_getb16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
return (bfd_vma) v;
}
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
@@ -155,10 +173,20 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#ifdef TARGET_SPARC64
disasm_info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (cpu_single_env->msr[MSR_LE])
disasm_info.endian = BFD_ENDIAN_LITTLE;
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
@@ -219,6 +247,10 @@ void disas(FILE *out, void *code, unsigned long size)
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#elif defined(__MIPSEB__)
print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
print_insn = print_insn_little_mips;
#else
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
(long) code);
@@ -328,7 +360,14 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
#else
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);

View File

@@ -218,6 +218,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#endif
#ifdef __s390__
#define EXIT_TB() asm volatile ("br %r14")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __alpha__
#define EXIT_TB() asm volatile ("ret")

18
elf.h
View File

@@ -31,11 +31,29 @@ typedef int64_t Elf64_Sxword;
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_MIPS_REGINFO 0x70000000
#define PT_MIPS_OPTIONS 0x70000001
/* Flags in the e_flags field of the header */
/* MIPS architecture level. */
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
/* The ABI of a file. */
#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
#define EF_MIPS_NOREORDER 0x00000001
#define EF_MIPS_PIC 0x00000002
#define EF_MIPS_CPIC 0x00000004
#define EF_MIPS_ABI2 0x00000020
#define EF_MIPS_OPTIONS_FIRST 0x00000080
#define EF_MIPS_32BITMODE 0x00000100
#define EF_MIPS_ABI 0x0000f000
#define EF_MIPS_ARCH 0xf0000000
/* These constants define the different elf file types */

View File

@@ -28,7 +28,7 @@
#define tostring(s) #s
#endif
#if GCC_MAJOR < 3
#if __GNUC__ < 3
#define __builtin_expect(x, n) (x)
#endif
@@ -131,7 +131,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
#elif defined(__powerpc__)
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
#else
#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024)
#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024)
#endif
//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
@@ -582,6 +582,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
is_user = ((env->hflags & HF_CPL_MASK) == 3);
#elif defined (TARGET_PPC)
is_user = msr_pr;
#elif defined (TARGET_MIPS)
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
#elif defined (TARGET_SPARC)
is_user = (env->psrs == 0);
#else
@@ -613,7 +615,8 @@ static inline int kqemu_is_ok(CPUState *env)
(env->eflags & IOPL_MASK) != IOPL_MASK &&
(env->cr[0] & CR0_PE_MASK) &&
(env->eflags & IF_MASK) &&
!(env->eflags & VM_MASK));
!(env->eflags & VM_MASK) &&
(env->ldt.limit == 0 || env->ldt.limit == 0x27));
}
#endif

185
exec.c
View File

@@ -51,6 +51,15 @@
#define MMAP_AREA_START 0x00000000
#define MMAP_AREA_END 0xa8000000
#if defined(TARGET_SPARC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 41
#elif defined(TARGET_PPC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 42
#else
/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#endif
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
@@ -83,6 +92,8 @@ typedef struct PhysPageDesc {
uint32_t phys_offset;
} PhysPageDesc;
/* Note: the VirtPage handling is absolete and will be suppressed
ASAP */
typedef struct VirtPageDesc {
/* physical address of code page. It is valid only if 'valid_tag'
matches 'virt_valid_tag' */
@@ -113,7 +124,13 @@ static PageDesc *l1_map[L1_SIZE];
PhysPageDesc **l1_phys_map;
#if !defined(CONFIG_USER_ONLY)
#if TARGET_LONG_BITS > 32
#define VIRT_L_BITS 9
#define VIRT_L_SIZE (1 << VIRT_L_BITS)
static void *l1_virt_map[VIRT_L_SIZE];
#else
static VirtPageDesc *l1_virt_map[L1_SIZE];
#endif
static unsigned int virt_valid_tag;
#endif
@@ -176,8 +193,8 @@ static void page_init(void)
#if !defined(CONFIG_USER_ONLY)
virt_valid_tag = 1;
#endif
l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
}
static inline PageDesc *page_find_alloc(unsigned int index)
@@ -205,80 +222,156 @@ static inline PageDesc *page_find(unsigned int index)
return p + (index & (L2_SIZE - 1));
}
static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
{
PhysPageDesc **lp, *p;
void **lp, **p;
lp = &l1_phys_map[index >> L2_BITS];
p = (void **)l1_phys_map;
#if TARGET_PHYS_ADDR_SPACE_BITS > 32
#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
#endif
lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
p = *lp;
if (!p) {
/* allocate if not found */
if (!alloc)
return NULL;
p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
memset(p, 0, sizeof(void *) * L1_SIZE);
*lp = p;
}
#endif
lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
p = *lp;
if (!p) {
/* allocate if not found */
if (!alloc)
return NULL;
p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
*lp = p;
}
return p + (index & (L2_SIZE - 1));
return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1));
}
static inline PhysPageDesc *phys_page_find(unsigned int index)
static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
{
PhysPageDesc *p;
p = l1_phys_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
return phys_page_find_alloc(index, 0);
}
#if !defined(CONFIG_USER_ONLY)
static void tlb_protect_code(CPUState *env, target_ulong addr);
static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
{
VirtPageDesc **lp, *p;
/* XXX: should not truncate for 64 bit addresses */
#if TARGET_LONG_BITS > 32
index &= (L1_SIZE - 1);
#endif
void **p, **lp;
p = l1_virt_map;
lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
*lp = p;
}
return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
#else
VirtPageDesc *p, **lp;
lp = &l1_virt_map[index >> L2_BITS];
p = *lp;
if (!p) {
/* allocate if not found */
p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
*lp = p;
}
return p + (index & (L2_SIZE - 1));
#endif
}
static inline VirtPageDesc *virt_page_find(unsigned int index)
static inline VirtPageDesc *virt_page_find(target_ulong index)
{
VirtPageDesc *p;
p = l1_virt_map[index >> L2_BITS];
if (!p)
return 0;
return p + (index & (L2_SIZE - 1));
return virt_page_find_alloc(index, 0);
}
#if TARGET_LONG_BITS > 32
static void virt_page_flush_internal(void **p, int level)
{
int i;
if (level == 0) {
VirtPageDesc *q = (VirtPageDesc *)p;
for(i = 0; i < VIRT_L_SIZE; i++)
q[i].valid_tag = 0;
} else {
level--;
for(i = 0; i < VIRT_L_SIZE; i++) {
if (p[i])
virt_page_flush_internal(p[i], level);
}
}
}
#endif
static void virt_page_flush(void)
{
int i, j;
VirtPageDesc *p;
virt_valid_tag++;
if (virt_valid_tag == 0) {
virt_valid_tag = 1;
for(i = 0; i < L1_SIZE; i++) {
p = l1_virt_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].valid_tag = 0;
#if TARGET_LONG_BITS > 32
virt_page_flush_internal(l1_virt_map, 5);
#else
{
int i, j;
VirtPageDesc *p;
for(i = 0; i < L1_SIZE; i++) {
p = l1_virt_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].valid_tag = 0;
}
}
}
#endif
}
}
#else
@@ -945,7 +1038,7 @@ void tb_link(TranslationBlock *tb)
/* save the code memory mappings (needed to invalidate the code) */
addr = tb->pc & TARGET_PAGE_MASK;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
#ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[0]) {
@@ -963,7 +1056,7 @@ void tb_link(TranslationBlock *tb)
if (tb->page_addr[1] != -1) {
addr += TARGET_PAGE_SIZE;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
#ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[1]) {
@@ -1330,7 +1423,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
TranslationBlock *tb;
#if defined(DEBUG_TLB)
printf("tlb_flush_page: 0x%08x\n", addr);
printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
#endif
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
@@ -1497,7 +1590,7 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
}
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
unsigned long start)
unsigned long start)
{
unsigned long addr;
if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
@@ -1536,7 +1629,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
TranslationBlock *first_tb;
unsigned int index;
target_ulong address;
unsigned long addend;
target_phys_addr_t addend;
int ret;
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
@@ -1553,7 +1646,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
}
}
#if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
#endif
@@ -1572,7 +1665,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
}
index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
addend -= vaddr;
if (prot & PAGE_READ) {
env->tlb_read[is_user][index].address = address;
@@ -1635,7 +1728,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
original mapping */
VirtPageDesc *vp;
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
vp->phys_addr = pd;
vp->prot = prot;
vp->valid_tag = virt_valid_tag;
@@ -1859,13 +1952,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset)
{
unsigned long addr, end_addr;
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p->phys_offset = phys_offset;
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
phys_offset += TARGET_PAGE_SIZE;

View File

@@ -1,7 +1,7 @@
/*
* gdb server stub
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003-2005 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -253,14 +253,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
registers[96] = tswapl(env->nip);
registers[97] = tswapl(_load_msr(env));
registers[97] = tswapl(do_load_msr(env));
tmp = 0;
for (i = 0; i < 8; i++)
tmp |= env->crf[i] << (32 - ((i + 1) * 4));
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
registers[101] = tswapl(_load_xer(env));
registers[101] = tswapl(do_load_xer(env));
registers[102] = 0;
return 103 * 4;
@@ -282,18 +282,18 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
}
/* nip, msr, ccr, lnk, ctr, xer, mq */
env->nip = tswapl(registers[96]);
_store_msr(env, tswapl(registers[97]));
do_store_msr(env, tswapl(registers[97]));
registers[98] = tswapl(registers[98]);
for (i = 0; i < 8; i++)
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
_store_xer(env, tswapl(registers[101]));
do_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *registers = (uint32_t *)mem_buf, tmp;
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
@@ -308,10 +308,15 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
for (i = 0; i < 32; i++) {
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
registers[64] = tswapl(env->y);
tmp = GET_PSR(env);
registers[65] = tswapl(tmp);
{
target_ulong tmp;
tmp = GET_PSR(env);
registers[65] = tswapl(tmp);
}
registers[66] = tswapl(env->wim);
registers[67] = tswapl(env->tbr);
registers[68] = tswapl(env->pc);
@@ -319,13 +324,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
registers[70] = tswapl(env->fsr);
registers[71] = 0; /* csr */
registers[72] = 0;
return 73 * 4;
return 73 * sizeof(target_ulong);
#else
for (i = 0; i < 32; i += 2) {
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
}
registers[81] = tswapl(env->pc);
registers[82] = tswapl(env->npc);
registers[83] = tswapl(env->tstate[env->tl]);
registers[84] = tswapl(env->fsr);
registers[85] = tswapl(env->fprs);
registers[86] = tswapl(env->y);
return 87 * sizeof(target_ulong);
#endif
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *registers = (uint32_t *)mem_buf;
target_ulong *registers = (target_ulong *)mem_buf;
int i;
/* fill in g0..g7 */
@@ -334,12 +350,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
}
/* fill in register window */
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i]);
env->regwptr[i] = tswapl(registers[i + 8]);
}
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
}
#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
env->y = tswapl(registers[64]);
PUT_PSR(env, tswapl(registers[65]));
@@ -348,6 +365,20 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
env->pc = tswapl(registers[68]);
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
#else
for (i = 0; i < 32; i += 2) {
uint64_t tmp;
tmp = tswapl(registers[i/2 + 64]) << 32;
tmp |= tswapl(registers[i/2 + 64 + 1]);
*((uint64_t *)&env->fpr[i]) = tmp;
}
env->pc = tswapl(registers[81]);
env->npc = tswapl(registers[82]);
env->tstate[env->tl] = tswapl(registers[83]);
env->fsr = tswapl(registers[84]);
env->fprs = tswapl(registers[85]);
env->y = tswapl(registers[86]);
#endif
}
#elif defined (TARGET_ARM)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)

553
hw/apic.c
View File

@@ -20,6 +20,7 @@
#include "vl.h"
//#define DEBUG_APIC
//#define DEBUG_IOAPIC
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
@@ -39,6 +40,10 @@
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
/* APIC destination mode */
#define APIC_DESTMODE_FLAT 0xf
#define APIC_DESTMODE_CLUSTER 1
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
@@ -49,6 +54,8 @@
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define IOAPIC_NUM_PINS 0x18
#define ESR_ILLEGAL_ADDRESS (1 << 7)
#define APIC_SV_ENABLE (1 << 8)
@@ -57,8 +64,11 @@ typedef struct APICState {
CPUState *cpu_env;
uint32_t apicbase;
uint8_t id;
uint8_t arb_id;
uint8_t tpr;
uint32_t spurious_vec;
uint8_t log_dest;
uint8_t dest_mode;
uint32_t isr[8]; /* in service register */
uint32_t tmr[8]; /* trigger mode register */
uint32_t irr[8]; /* interrupt request register */
@@ -71,9 +81,64 @@ typedef struct APICState {
uint32_t initial_count;
int64_t initial_count_load_time, next_time;
QEMUTimer *timer;
struct APICState *next_apic;
} APICState;
struct IOAPICState {
uint8_t id;
uint8_t ioregsel;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
};
static int apic_io_memory;
static APICState *first_local_apic = NULL;
static int last_apic_id = 0;
static void apic_init_ipi(APICState *s);
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
static void apic_update_irq(APICState *s);
static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
uint8_t vector_num, uint8_t polarity,
uint8_t trigger_mode)
{
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
case APIC_DM_FIXED:
/* XXX: arbitration */
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
break;
case APIC_DM_INIT:
/* normal INIT IPI sent to processors */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
apic_init_ipi(apic_iter);
}
return;
case APIC_DM_EXTINT:
/* handled in I/O APIC code */
break;
default:
return;
}
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id))
apic_set_irq(apic_iter, vector_num, trigger_mode);
}
}
void cpu_set_apic_base(CPUState *env, uint64_t val)
{
@@ -104,6 +169,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
{
APICState *s = env->apic_state;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
uint8_t cpu_get_apic_tpr(CPUX86State *env)
@@ -112,16 +178,24 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env)
return s->tpr >> 4;
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
static int fls_bit(int value)
{
int i;
for(i = 0;i < 8; i++) {
if (tab[i] != 0) {
return i * 32 + ffs(tab[i]) - 1;
}
}
return -1;
unsigned int ret = 0;
#ifdef HOST_I386
__asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
return ret;
#else
if (value > 0xffff)
value >>= 16, ret = 16;
if (value > 0xff)
value >>= 8, ret += 8;
if (value > 0xf)
value >>= 4, ret += 4;
if (value > 0x3)
value >>= 2, ret += 2;
return ret + (value >> 1);
#endif
}
static inline void set_bit(uint32_t *tab, int index)
@@ -140,6 +214,18 @@ static inline void reset_bit(uint32_t *tab, int index)
tab[i] &= ~mask;
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
int i;
for(i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + fls_bit(tab[i]);
}
}
return -1;
}
static int apic_get_ppr(APICState *s)
{
int tpr, isrv, ppr;
@@ -156,16 +242,23 @@ static int apic_get_ppr(APICState *s)
return ppr;
}
static int apic_get_arb_pri(APICState *s)
{
/* XXX: arbitration */
return 0;
}
/* signal the CPU if an irq is pending */
static void apic_update_irq(APICState *s)
{
int irrv, isrv;
int irrv, ppr;
if (!(s->spurious_vec & APIC_SV_ENABLE))
return;
irrv = get_highest_priority_int(s->irr);
if (irrv < 0)
return;
isrv = get_highest_priority_int(s->isr);
/* if the pending irq has less priority, we do not make a new request */
if (isrv >= 0 && irrv >= isrv)
ppr = apic_get_ppr(s);
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
return;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
@@ -187,9 +280,116 @@ static void apic_eoi(APICState *s)
if (isrv < 0)
return;
reset_bit(s->isr, isrv);
/* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
set the remote IRR bit for level triggered interrupts. */
apic_update_irq(s);
}
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
{
uint32_t mask = 0;
APICState *apic_iter;
if (dest_mode == 0) {
if (dest == 0xff)
mask = 0xff;
else
mask = 1 << dest;
} else {
/* XXX: cluster mode */
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (dest & apic_iter->log_dest)
mask |= (1 << apic_iter->id);
}
}
return mask;
}
static void apic_init_ipi(APICState *s)
{
int i;
for(i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = 1 << 16; /* mask LVT */
s->tpr = 0;
s->spurious_vec = 0xff;
s->log_dest = 0;
s->dest_mode = 0;
memset(s->isr, 0, sizeof(s->isr));
memset(s->tmr, 0, sizeof(s->tmr));
memset(s->irr, 0, sizeof(s->irr));
memset(s->lvt, 0, sizeof(s->lvt));
s->esr = 0;
memset(s->icr, 0, sizeof(s->icr));
s->divide_conf = 0;
s->count_shift = 0;
s->initial_count = 0;
s->initial_count_load_time = 0;
s->next_time = 0;
}
static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t polarity, uint8_t trigger_mode)
{
uint32_t deliver_bitmask = 0;
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
/* XXX: serch for focus processor, arbitration */
dest = s->id;
case APIC_DM_INIT:
{
int trig_mode = (s->icr[0] >> 15) & 1;
int level = (s->icr[0] >> 14) & 1;
if (level == 0 && trig_mode == 1) {
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
apic_iter->arb_id = apic_iter->id;
}
}
return;
}
}
break;
case APIC_DM_SIPI:
for (apic_iter = first_local_apic; apic_iter != NULL;
apic_iter = apic_iter->next_apic) {
if (deliver_bitmask & (1 << apic_iter->id)) {
/* XXX: SMP support */
/* apic_startup(apic_iter); */
}
}
return;
}
switch (dest_shorthand) {
case 0:
deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
break;
case 1:
deliver_bitmask = (1 << s->id);
break;
case 2:
deliver_bitmask = 0xffffffff;
break;
case 3:
deliver_bitmask = 0xffffffff & ~(1 << s->id);
break;
}
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
trigger_mode);
}
int apic_get_interrupt(CPUState *env)
{
APICState *s = env->apic_state;
@@ -207,6 +407,8 @@ int apic_get_interrupt(CPUState *env)
if (intno < 0)
return -1;
reset_bit(s->irr, intno);
if (s->tpr && intno <= s->tpr)
return s->spurious_vec & 0xff;
set_bit(s->isr, intno);
apic_update_irq(s);
return intno;
@@ -220,7 +422,7 @@ static uint32_t apic_get_current_count(APICState *s)
s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
/* periodic */
val = s->initial_count - (d % (s->initial_count + 1));
val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
} else {
if (d >= s->initial_count)
val = 0;
@@ -238,11 +440,11 @@ static void apic_timer_update(APICState *s, int64_t current_time)
d = (current_time - s->initial_count_load_time) >>
s->count_shift;
if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);
d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
} else {
if (d >= s->initial_count)
goto no_timer;
d = s->initial_count + 1;
d = (uint64_t)s->initial_count + 1;
}
next_time = s->initial_count_load_time + (d << s->count_shift);
qemu_mod_timer(s->timer, next_time);
@@ -304,10 +506,19 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
case 0x08:
val = s->tpr;
break;
case 0x09:
val = apic_get_arb_pri(s);
break;
case 0x0a:
/* ppr */
val = apic_get_ppr(s);
break;
case 0x0d:
val = s->log_dest << 24;
break;
case 0x0e:
val = s->dest_mode << 28;
break;
case 0x0f:
val = s->spurious_vec;
break;
@@ -372,16 +583,29 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 0x08:
s->tpr = val;
apic_update_irq(s);
break;
case 0x0b: /* EOI */
apic_eoi(s);
break;
case 0x0d:
s->log_dest = val >> 24;
break;
case 0x0e:
s->dest_mode = val >> 28;
break;
case 0x0f:
s->spurious_vec = val & 0x1ff;
apic_update_irq(s);
break;
case 0x30:
s->icr[0] = val;
apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
(s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
(s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
break;
case 0x31:
s->icr[index & 1] = val;
s->icr[1] = val;
break;
case 0x32 ... 0x37:
{
@@ -410,7 +634,76 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
static void apic_save(QEMUFile *f, void *opaque)
{
APICState *s = opaque;
int i;
qemu_put_be32s(f, &s->apicbase);
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->arb_id);
qemu_put_8s(f, &s->tpr);
qemu_put_be32s(f, &s->spurious_vec);
qemu_put_8s(f, &s->log_dest);
qemu_put_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_put_be32s(f, &s->isr[i]);
qemu_put_be32s(f, &s->tmr[i]);
qemu_put_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_put_be32s(f, &s->lvt[i]);
}
qemu_put_be32s(f, &s->esr);
qemu_put_be32s(f, &s->icr[0]);
qemu_put_be32s(f, &s->icr[1]);
qemu_put_be32s(f, &s->divide_conf);
qemu_put_be32s(f, &s->count_shift);
qemu_put_be32s(f, &s->initial_count);
qemu_put_be64s(f, &s->initial_count_load_time);
qemu_put_be64s(f, &s->next_time);
}
static int apic_load(QEMUFile *f, void *opaque, int version_id)
{
APICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
/* XXX: what if the base changes? (registered memory regions) */
qemu_get_be32s(f, &s->apicbase);
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->arb_id);
qemu_get_8s(f, &s->tpr);
qemu_get_be32s(f, &s->spurious_vec);
qemu_get_8s(f, &s->log_dest);
qemu_get_8s(f, &s->dest_mode);
for (i = 0; i < 8; i++) {
qemu_get_be32s(f, &s->isr[i]);
qemu_get_be32s(f, &s->tmr[i]);
qemu_get_be32s(f, &s->irr[i]);
}
for (i = 0; i < APIC_LVT_NB; i++) {
qemu_get_be32s(f, &s->lvt[i]);
}
qemu_get_be32s(f, &s->esr);
qemu_get_be32s(f, &s->icr[0]);
qemu_get_be32s(f, &s->icr[1]);
qemu_get_be32s(f, &s->divide_conf);
qemu_get_be32s(f, &s->count_shift);
qemu_get_be32s(f, &s->initial_count);
qemu_get_be64s(f, &s->initial_count_load_time);
qemu_get_be64s(f, &s->next_time);
return 0;
}
static void apic_reset(void *opaque)
{
APICState *s = opaque;
apic_init_ipi(s);
}
static CPUReadMemoryFunc *apic_mem_read[3] = {
apic_mem_readb,
@@ -427,27 +720,237 @@ static CPUWriteMemoryFunc *apic_mem_write[3] = {
int apic_init(CPUState *env)
{
APICState *s;
int i;
s = malloc(sizeof(APICState));
s = qemu_mallocz(sizeof(APICState));
if (!s)
return -1;
memset(s, 0, sizeof(*s));
env->apic_state = s;
apic_init_ipi(s);
s->id = last_apic_id++;
s->cpu_env = env;
s->apicbase = 0xfee00000 |
MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
for(i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = 1 << 16; /* mask LVT */
s->spurious_vec = 0xff;
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
/* XXX: mapping more APICs at the same memory location */
if (apic_io_memory == 0) {
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
apic_mem_write, NULL);
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
apic_io_memory);
}
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
register_savevm("apic", 0, 1, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
s->next_apic = first_local_apic;
first_local_apic = s;
return 0;
}
static void ioapic_service(IOAPICState *s)
{
uint8_t i;
uint8_t trig_mode;
uint8_t vector;
uint8_t delivery_mode;
uint32_t mask;
uint64_t entry;
uint8_t dest;
uint8_t dest_mode;
uint8_t polarity;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
if (s->irr & mask) {
entry = s->ioredtbl[i];
if (!(entry & APIC_LVT_MASKED)) {
trig_mode = ((entry >> 15) & 1);
dest = entry >> 56;
dest_mode = (entry >> 11) & 1;
delivery_mode = (entry >> 8) & 7;
polarity = (entry >> 13) & 1;
if (trig_mode == APIC_TRIGGER_EDGE)
s->irr &= ~mask;
if (delivery_mode == APIC_DM_EXTINT)
vector = pic_read_irq(isa_pic);
else
vector = entry & 0xff;
apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
delivery_mode, vector, polarity, trig_mode);
}
}
}
}
void ioapic_set_irq(void *opaque, int vector, int level)
{
IOAPICState *s = opaque;
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
if ((entry >> 15) & 1) {
/* level triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
} else {
s->irr &= ~mask;
}
} else {
/* edge triggered */
if (level) {
s->irr |= mask;
ioapic_service(s);
}
}
}
}
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
{
IOAPICState *s = opaque;
int index;
uint32_t val = 0;
addr &= 0xff;
if (addr == 0x00) {
val = s->ioregsel;
} else if (addr == 0x10) {
switch (s->ioregsel) {
case 0x00:
val = s->id << 24;
break;
case 0x01:
val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
break;
case 0x02:
val = 0;
break;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1)
val = s->ioredtbl[index] >> 32;
else
val = s->ioredtbl[index] & 0xffffffff;
}
}
#ifdef DEBUG_IOAPIC
printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
#endif
}
return val;
}
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOAPICState *s = opaque;
int index;
addr &= 0xff;
if (addr == 0x00) {
s->ioregsel = val;
return;
} else if (addr == 0x10) {
#ifdef DEBUG_IOAPIC
printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
#endif
switch (s->ioregsel) {
case 0x00:
s->id = (val >> 24) & 0xff;
return;
case 0x01:
case 0x02:
return;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
} else {
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
ioapic_service(s);
}
}
}
}
static void ioapic_save(QEMUFile *f, void *opaque)
{
IOAPICState *s = opaque;
int i;
qemu_put_8s(f, &s->id);
qemu_put_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_put_be64s(f, &s->ioredtbl[i]);
}
}
static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
{
IOAPICState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->id);
qemu_get_8s(f, &s->ioregsel);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
qemu_get_be64s(f, &s->ioredtbl[i]);
}
return 0;
}
static void ioapic_reset(void *opaque)
{
IOAPICState *s = opaque;
int i;
memset(s, 0, sizeof(*s));
for(i = 0; i < IOAPIC_NUM_PINS; i++)
s->ioredtbl[i] = 1 << 16; /* mask LVT */
}
static CPUReadMemoryFunc *ioapic_mem_read[3] = {
ioapic_mem_readl,
ioapic_mem_readl,
ioapic_mem_readl,
};
static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
ioapic_mem_writel,
ioapic_mem_writel,
ioapic_mem_writel,
};
IOAPICState *ioapic_init(void)
{
IOAPICState *s;
int io_memory;
s = qemu_mallocz(sizeof(IOAPICState));
if (!s)
return NULL;
ioapic_reset(s);
s->id = last_apic_id++;
io_memory = cpu_register_io_memory(0, ioapic_mem_read,
ioapic_mem_write, s);
cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
qemu_register_reset(ioapic_reset, s);
return s;
}

View File

@@ -61,8 +61,8 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
pattern_pitch = 32;
#endif
pattern_y = s->cirrus_blt_srcaddr & 7;
pattern_x = skipleft;
for(y = 0; y < bltheight; y++) {
pattern_x = skipleft;
d = dst + skipleft;
src1 = src + pattern_y * pattern_pitch;
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {

View File

@@ -23,6 +23,8 @@
*/
#include "vl.h"
/* XXX: implement all timer modes */
//#define DEBUG_CUDA
//#define DEBUG_CUDA_PACKET
@@ -41,6 +43,7 @@
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
#define T1_INT 0x40 /* Timer 1 interrupt */
#define T2_INT 0x20 /* Timer 2 interrupt */
/* Bits in ACR */
#define T1MODE 0xc0 /* Timer 1 mode */
@@ -91,7 +94,8 @@
#define RTC_OFFSET 2082844800
typedef struct CUDATimer {
unsigned int latch;
int index;
uint16_t latch;
uint16_t counter_value; /* counter value at load time */
int64_t load_time;
int64_t next_irq_time;
@@ -120,8 +124,9 @@ typedef struct CUDAState {
int data_in_index;
int data_out_index;
SetIRQFunc *set_irq;
int irq;
openpic_t *openpic;
void *irq_opaque;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
@@ -140,9 +145,9 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
static void cuda_update_irq(CUDAState *s)
{
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
openpic_set_irq(s->openpic, s->irq, 1);
s->set_irq(s->irq_opaque, s->irq, 1);
} else {
openpic_set_irq(s->openpic, s->irq, 0);
s->set_irq(s->irq_opaque, s->irq, 0);
}
}
@@ -153,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s)
d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (d <= s->counter_value) {
counter = d;
if (s->index == 0) {
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
}
} else {
counter = s->latch - 1 - ((d - s->counter_value) % s->latch);
counter = (s->counter_value - d) & 0xffff;
}
return counter;
}
@@ -174,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
{
int64_t d, next_time, base;
int64_t d, next_time;
unsigned int counter;
/* current counter value */
d = muldiv64(current_time - s->load_time,
CUDA_TIMER_FREQ, ticks_per_sec);
if (d < s->counter_value) {
next_time = s->counter_value + 1;
} else
{
base = ((d - s->counter_value + 1) / s->latch);
base = (base * s->latch) + s->counter_value;
next_time = base + s->latch;
/* the timer goes down from latch to -1 (period of latch + 2) */
if (d <= (s->counter_value + 1)) {
counter = (s->counter_value - d) & 0xffff;
} else {
counter = (d - (s->counter_value + 1)) % (s->latch + 2);
counter = (s->latch - counter) & 0xffff;
}
/* Note: we consider the irq is raised on 0 */
if (counter == 0xffff) {
next_time = d + s->latch + 1;
} else if (counter == 0) {
next_time = d + s->latch + 2;
} else {
next_time = d + counter;
}
#if 0
#ifdef DEBUG_CUDA
@@ -248,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
break;
case 5:
val = get_counter(&s->timers[0]) >> 8;
s->ifr &= ~T1_INT;
cuda_update_irq(s);
break;
case 6:
val = s->timers[0].latch & 0xff;
break;
case 7:
/* XXX: check this */
val = (s->timers[0].latch >> 8) & 0xff;
break;
case 8:
val = get_counter(&s->timers[1]) & 0xff;
s->ifr &= ~T2_INT;
break;
case 9:
val = get_counter(&s->timers[1]) >> 8;
@@ -276,9 +298,11 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
break;
case 13:
val = s->ifr;
if (s->ifr & s->ier)
val |= 0x80;
break;
case 14:
val = s->ier;
val = s->ier | 0x80;
break;
default:
case 15:
@@ -316,12 +340,13 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
s->dira = val;
break;
case 4:
val = val | (get_counter(&s->timers[0]) & 0xff00);
set_counter(s, &s->timers[0], val);
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 5:
val = (val << 8) | (get_counter(&s->timers[0]) & 0xff);
set_counter(s, &s->timers[0], val);
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
set_counter(s, &s->timers[0], s->timers[0].latch);
break;
case 6:
s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
@@ -329,15 +354,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 7:
s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
s->ifr &= ~T1_INT;
cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
break;
case 8:
val = val | (get_counter(&s->timers[1]) & 0xff00);
s->timers[1].latch = val;
set_counter(s, &s->timers[1], val);
break;
case 9:
val = (val << 8) | (get_counter(&s->timers[1]) & 0xff);
set_counter(s, &s->timers[1], val);
set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
break;
case 10:
s->sr = val;
@@ -545,7 +570,7 @@ static void cuda_receive_packet_from_host(CUDAState *s,
#ifdef DEBUG_CUDA_PACKET
{
int i;
printf("cuda_receive_packet_to_host:\n");
printf("cuda_receive_packet_from_host:\n");
for(i = 0; i < len; i++)
printf(" %02x", data[i]);
printf("\n");
@@ -605,19 +630,24 @@ static CPUReadMemoryFunc *cuda_read[] = {
&cuda_readl,
};
int cuda_init(openpic_t *openpic, int irq)
int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
s->openpic = openpic;
s->set_irq = set_irq;
s->irq_opaque = irq_opaque;
s->irq = irq;
s->timers[0].index = 0;
s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
s->timers[0].latch = 0x10000;
s->timers[0].latch = 0xffff;
set_counter(s, &s->timers[0], 0xffff);
s->timers[1].latch = 0x10000;
s->ier = T1_INT | SR_INT;
s->timers[1].index = 1;
s->timers[1].latch = 0;
// s->ier = T1_INT | SR_INT;
s->ier = 0;
set_counter(s, &s->timers[1], 0xffff);
s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);

218
hw/elf_ops.h Normal file
View File

@@ -0,0 +1,218 @@
#ifdef BSWAP_NEEDED
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
bswap16s(&ehdr->e_machine); /* Architecture */
bswap32s(&ehdr->e_version); /* Object file version */
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
bswapSZs(&phdr->p_offset); /* Segment file offset */
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
bswapSZs(&phdr->p_paddr); /* Segment physical address */
bswapSZs(&phdr->p_filesz); /* Segment size in file */
bswapSZs(&phdr->p_memsz); /* Segment size in memory */
bswap32s(&phdr->p_flags); /* Segment flags */
bswapSZs(&phdr->p_align); /* Segment alignment */
}
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswapSZs(&shdr->sh_flags);
bswapSZs(&shdr->sh_addr);
bswapSZs(&shdr->sh_offset);
bswapSZs(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswapSZs(&shdr->sh_addralign);
bswapSZs(&shdr->sh_entsize);
}
static void glue(bswap_sym, SZ)(struct elf_sym *sym)
{
bswap32s(&sym->st_name);
bswapSZs(&sym->st_value);
bswapSZs(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
if (retval < 0)
return -1;
for (i = 0; i < ehdr->e_phnum; i++) {
retval = read(fd, phdr, sizeof(*phdr));
if (retval < 0)
return -1;
glue(bswap_phdr, SZ)(phdr);
if (phdr->p_type == type)
return 0;
}
return -1;
}
static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
int i, retval;
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
if (retval < 0)
return NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == type)
return qemu_malloc(shdr->sh_size);
}
return NULL;
}
static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
return NULL;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
glue(bswap_shdr, SZ)(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
return NULL;
}
static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry)
{
int retval;
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
}
static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst)
{
int retval;
retval = lseek(fd, s->sh_offset, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, dst, s->sh_size);
if (retval < 0)
return -1;
return 0;
}
static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type)
{
void *dst;
dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab);
if (!dst)
goto error;
if (glue(read_section, SZ)(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
#if (SZ == 64)
struct elf32_sym *syms32;
#endif
struct syminfo *s;
int nsyms, i;
char *str;
/* Symbol table */
syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB);
if (!syms)
return;
nsyms = symtab.sh_size / sizeof(struct elf_sym);
#if (SZ == 64)
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
#endif
for (i = 0; i < nsyms; i++) {
glue(bswap_sym, SZ)(&syms[i]);
#if (SZ == 64)
syms32[i].st_name = syms[i].st_name;
syms32[i].st_info = syms[i].st_info;
syms32[i].st_other = syms[i].st_other;
syms32[i].st_shndx = syms[i].st_shndx;
syms32[i].st_value = syms[i].st_value & 0xffffffff;
syms32[i].st_size = syms[i].st_size & 0xffffffff;
#endif
}
/* String table */
str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab);
if (!str)
goto error_freesyms;
/* Commit */
s = qemu_mallocz(sizeof(*s));
#if (SZ == 64)
s->disas_symtab = syms32;
qemu_free(syms);
#else
s->disas_symtab = syms;
#endif
s->disas_num_syms = nsyms;
s->disas_strtab = str;
s->next = syminfos;
syminfos = s;
return;
error_freesyms:
#if (SZ == 64)
qemu_free(syms32);
#endif
qemu_free(syms);
return;
}

168
hw/heathrow_pic.c Normal file
View File

@@ -0,0 +1,168 @@
/*
* Heathrow PIC support (standard PowerMac PIC)
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG
typedef struct HeathrowPIC {
uint32_t events;
uint32_t mask;
uint32_t levels;
uint32_t level_triggered;
} HeathrowPIC;
struct HeathrowPICS {
HeathrowPIC pics[2];
};
static inline int check_irq(HeathrowPIC *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
static void heathrow_pic_update(HeathrowPICS *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
value = bswap32(value);
#ifdef DEBUG
printf("pic_writel: %08x: %08x\n",
addr, value);
#endif
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
heathrow_pic_update(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
heathrow_pic_update(s);
break;
default:
break;
}
}
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int n;
uint32_t value;
n = ((addr & 0xfff) - 0x10) >> 4;
if (n >= 2) {
value = 0;
} else {
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x0:
value = pic->events;
break;
case 0x4:
value = pic->mask;
break;
case 0xc:
value = pic->levels;
break;
default:
value = 0;
break;
}
}
#ifdef DEBUG
printf("pic_readl: %08x: %08x\n",
addr, value);
#endif
value = bswap32(value);
return value;
}
static CPUWriteMemoryFunc *pic_write[] = {
&pic_writel,
&pic_writel,
&pic_writel,
};
static CPUReadMemoryFunc *pic_read[] = {
&pic_readl,
&pic_readl,
&pic_readl,
};
void heathrow_pic_set_irq(void *opaque, int num, int level)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
unsigned int irq_bit;
#if defined(DEBUG)
{
static int last_level[64];
if (last_level[num] != level) {
printf("set_irq: num=0x%02x level=%d\n", num, level);
last_level[num] = level;
}
}
#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
heathrow_pic_update(s);
}
HeathrowPICS *heathrow_pic_init(int *pmem_index)
{
HeathrowPICS *s;
s = qemu_mallocz(sizeof(HeathrowPICS));
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
return s;
}

View File

@@ -46,10 +46,19 @@ typedef struct PicState {
uint8_t init4; /* true if 4 byte init */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
PicState2 *pics_state;
} PicState;
/* 0 is master pic, 1 is slave pic */
static PicState pics[2];
struct PicState2 {
/* 0 is master pic, 1 is slave pic */
/* XXX: better separation between the two pics */
PicState pics[2];
IRQRequestFunc *irq_request;
void *irq_request_opaque;
/* IOAPIC callback support */
SetIRQFunc *alt_irq_func;
void *alt_irq_opaque;
};
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
static int irq_level[16];
@@ -110,7 +119,7 @@ static int pic_get_irq(PicState *s)
master, the IRQ coming from the slave is not taken into account
for the priority computation. */
mask = s->isr;
if (s->special_fully_nested_mode && s == &pics[0])
if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
mask &= ~(1 << 2);
cur_priority = get_priority(s, mask);
if (priority < cur_priority) {
@@ -123,32 +132,34 @@ static int pic_get_irq(PicState *s)
/* raise irq to CPU if necessary. must be called every time the active
irq may change */
static void pic_update_irq(void)
/* XXX: should not export it, but it is needed for an APIC kludge */
void pic_update_irq(PicState2 *s)
{
int irq2, irq;
/* first look at slave pic */
irq2 = pic_get_irq(&pics[1]);
irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) {
/* if irq request by slave pic, signal master PIC */
pic_set_irq1(&pics[0], 2, 1);
pic_set_irq1(&pics[0], 2, 0);
pic_set_irq1(&s->pics[0], 2, 1);
pic_set_irq1(&s->pics[0], 2, 0);
}
/* look at requested irq */
irq = pic_get_irq(&pics[0]);
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
#if defined(DEBUG_PIC)
{
int i;
for(i = 0; i < 2; i++) {
printf("pic%d: imr=%x irr=%x padd=%d\n",
i, pics[i].imr, pics[i].irr, pics[i].priority_add);
i, s->pics[i].imr, s->pics[i].irr,
s->pics[i].priority_add);
}
}
printf("pic: cpu_interrupt\n");
#endif
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
s->irq_request(s->irq_request_opaque, 1);
}
}
@@ -156,8 +167,10 @@ static void pic_update_irq(void)
int64_t irq_time[16];
#endif
void pic_set_irq(int irq, int level)
void pic_set_irq_new(void *opaque, int irq, int level)
{
PicState2 *s = opaque;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
@@ -175,8 +188,17 @@ void pic_set_irq(int irq, int level)
irq_time[irq] = qemu_get_clock(vm_clock);
}
#endif
pic_set_irq1(&pics[irq >> 3], irq & 7, level);
pic_update_irq();
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
/* used for IOAPIC irqs */
if (s->alt_irq_func)
s->alt_irq_func(s->alt_irq_opaque, irq, level);
pic_update_irq(s);
}
/* obsolete function */
void pic_set_irq(int irq, int level)
{
pic_set_irq_new(isa_pic, irq, level);
}
/* acknowledge interrupt 'irq' */
@@ -193,43 +215,32 @@ static inline void pic_intack(PicState *s, int irq)
s->irr &= ~(1 << irq);
}
int cpu_get_pic_interrupt(CPUState *env)
int pic_read_irq(PicState2 *s)
{
int irq, irq2, intno;
#ifdef TARGET_X86_64
intno = apic_get_interrupt(env);
if (intno >= 0) {
/* set irq request if a PIC irq is still pending */
/* XXX: improve that */
pic_update_irq();
return intno;
}
#endif
/* read the irq from the PIC */
irq = pic_get_irq(&pics[0]);
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
pic_intack(&pics[0], irq);
pic_intack(&s->pics[0], irq);
if (irq == 2) {
irq2 = pic_get_irq(&pics[1]);
irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) {
pic_intack(&pics[1], irq2);
pic_intack(&s->pics[1], irq2);
} else {
/* spurious IRQ on slave controller */
irq2 = 7;
}
intno = pics[1].irq_base + irq2;
intno = s->pics[1].irq_base + irq2;
irq = irq2 + 8;
} else {
intno = pics[0].irq_base + irq;
intno = s->pics[0].irq_base + irq;
}
} else {
/* spurious IRQ on host controller */
irq = 7;
intno = pics[0].irq_base + irq;
intno = s->pics[0].irq_base + irq;
}
pic_update_irq();
pic_update_irq(s);
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
@@ -245,11 +256,22 @@ int cpu_get_pic_interrupt(CPUState *env)
static void pic_reset(void *opaque)
{
PicState *s = opaque;
int tmp;
tmp = s->elcr_mask;
memset(s, 0, sizeof(PicState));
s->elcr_mask = tmp;
s->last_irr = 0;
s->irr = 0;
s->imr = 0;
s->isr = 0;
s->priority_add = 0;
s->irq_base = 0;
s->read_reg_select = 0;
s->poll = 0;
s->special_mask = 0;
s->init_state = 0;
s->auto_eoi = 0;
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
s->elcr = 0;
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -266,8 +288,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* init */
pic_reset(s);
/* deassert a pending interrupt */
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
s->init_state = 1;
s->init4 = val & 1;
if (val & 0x02)
@@ -296,23 +317,23 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->isr &= ~(1 << irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
pic_update_irq();
pic_update_irq(s->pics_state);
}
break;
case 3:
irq = val & 7;
s->isr &= ~(1 << irq);
pic_update_irq();
pic_update_irq(s->pics_state);
break;
case 6:
s->priority_add = (val + 1) & 7;
pic_update_irq();
pic_update_irq(s->pics_state);
break;
case 7:
irq = val & 7;
s->isr &= ~(1 << irq);
s->priority_add = (irq + 1) & 7;
pic_update_irq();
pic_update_irq(s->pics_state);
break;
default:
/* no operation */
@@ -324,7 +345,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case 0:
/* normal mode */
s->imr = val;
pic_update_irq();
pic_update_irq(s->pics_state);
break;
case 1:
s->irq_base = val & 0xf8;
@@ -353,16 +374,16 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
ret = pic_get_irq(s);
if (ret >= 0) {
if (addr1 >> 7) {
pics[0].isr &= ~(1 << 2);
pics[0].irr &= ~(1 << 2);
s->pics_state->pics[0].isr &= ~(1 << 2);
s->pics_state->pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
if (addr1 >> 7 || ret != 2)
pic_update_irq();
pic_update_irq(s->pics_state);
} else {
ret = 0x07;
pic_update_irq();
pic_update_irq(s->pics_state);
}
return ret;
@@ -396,15 +417,16 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
}
/* memory mapped interrupt status */
uint32_t pic_intack_read(CPUState *env)
/* XXX: may be the same than pic_read_irq() */
uint32_t pic_intack_read(PicState2 *s)
{
int ret;
ret = pic_poll_read(&pics[0], 0x00);
ret = pic_poll_read(&s->pics[0], 0x00);
if (ret == 2)
ret = pic_poll_read(&pics[1], 0x80) + 8;
ret = pic_poll_read(&s->pics[1], 0x80) + 8;
/* Prepare for ISR read */
pics[0].read_reg_select = 1;
s->pics[0].read_reg_select = 1;
return ret;
}
@@ -484,9 +506,12 @@ void pic_info(void)
{
int i;
PicState *s;
if (!isa_pic)
return;
for(i=0;i<2;i++) {
s = &pics[i];
s = &isa_pic->pics[i];
term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
s->irq_base, s->read_reg_select, s->elcr,
@@ -511,11 +536,26 @@ void irq_info(void)
#endif
}
void pic_init(void)
PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
{
pic_init1(0x20, 0x4d0, &pics[0]);
pic_init1(0xa0, 0x4d1, &pics[1]);
pics[0].elcr_mask = 0xf8;
pics[1].elcr_mask = 0xde;
PicState2 *s;
s = qemu_mallocz(sizeof(PicState2));
if (!s)
return NULL;
pic_init1(0x20, 0x4d0, &s->pics[0]);
pic_init1(0xa0, 0x4d1, &s->pics[1]);
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
s->irq_request = irq_request;
s->irq_request_opaque = irq_request_opaque;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
return s;
}
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
void *alt_irq_opaque)
{
s->alt_irq_func = alt_irq_func;
s->alt_irq_opaque = alt_irq_opaque;
}

273
hw/ide.c
View File

@@ -296,8 +296,9 @@ typedef struct IDEState {
int cylinders, heads, sectors;
int64_t nb_sectors;
int mult_sectors;
SetIRQFunc *set_irq;
void *irq_opaque;
int irq;
openpic_t *openpic;
PCIDevice *pci_dev;
struct BMDMAState *bmdma;
int drive_serial;
@@ -332,6 +333,7 @@ typedef struct IDEState {
uint8_t *data_ptr;
uint8_t *data_end;
uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
} IDEState;
#define BM_STATUS_DMAING 0x01
@@ -341,6 +343,18 @@ typedef struct IDEState {
#define BM_CMD_START 0x01
#define BM_CMD_READ 0x08
#define IDE_TYPE_PIIX3 0
#define IDE_TYPE_CMD646 1
/* CMD646 specific */
#define MRDMODE 0x71
#define MRDMODE_INTR_CH0 0x04
#define MRDMODE_INTR_CH1 0x08
#define MRDMODE_BLK_CH0 0x10
#define MRDMODE_BLK_CH1 0x20
#define UDIDETCR0 0x73
#define UDIDETCR1 0x7B
typedef int IDEDMAFunc(IDEState *s,
target_phys_addr_t phys_addr,
int transfer_size1);
@@ -349,6 +363,8 @@ typedef struct BMDMAState {
uint8_t cmd;
uint8_t status;
uint32_t addr;
struct PCIIDEState *pci_dev;
/* current transfer state */
IDEState *ide_if;
IDEDMAFunc *dma_cb;
@@ -358,6 +374,7 @@ typedef struct PCIIDEState {
PCIDevice dev;
IDEState ide_if[4];
BMDMAState bmdma[2];
int type; /* see IDE_TYPE_xxx */
} PCIIDEState;
static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
@@ -499,16 +516,12 @@ static inline void ide_abort_command(IDEState *s)
static inline void ide_set_irq(IDEState *s)
{
BMDMAState *bm = s->bmdma;
if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
#ifdef TARGET_PPC
if (s->openpic)
openpic_set_irq(s->openpic, s->irq, 1);
else
#endif
if (s->irq == 16)
pci_set_irq(s->pci_dev, 0, 1);
else
pic_set_irq(s->irq, 1);
if (bm) {
bm->status |= BM_STATUS_INT;
}
s->set_irq(s->irq_opaque, s->irq, 1);
}
}
@@ -642,6 +655,12 @@ static void ide_sector_read_dma(IDEState *s)
ide_dma_start(s, ide_read_dma_cb);
}
static void ide_sector_write_timer_cb(void *opaque)
{
IDEState *s = opaque;
ide_set_irq(s);
}
static void ide_sector_write(IDEState *s)
{
int64_t sector_num;
@@ -667,7 +686,22 @@ static void ide_sector_write(IDEState *s)
ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
}
ide_set_sector(s, sector_num + n);
ide_set_irq(s);
#ifdef TARGET_I386
if (win2k_install_hack) {
/* It seems there is a bug in the Windows 2000 installer HDD
IDE driver which fills the disk with empty logs when the
IDE write IRQ comes too early. This hack tries to correct
that at the expense of slower write performances. Use this
option _only_ to install Windows 2000. You must disable it
for normal use. */
qemu_mod_timer(s->sector_write_timer,
qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
} else
#endif
{
ide_set_irq(s);
}
}
static int ide_write_dma_cb(IDEState *s,
@@ -789,7 +823,8 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
case 2352:
/* sync bytes */
buf[0] = 0x00;
memset(buf + 1, 0xff, 11);
memset(buf + 1, 0xff, 10);
buf[11] = 0x00;
buf += 12;
/* MSF */
lba_to_msf(buf, lba);
@@ -917,6 +952,9 @@ static int ide_atapi_cmd_read_dma_cb(IDEState *s,
transfer_size = transfer_size1;
while (transfer_size > 0) {
#ifdef DEBUG_IDE_ATAPI
printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);
#endif
if (s->packet_transfer_size <= 0)
break;
len = s->cd_sector_size - s->io_buffer_index;
@@ -994,9 +1032,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
*q++ = 0; /* minute */
*q++ = 2; /* second */
*q++ = 0; /* frame */
lba_to_msf(q, 0);
q += 3;
} else {
/* sector 0 */
cpu_to_ube32(q, 0);
@@ -1081,10 +1118,16 @@ static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 0;
*q++ = 0;
*q++ = 0;
if (msf) {
*q++ = 0;
lba_to_msf(q, 0);
q += 3;
} else {
*q++ = 0;
*q++ = 0;
*q++ = 0;
*q++ = 0;
}
len = q - buf;
cpu_to_ube16(buf, len - 2);
@@ -1571,6 +1614,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
break;
case WIN_STANDBYNOW1:
case WIN_IDLEIMMEDIATE:
case WIN_FLUSH_CACHE:
s->status = READY_STAT;
ide_set_irq(s);
break;
@@ -1672,15 +1716,7 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
ret = 0;
else
ret = s->status;
#ifdef TARGET_PPC
if (s->openpic)
openpic_set_irq(s->openpic, s->irq, 0);
else
#endif
if (s->irq == 16)
pci_set_irq(s->pci_dev, 0, 0);
else
pic_set_irq(s->irq, 0);
s->set_irq(s->irq_opaque, s->irq, 0);
break;
}
#ifdef DEBUG_IDE
@@ -1873,8 +1909,9 @@ static int guess_disk_lchs(IDEState *s,
return -1;
}
static void ide_init2(IDEState *ide_state, int irq,
BlockDriverState *hd0, BlockDriverState *hd1)
static void ide_init2(IDEState *ide_state,
BlockDriverState *hd0, BlockDriverState *hd1,
SetIRQFunc *set_irq, void *irq_opaque, int irq)
{
IDEState *s;
static int drive_serial = 1;
@@ -1935,7 +1972,11 @@ static void ide_init2(IDEState *ide_state, int irq,
}
}
s->drive_serial = drive_serial++;
s->set_irq = set_irq;
s->irq_opaque = irq_opaque;
s->irq = irq;
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
ide_reset(s);
}
}
@@ -1968,13 +2009,15 @@ void isa_ide_init(int iobase, int iobase2, int irq,
if (!ide_state)
return;
ide_init2(ide_state, irq, hd0, hd1);
ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
ide_init_ioport(ide_state, iobase, iobase2);
}
/***********************************************************/
/* PCI IDE definitions */
static void cmd646_update_irq(PCIIDEState *d);
static void ide_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
@@ -2055,17 +2098,6 @@ static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
}
}
static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr)
{
BMDMAState *bm = opaque;
uint32_t val;
val = bm->cmd;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
return val;
}
static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
@@ -2085,24 +2117,77 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
}
}
static uint32_t bmdma_status_readb(void *opaque, uint32_t addr)
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
{
BMDMAState *bm = opaque;
PCIIDEState *pci_dev;
uint32_t val;
val = bm->status;
switch(addr & 3) {
case 0:
val = bm->cmd;
break;
case 1:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
val = pci_dev->dev.config[MRDMODE];
} else {
val = 0xff;
}
break;
case 2:
val = bm->status;
break;
case 3:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
if (bm == &pci_dev->bmdma[0])
val = pci_dev->dev.config[UDIDETCR0];
else
val = pci_dev->dev.config[UDIDETCR1];
} else {
val = 0xff;
}
break;
default:
val = 0xff;
break;
}
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
#endif
return val;
}
static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val)
static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
PCIIDEState *pci_dev;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
#endif
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
switch(addr & 3) {
case 1:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
pci_dev->dev.config[MRDMODE] =
(pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
cmd646_update_irq(pci_dev);
}
break;
case 2:
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
break;
case 3:
pci_dev = bm->pci_dev;
if (pci_dev->type == IDE_TYPE_CMD646) {
if (bm == &pci_dev->bmdma[0])
pci_dev->dev.config[UDIDETCR0] = val;
else
pci_dev->dev.config[UDIDETCR1] = val;
}
break;
}
}
static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
@@ -2135,12 +2220,12 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
BMDMAState *bm = &d->bmdma[i];
d->ide_if[2 * i].bmdma = bm;
d->ide_if[2 * i + 1].bmdma = bm;
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm);
bm->pci_dev = (PCIIDEState *)pci_dev;
register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm);
register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm);
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm);
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
@@ -2148,29 +2233,62 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
}
}
/* hd_table must contain 4 block drivers */
void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table)
/* XXX: call it also when the MRDMODE is changed from the PCI config
registers */
static void cmd646_update_irq(PCIIDEState *d)
{
int pci_level;
pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
pci_set_irq((PCIDevice *)d, 0, pci_level);
}
/* the PCI irq level is the logical OR of the two channels */
static void cmd646_set_irq(void *opaque, int channel, int level)
{
PCIIDEState *d = opaque;
int irq_mask;
irq_mask = MRDMODE_INTR_CH0 << channel;
if (level)
d->dev.config[MRDMODE] |= irq_mask;
else
d->dev.config[MRDMODE] &= ~irq_mask;
cmd646_update_irq(d);
}
/* CMD646 PCI IDE controller */
void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
int secondary_ide_enabled)
{
PCIIDEState *d;
uint8_t *pci_conf;
int i;
d = (PCIIDEState *)pci_register_device(bus, "IDE", sizeof(PCIIDEState),
d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
sizeof(PCIIDEState),
-1,
NULL, NULL);
d->type = IDE_TYPE_CMD646;
pci_conf = d->dev.config;
pci_conf[0x00] = 0x86; // Intel
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x00; // fake
pci_conf[0x03] = 0x01; // fake
pci_conf[0x00] = 0x95; // CMD646
pci_conf[0x01] = 0x10;
pci_conf[0x02] = 0x46;
pci_conf[0x03] = 0x06;
pci_conf[0x08] = 0x07; // IDE controller revision
pci_conf[0x09] = 0x8f;
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
pci_conf[0x2c] = 0x86; // subsys vendor
pci_conf[0x2d] = 0x80; // subsys vendor
pci_conf[0x2e] = 0x00; // fake
pci_conf[0x2f] = 0x01; // fake
pci_conf[0x0e] = 0x00; // header_type
if (secondary_ide_enabled) {
/* XXX: if not enabled, really disable the seconday IDE controller */
pci_conf[0x51] = 0x80; /* enable IDE1 */
}
pci_register_io_region((PCIDevice *)d, 0, 0x8,
PCI_ADDRESS_SPACE_IO, ide_map);
@@ -2184,11 +2302,13 @@ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table)
PCI_ADDRESS_SPACE_IO, bmdma_map);
pci_conf[0x3d] = 0x01; // interrupt on pin 1
for(i = 0; i < 4; i++)
d->ide_if[i].pci_dev = (PCIDevice *)d;
ide_init2(&d->ide_if[0], 16, hd_table[0], hd_table[1]);
ide_init2(&d->ide_if[2], 16, hd_table[2], hd_table[3]);
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
cmd646_set_irq, d, 0);
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
cmd646_set_irq, d, 1);
}
/* hd_table must contain 4 block drivers */
@@ -2203,6 +2323,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
sizeof(PCIIDEState),
((PCIDevice *)piix3_state)->devfn + 1,
NULL, NULL);
d->type = IDE_TYPE_PIIX3;
pci_conf = d->dev.config;
pci_conf[0x00] = 0x86; // Intel
pci_conf[0x01] = 0x80;
@@ -2215,8 +2337,10 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
pci_register_io_region((PCIDevice *)d, 4, 0x10,
PCI_ADDRESS_SPACE_IO, bmdma_map);
ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]);
ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]);
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
pic_set_irq_new, isa_pic, 14);
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
pic_set_irq_new, isa_pic, 15);
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
}
@@ -2334,15 +2458,14 @@ static CPUReadMemoryFunc *pmac_ide_read[] = {
/* PowerMac uses memory mapped registers, not I/O. Return the memory
I/O index to access the ide. */
int pmac_ide_init (BlockDriverState **hd_table,
openpic_t *openpic, int irq)
SetIRQFunc *set_irq, void *irq_opaque, int irq)
{
IDEState *ide_if;
int pmac_ide_memory;
ide_if = qemu_mallocz(sizeof(IDEState) * 2);
ide_init2(&ide_if[0], irq, hd_table[0], hd_table[1]);
ide_if[0].openpic = openpic;
ide_if[1].openpic = openpic;
ide_init2(&ide_if[0], hd_table[0], hd_table[1],
set_irq, irq_opaque, irq);
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
pmac_ide_write, &ide_if[0]);

View File

@@ -56,213 +56,49 @@ static void bswap_ahdr(struct exec *e)
#include "elf.h"
#ifdef BSWAP_NEEDED
static void bswap_ehdr(Elf32_Ehdr *ehdr)
{
bswap16s(&ehdr->e_type); /* Object file type */
bswap16s(&ehdr->e_machine); /* Architecture */
bswap32s(&ehdr->e_version); /* Object file version */
bswap32s(&ehdr->e_entry); /* Entry point virtual address */
bswap32s(&ehdr->e_phoff); /* Program header table file offset */
bswap32s(&ehdr->e_shoff); /* Section header table file offset */
bswap32s(&ehdr->e_flags); /* Processor-specific flags */
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
bswap16s(&ehdr->e_phnum); /* Program header table entry count */
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
bswap16s(&ehdr->e_shnum); /* Section header table entry count */
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
}
static void bswap_phdr(Elf32_Phdr *phdr)
{
bswap32s(&phdr->p_type); /* Segment type */
bswap32s(&phdr->p_offset); /* Segment file offset */
bswap32s(&phdr->p_vaddr); /* Segment virtual address */
bswap32s(&phdr->p_paddr); /* Segment physical address */
bswap32s(&phdr->p_filesz); /* Segment size in file */
bswap32s(&phdr->p_memsz); /* Segment size in memory */
bswap32s(&phdr->p_flags); /* Segment flags */
bswap32s(&phdr->p_align); /* Segment alignment */
}
static void bswap_shdr(Elf32_Shdr *shdr)
{
bswap32s(&shdr->sh_name);
bswap32s(&shdr->sh_type);
bswap32s(&shdr->sh_flags);
bswap32s(&shdr->sh_addr);
bswap32s(&shdr->sh_offset);
bswap32s(&shdr->sh_size);
bswap32s(&shdr->sh_link);
bswap32s(&shdr->sh_info);
bswap32s(&shdr->sh_addralign);
bswap32s(&shdr->sh_entsize);
}
static void bswap_sym(Elf32_Sym *sym)
{
bswap32s(&sym->st_name);
bswap32s(&sym->st_value);
bswap32s(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#else
#define bswap_ehdr(e) do { } while (0)
#define bswap_phdr(e) do { } while (0)
#define bswap_shdr(e) do { } while (0)
#define bswap_sym(e) do { } while (0)
#ifndef BSWAP_NEEDED
#define bswap_ehdr32(e) do { } while (0)
#define bswap_phdr32(e) do { } while (0)
#define bswap_shdr32(e) do { } while (0)
#define bswap_sym32(e) do { } while (0)
#ifdef TARGET_SPARC64
#define bswap_ehdr64(e) do { } while (0)
#define bswap_phdr64(e) do { } while (0)
#define bswap_shdr64(e) do { } while (0)
#define bswap_sym64(e) do { } while (0)
#endif
#endif
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type)
{
int i, retval;
#define SZ 32
#define elf_word uint32_t
#define bswapSZs bswap32s
#include "elf_ops.h"
retval = lseek(fd, ehdr->e_phoff, SEEK_SET);
if (retval < 0)
return -1;
for (i = 0; i < ehdr->e_phnum; i++) {
retval = read(fd, phdr, sizeof(*phdr));
if (retval < 0)
return -1;
bswap_phdr(phdr);
if (phdr->p_type == type)
return 0;
}
return -1;
}
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
{
int i, retval;
retval = lseek(fd, ehdr->e_shoff, SEEK_SET);
if (retval < 0)
return NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
bswap_shdr(shdr);
if (shdr->sh_type == type)
return qemu_malloc(shdr->sh_size);
}
return NULL;
}
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
return NULL;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
return NULL;
bswap_shdr(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
return NULL;
}
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
{
int retval;
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
}
static int read_section(int fd, struct elf_shdr *s, void *dst)
{
int retval;
retval = lseek(fd, s->sh_offset, SEEK_SET);
if (retval < 0)
return -1;
retval = read(fd, dst, s->sh_size);
if (retval < 0)
return -1;
return 0;
}
static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type)
{
void *dst;
dst = find_shdr(ehdr, fd, shdr, type);
if (!dst)
goto error;
if (read_section(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
void *dst;
dst = find_strtab(ehdr, fd, shdr, symtab);
if (!dst)
goto error;
if (read_section(fd, shdr, dst))
goto error;
return dst;
error:
qemu_free(dst);
return NULL;
}
static void load_symbols(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
struct syminfo *s;
int nsyms, i;
char *str;
/* Symbol table */
syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB);
if (!syms)
return;
nsyms = symtab.sh_size / sizeof(struct elf_sym);
for (i = 0; i < nsyms; i++)
bswap_sym(&syms[i]);
/* String table */
str = process_strtab(ehdr, fd, &strtab, &symtab);
if (!str)
goto error_freesyms;
/* Commit */
s = qemu_mallocz(sizeof(*s));
s->disas_symtab = syms;
s->disas_num_syms = nsyms;
s->disas_strtab = str;
s->next = syminfos;
syminfos = s;
return;
error_freesyms:
qemu_free(syms);
return;
}
#ifdef TARGET_SPARC64
#undef elfhdr
#undef elf_phdr
#undef elf_shdr
#undef elf_sym
#undef elf_note
#undef elf_word
#undef bswapSZs
#undef SZ
#define elfhdr elf64_hdr
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
#define elf_word uint64_t
#define bswapSZs bswap64s
#define SZ 64
#include "elf_ops.h"
#endif
int load_elf(const char *filename, uint8_t *addr)
{
struct elfhdr ehdr;
struct elf_phdr phdr;
struct elf32_hdr ehdr;
int retval, fd;
Elf32_Half machine;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
@@ -272,21 +108,43 @@ int load_elf(const char *filename, uint8_t *addr)
if (retval < 0)
goto error;
bswap_ehdr(&ehdr);
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|| (ehdr.e_machine != EM_SPARC
&& ehdr.e_machine != EM_SPARC32PLUS))
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
goto error;
machine = tswap16(ehdr.e_machine);
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) {
struct elf32_phdr phdr;
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program(fd, &phdr, addr, ehdr.e_entry);
if (retval < 0)
goto error;
bswap_ehdr32(&ehdr);
load_symbols(&ehdr, fd);
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD))
goto error;
retval = read_program32(fd, &phdr, addr, ehdr.e_entry);
if (retval < 0)
goto error;
load_symbols32(&ehdr, fd);
}
#ifdef TARGET_SPARC64
else if (machine == EM_SPARCV9) {
struct elf64_hdr ehdr64;
struct elf64_phdr phdr;
lseek(fd, 0, SEEK_SET);
retval = read(fd, &ehdr64, sizeof(ehdr64));
if (retval < 0)
goto error;
bswap_ehdr64(&ehdr64);
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD))
goto error;
retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry);
if (retval < 0)
goto error;
load_symbols64(&ehdr64, fd);
}
#endif
close(fd);
return retval;

254
hw/mips_r4k.c Normal file
View File

@@ -0,0 +1,254 @@
#include "vl.h"
#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
extern FILE *logfile;
static void pic_irq_request(void *opaque, int level)
{
if (level) {
cpu_single_env->CP0_Cause |= 0x00000400;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_single_env->CP0_Cause &= ~0x00000400;
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
void cpu_mips_irqctrl_init (void)
{
}
uint32_t cpu_mips_get_random (CPUState *env)
{
uint32_t now = qemu_get_clock(vm_clock);
return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
}
/* MIPS R4K timer */
uint32_t cpu_mips_get_count (CPUState *env)
{
return env->CP0_Count +
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
100 * 1000 * 1000, ticks_per_sec);
}
static void cpu_mips_update_count (CPUState *env, uint32_t count,
uint32_t compare)
{
uint64_t now, next;
uint32_t tmp;
tmp = count;
if (count == compare)
tmp++;
now = qemu_get_clock(vm_clock);
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 1
if (logfile) {
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
__func__, now, count, compare, next - now);
}
#endif
/* Store new count and compare registers */
env->CP0_Compare = compare;
env->CP0_Count =
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
/* Adjust timer */
qemu_mod_timer(env->timer, next);
}
void cpu_mips_store_count (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, value, env->CP0_Compare);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
pic_set_irq(5, 0);
}
static void mips_timer_cb (void *opaque)
{
CPUState *env;
env = opaque;
#if 1
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
pic_set_irq(5, 1);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
cpu_mips_update_count(env, 1, 0);
}
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
CPUWriteMemoryFunc *io_write[] = {
&io_writeb,
&io_writew,
&io_writel,
};
CPUReadMemoryFunc *io_read[] = {
&io_readb,
&io_readw,
&io_readl,
};
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
unsigned long bios_offset;
int io_memory;
int linux_boot;
int ret;
printf("%s: start\n", __func__);
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
#if 0
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
cpu_single_env->PC = 0x80010004;
#else
cpu_single_env->PC = 0xBFC00004;
#endif
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename,
phys_ram_base + (kernel_base - 0x80000000));
if (kernel_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
cpu_single_env->PC = KERNEL_LOAD_ADDR;
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* Init internal devices */
cpu_mips_clock_init(cpu_single_env);
cpu_mips_irqctrl_init();
/* Register 64 KB of ISA IO space at 0x14000000 */
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
isa_mem_base = 0x10000000;
isa_pic = pic_init(pic_irq_request, cpu_single_env);
serial_init(0x3f8, 4, serial_hds[0]);
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
isa_ne2000_init(0x300, 9, &nd_table[0]);
}
QEMUMachine mips_machine = {
"mips",
"mips r4k platform",
mips_r4k_init,
};

View File

@@ -61,6 +61,9 @@
#define EN1_CURPAG 0x17
#define EN1_MULT 0x18
#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_START 0x02 /* Start the chip, clear reset */
@@ -150,7 +153,7 @@ static void ne2000_reset(NE2000State *s)
static void ne2000_update_irq(NE2000State *s)
{
int isr;
isr = s->isr & s->imr;
isr = (s->isr & s->imr) & 0x7f;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
s->irq, isr ? 1 : 0, s->isr, s->imr);
@@ -255,7 +258,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (addr == E8390_CMD) {
/* control register */
s->cmd = val;
if (val & E8390_START) {
if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
s->isr &= ~ENISR_RESET;
/* test specific case: zero length transfert */
if ((val & (E8390_RREAD | E8390_RWRITE)) &&
@@ -376,6 +379,12 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
case EN0_RSR:
ret = s->rsr;
break;
case EN2_STARTPG:
ret = s->start >> 8;
break;
case EN2_STOPPG:
ret = s->stop >> 8;
break;
default:
ret = 0x00;
break;

View File

@@ -320,8 +320,9 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ)
}
}
void openpic_set_irq(openpic_t *opp, int n_IRQ, int level)
void openpic_set_irq(void *opaque, int n_IRQ, int level)
{
openpic_t *opp = opaque;
IRQ_src_t *src;
src = &opp->src[n_IRQ];

53
hw/pc.c
View File

@@ -41,6 +41,7 @@ int dummy_refresh_clock;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
static IOAPICState *ioapic;
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
@@ -65,6 +66,31 @@ uint64_t cpu_get_tsc(CPUX86State *env)
return qemu_get_clock(vm_clock);
}
/* IRQ handling */
int cpu_get_pic_interrupt(CPUState *env)
{
int intno;
intno = apic_get_interrupt(env);
if (intno >= 0) {
/* set irq request if a PIC irq is still pending */
/* XXX: improve that */
pic_update_irq(isa_pic);
return intno;
}
/* read the irq from the PIC */
intno = pic_read_irq(isa_pic);
return intno;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
@@ -380,17 +406,17 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
/* PC hardware initialisation */
void pc_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot, initrd_size, i, nb_nics1;
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
@@ -520,7 +546,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
}
} else {
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
vga_ram_size, 0, 0);
}
rtc_state = rtc_init(0x70, 8);
@@ -530,10 +556,15 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
if (pci_enabled)
if (pci_enabled) {
apic_init(cpu_single_env);
pic_init();
ioapic = ioapic_init();
}
isa_pic = pic_init(pic_irq_request, cpu_single_env);
pit = pit_init(0x40, 0);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
}
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
@@ -595,3 +626,9 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
pci_bios_init();
}
}
QEMUMachine pc_machine = {
"pc",
"Standard PC",
pc_init1,
};

453
hw/pci.c
View File

@@ -45,7 +45,9 @@ struct PCIBus {
int devfn_min;
void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
uint32_t config_reg; /* XXX: suppress */
openpic_t *openpic; /* XXX: suppress */
/* low level pic */
SetIRQFunc *low_set_irq;
void *irq_opaque;
PCIDevice *devices[256];
};
@@ -498,6 +500,27 @@ static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
return (irq_num + slot_addend) & 3;
}
static inline int get_pci_irq_level(int irq_num)
{
int pic_level;
#if (PCI_IRQ_WORDS == 2)
pic_level = ((pci_irq_levels[irq_num][0] |
pci_irq_levels[irq_num][1]) != 0);
#else
{
int i;
pic_level = 0;
for(i = 0; i < PCI_IRQ_WORDS; i++) {
if (pci_irq_levels[irq_num][i]) {
pic_level = 1;
break;
}
}
}
#endif
return pic_level;
}
static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
{
int irq_index, shift, pic_irq, pic_level;
@@ -510,26 +533,20 @@ static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
*p = (*p & ~(1 << shift)) | (level << shift);
/* now we change the pic irq level according to the piix irq mappings */
/* XXX: optimize */
pic_irq = piix3_state->dev.config[0x60 + irq_num];
if (pic_irq < 16) {
/* the pic level is the logical OR of all the PCI irqs mapped
to it */
pic_level = 0;
#if (PCI_IRQ_WORDS == 2)
pic_level = ((pci_irq_levels[irq_num][0] |
pci_irq_levels[irq_num][1]) != 0);
#else
{
int i;
pic_level = 0;
for(i = 0; i < PCI_IRQ_WORDS; i++) {
if (pci_irq_levels[irq_num][i]) {
pic_level = 1;
break;
}
}
}
#endif
if (pic_irq == piix3_state->dev.config[0x60])
pic_level |= get_pci_irq_level(0);
if (pic_irq == piix3_state->dev.config[0x61])
pic_level |= get_pci_irq_level(1);
if (pic_irq == piix3_state->dev.config[0x62])
pic_level |= get_pci_irq_level(2);
if (pic_irq == piix3_state->dev.config[0x63])
pic_level |= get_pci_irq_level(3);
pic_set_irq(pic_irq, pic_level);
}
}
@@ -708,25 +725,25 @@ PCIBus *pci_prep_init(void)
PPC_PCIIO_write, s);
cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
d = pci_register_device(s, "PREP PCI Bridge", sizeof(PCIDevice), 0,
NULL, NULL);
/* XXX: put correct IDs */
d->config[0x00] = 0x11; // vendor_id
/* PCI host bridge */
d = pci_register_device(s, "PREP Host Bridge - Motorola Raven",
sizeof(PCIDevice), 0, NULL, NULL);
d->config[0x00] = 0x57; // vendor_id : Motorola
d->config[0x01] = 0x10;
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
d->config[0x02] = 0x01; // device_id : Raven
d->config[0x03] = 0x48;
d->config[0x08] = 0x00; // revision
d->config[0x0A] = 0x00; // class_sub = pci host
d->config[0x0B] = 0x06; // class_base = PCI_bridge
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
return s;
}
/* pmac pci init */
#if 0
/* Grackle PCI host */
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
@@ -831,7 +848,93 @@ static CPUReadMemoryFunc *pci_grackle_read[] = {
&pci_grackle_readw,
&pci_grackle_readl,
};
void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
{
bus->low_set_irq = set_irq;
bus->irq_opaque = irq_opaque;
}
/* XXX: we do not simulate the hardware - we rely on the BIOS to
set correctly for irq line field */
static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
{
PCIBus *s = d->bus;
s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
}
PCIBus *pci_grackle_init(uint32_t base)
{
PCIBus *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data;
s = pci_register_bus();
s->set_irq = pci_set_irq_simple;
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
pci_grackle_config_write, s);
pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
pci_grackle_write, s);
cpu_register_physical_memory(base, 0x1000, pci_mem_config);
cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice),
0, NULL, NULL);
d->config[0x00] = 0x57; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x02; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x01;
d->config[0x0a] = 0x00; // class_sub = host
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x00; // header_type
d->config[0x18] = 0x00; // primary_bus
d->config[0x19] = 0x01; // secondary_bus
d->config[0x1a] = 0x00; // subordinate_bus
d->config[0x1c] = 0x00;
d->config[0x1d] = 0x00;
d->config[0x20] = 0x00; // memory_base
d->config[0x21] = 0x00;
d->config[0x22] = 0x01; // memory_limit
d->config[0x23] = 0x00;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x00;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x00;
#if 0
/* PCI2PCI bridge same values as PearPC - check this */
d->config[0x00] = 0x11; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
d->config[0x18] = 0x0; // primary_bus
d->config[0x19] = 0x1; // secondary_bus
d->config[0x1a] = 0x1; // subordinate_bus
d->config[0x1c] = 0x10; // io_base
d->config[0x1d] = 0x20; // io_limit
d->config[0x20] = 0x80; // memory_base
d->config[0x21] = 0x80;
d->config[0x22] = 0x90; // memory_limit
d->config[0x23] = 0x80;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x84;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x85;
#endif
return s;
}
/* Uninorth PCI host (for all Mac99 and newer machines */
static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
@@ -1073,23 +1176,6 @@ static CPUReadMemoryFunc *pci_unin_read[] = {
};
#endif
static void pmac_set_irq(PCIDevice *d, int irq_num, int level)
{
openpic_t *openpic;
/* XXX: we do not simulate the hardware - we rely on the BIOS to
set correctly for irq line field */
openpic = d->bus->openpic;
#ifdef TARGET_PPC
if (openpic)
openpic_set_irq(openpic, d->config[PCI_INTERRUPT_LINE], level);
#endif
}
void pci_pmac_set_openpic(PCIBus *bus, openpic_t *openpic)
{
bus->openpic = openpic;
}
PCIBus *pci_pmac_init(void)
{
PCIBus *s;
@@ -1099,7 +1185,7 @@ PCIBus *pci_pmac_init(void)
/* Use values found on a real PowerMac */
/* Uninorth main bus */
s = pci_register_bus();
s->set_irq = pmac_set_irq;
s->set_irq = pci_set_irq_simple;
pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
pci_unin_main_config_write, s);
@@ -1202,34 +1288,253 @@ PCIBus *pci_pmac_init(void)
d->config[0x0E] = 0x00; // header_type
d->config[0x34] = 0x00; // capabilities_pointer
#endif
return s;
}
#if 0 // Grackle ?
/* same values as PearPC - check this */
d->config[0x00] = 0x11; // vendor_id
/* Ultrasparc APB PCI host */
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
int i;
for (i = 11; i < 32; i++) {
if ((val & (1 << i)) != 0)
break;
}
s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
}
static uint32_t pci_apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
int devfn;
devfn = (s->config_reg >> 8) & 0xFF;
val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
return val;
}
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
&pci_apb_config_writel,
&pci_apb_config_writel,
&pci_apb_config_writel,
};
static CPUReadMemoryFunc *pci_apb_config_read[] = {
&pci_apb_config_readl,
&pci_apb_config_readl,
&pci_apb_config_readl,
};
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
//PCIBus *s = opaque;
switch (addr & 0x3f) {
case 0x00: // Control/Status
case 0x10: // AFSR
case 0x18: // AFAR
case 0x20: // Diagnostic
case 0x28: // Target address space
// XXX
default:
break;
}
}
static uint32_t apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
//PCIBus *s = opaque;
uint32_t val;
switch (addr & 0x3f) {
case 0x00: // Control/Status
case 0x10: // AFSR
case 0x18: // AFAR
case 0x20: // Diagnostic
case 0x28: // Target address space
// XXX
default:
val = 0;
break;
}
return val;
}
static CPUWriteMemoryFunc *apb_config_write[] = {
&apb_config_writel,
&apb_config_writel,
&apb_config_writel,
};
static CPUReadMemoryFunc *apb_config_read[] = {
&apb_config_readl,
&apb_config_readl,
&apb_config_readl,
};
static void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 1);
}
static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 2);
}
static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBus *s = opaque;
pci_data_write(s, addr & 7, val, 4);
}
static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr & 7, 1);
return val;
}
static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr & 7, 2);
return val;
}
static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
{
PCIBus *s = opaque;
uint32_t val;
val = pci_data_read(s, addr, 4);
return val;
}
static CPUWriteMemoryFunc *pci_apb_write[] = {
&pci_apb_writeb,
&pci_apb_writew,
&pci_apb_writel,
};
static CPUReadMemoryFunc *pci_apb_read[] = {
&pci_apb_readb,
&pci_apb_readw,
&pci_apb_readl,
};
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outb(NULL, addr & 0xffff, val);
}
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outw(NULL, addr & 0xffff, val);
}
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outl(NULL, addr & 0xffff, val);
}
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inb(NULL, addr & 0xffff);
return val;
}
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inw(NULL, addr & 0xffff);
return val;
}
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inl(NULL, addr & 0xffff);
return val;
}
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
&pci_apb_iowriteb,
&pci_apb_iowritew,
&pci_apb_iowritel,
};
static CPUReadMemoryFunc *pci_apb_ioread[] = {
&pci_apb_ioreadb,
&pci_apb_ioreadw,
&pci_apb_ioreadl,
};
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
{
PCIBus *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
/* Ultrasparc APB main bus */
s = pci_register_bus();
s->set_irq = pci_set_irq_simple;
pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
pci_apb_config_write, s);
apb_config = cpu_register_io_memory(0, apb_config_read,
apb_config_write, s);
pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
pci_apb_write, s);
pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
pci_apb_iowrite, s);
cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice),
-1, NULL, NULL);
d->config[0x00] = 0x8e; // vendor_id : Sun
d->config[0x01] = 0x10;
d->config[0x02] = 0x26; // device_id
d->config[0x03] = 0x00;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x04; // class_sub = pci2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x01; // header_type
d->config[0x18] = 0x0; // primary_bus
d->config[0x19] = 0x1; // secondary_bus
d->config[0x1a] = 0x1; // subordinate_bus
d->config[0x1c] = 0x10; // io_base
d->config[0x1d] = 0x20; // io_limit
d->config[0x20] = 0x80; // memory_base
d->config[0x21] = 0x80;
d->config[0x22] = 0x90; // memory_limit
d->config[0x23] = 0x80;
d->config[0x24] = 0x00; // prefetchable_memory_base
d->config[0x25] = 0x84;
d->config[0x26] = 0x00; // prefetchable_memory_limit
d->config[0x27] = 0x85;
#endif
d->config[0x02] = 0x00; // device_id
d->config[0x03] = 0xa0;
d->config[0x04] = 0x06; // command = bus master, pci mem
d->config[0x05] = 0x00;
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
d->config[0x07] = 0x03; // status = medium devsel
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x00; // programming i/f
d->config[0x0A] = 0x00; // class_sub = pci host
d->config[0x0B] = 0x06; // class_base = PCI_bridge
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
return s;
}

View File

@@ -107,13 +107,16 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
{
ppc_tb_t *tb_env = env->tb_env;
uint32_t decr;
int64_t diff;
decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock),
tb_env->tb_freq, ticks_per_sec);
diff = tb_env->decr_next - qemu_get_clock(vm_clock);
if (diff >= 0)
decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
else
decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
#if defined(DEBUG_TB)
printf("%s: 0x%08x\n", __func__, decr);
#endif
return decr;
}
@@ -440,23 +443,4 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
/*****************************************************************************/
void ppc_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
if (prep_enabled) {
ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
} else {
ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename);
}
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}

View File

@@ -24,19 +24,22 @@
#include "vl.h"
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define KERNEL_LOAD_ADDR 0x01000000
#define INITRD_LOAD_ADDR 0x01800000
/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
NVRAM (not implemented). */
NVRAM */
static int dbdma_mem_index;
static int cuda_mem_index;
static int ide0_mem_index;
static int ide1_mem_index;
static int openpic_mem_index;
static int ide0_mem_index = -1;
static int ide1_mem_index = -1;
static int openpic_mem_index = -1;
static int heathrow_pic_mem_index = -1;
static int macio_nvram_mem_index = -1;
/* DBDMA: currently no op - should suffice right now */
@@ -81,17 +84,75 @@ static CPUReadMemoryFunc *dbdma_read[] = {
&dbdma_readl,
};
/* macio style NVRAM device */
typedef struct MacIONVRAMState {
uint8_t data[0x2000];
} MacIONVRAMState;
static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
MacIONVRAMState *s = opaque;
addr = (addr >> 4) & 0x1fff;
s->data[addr] = value;
// printf("macio_nvram_writeb %04x = %02x\n", addr, value);
}
static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
{
MacIONVRAMState *s = opaque;
uint32_t value;
addr = (addr >> 4) & 0x1fff;
value = s->data[addr];
// printf("macio_nvram_readb %04x = %02x\n", addr, value);
return value;
}
static CPUWriteMemoryFunc *macio_nvram_write[] = {
&macio_nvram_writeb,
&macio_nvram_writeb,
&macio_nvram_writeb,
};
static CPUReadMemoryFunc *macio_nvram_read[] = {
&macio_nvram_readb,
&macio_nvram_readb,
&macio_nvram_readb,
};
static MacIONVRAMState *macio_nvram_init(void)
{
MacIONVRAMState *s;
s = qemu_mallocz(sizeof(MacIONVRAMState));
if (!s)
return NULL;
macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
macio_nvram_write, s);
return s;
}
static void macio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
if (heathrow_pic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x00000, 0x1000,
heathrow_pic_mem_index);
}
cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index);
if (ide0_mem_index >= 0)
cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
if (ide1_mem_index >= 0)
cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
if (openpic_mem_index >= 0) {
cpu_register_physical_memory(addr + 0x40000, 0x40000,
openpic_mem_index);
}
if (macio_nvram_mem_index >= 0)
cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
}
static void macio_init(PCIBus *bus)
static void macio_init(PCIBus *bus, int device_id)
{
PCIDevice *d;
@@ -101,8 +162,8 @@ static void macio_init(PCIBus *bus)
in PearPC */
d->config[0x00] = 0x6b; // vendor_id
d->config[0x01] = 0x10;
d->config[0x02] = 0x22;
d->config[0x03] = 0x00;
d->config[0x02] = device_id;
d->config[0x03] = device_id >> 8;
d->config[0x0a] = 0x00; // class_sub = pci2pci
d->config[0x0b] = 0xff; // class_base = bridge
@@ -116,20 +177,141 @@ static void macio_init(PCIBus *bus)
PCI_ADDRESS_SPACE_MEM, macio_map);
}
/* PowerPC PREP hardware initialisation */
void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
/* UniN device */
static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
}
static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
{
return 0;
}
static CPUWriteMemoryFunc *unin_write[] = {
&unin_writel,
&unin_writel,
&unin_writel,
};
static CPUReadMemoryFunc *unin_read[] = {
&unin_readl,
&unin_readl,
&unin_readl,
};
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
static int vga_osi_call(CPUState *env)
{
static int vga_vbl_enabled;
int linesize;
// printf("osi_call R5=%d\n", env->gpr[5]);
/* same handler as PearPC, coming from the original MOL video
driver. */
switch(env->gpr[5]) {
case 4:
break;
case 28: /* set_vmode */
if (env->gpr[6] != 1 || env->gpr[7] != 0)
env->gpr[3] = 1;
else
env->gpr[3] = 0;
break;
case 29: /* get_vmode_info */
if (env->gpr[6] != 0) {
if (env->gpr[6] != 1 || env->gpr[7] != 0) {
env->gpr[3] = 1;
break;
}
}
env->gpr[3] = 0;
env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
env->gpr[7] = 85 << 16; /* refresh rate */
env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
linesize = ((graphic_depth + 7) >> 3) * graphic_width;
linesize = (linesize + 3) & ~3;
env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
break;
case 31: /* set_video power */
env->gpr[3] = 0;
break;
case 39: /* video_ctrl */
if (env->gpr[6] == 0 || env->gpr[6] == 1)
vga_vbl_enabled = env->gpr[6];
env->gpr[3] = 0;
break;
case 47:
break;
case 59: /* set_color */
/* R6 = index, R7 = RGB */
env->gpr[3] = 0;
break;
case 64: /* get color */
/* R6 = index */
env->gpr[3] = 0;
break;
case 116: /* set hwcursor */
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
/* XXX: suppress that */
static void pic_irq_request(void *opaque, int level)
{
}
static uint8_t nvram_chksum(const uint8_t *buf, int n)
{
int sum, i;
sum = 0;
for(i = 0; i < n; i++)
sum += buf[i];
return (sum & 0xff) + (sum >> 8);
}
/* set a free Mac OS NVRAM partition */
void pmac_format_nvram_partition(uint8_t *buf, int len)
{
char partition_name[12] = "wwwwwwwwwwww";
buf[0] = 0x7f; /* free partition magic */
buf[1] = 0; /* checksum */
buf[2] = len >> 8;
buf[3] = len;
memcpy(buf + 4, partition_name, 12);
buf[1] = nvram_chksum(buf, 16);
}
/* PowerPC CHRP hardware initialisation */
static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
int is_heathrow)
{
char buf[1024];
openpic_t *openpic;
SetIRQFunc *set_irq;
void *pic;
m48t59_t *nvram;
int PPC_io_memory;
int ret, linux_boot, i;
unsigned long bios_offset;
int PPC_io_memory, unin_memory;
int linux_boot, i;
unsigned long bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
const char *arch_name;
int vga_bios_size, bios_size;
linux_boot = (kernel_filename != NULL);
@@ -139,15 +321,36 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
vga_bios_offset = bios_offset + bios_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
vga_bios_size = 0;
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
phys_ram_base[vga_bios_offset] = 'N';
phys_ram_base[vga_bios_offset + 1] = 'D';
phys_ram_base[vga_bios_offset + 2] = 'R';
phys_ram_base[vga_bios_offset + 3] = 'V';
cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
vga_bios_size);
vga_bios_size += 8;
}
vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
@@ -179,50 +382,129 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
initrd_size = 0;
}
/* Register CPU as a 74x/75x */
cpu_ppc_register(cpu_single_env, 0x00080000);
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def); // Linux boot OK
// ppc_find_by_name("750fx", &def); // Linux boot OK
/* Linux does not boot on 750cxe (and probably other 750cx based)
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
*/
// ppc_find_by_name("750cxe", &def);
// ppc_find_by_name("750p", &def);
// ppc_find_by_name("740p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("740", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
cpu_single_env->osi_call = vga_osi_call;
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
if (is_heathrow) {
isa_mem_base = 0x80000000;
pci_bus = pci_grackle_init(0xfec00000);
/* Register 2 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = heathrow_pic_init(&heathrow_pic_mem_index);
set_irq = heathrow_pic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
openpic = openpic_init(NULL, &openpic_mem_index, 1);
pci_pmac_set_openpic(pci_bus, openpic);
/* XXX: suppress that */
pic_init();
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x12);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
{
MacIONVRAMState *nvr;
nvr = macio_nvram_init();
pmac_format_nvram_partition(nvr->data, 0x2000);
}
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
macio_init(pci_bus, 0x0017);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
pic = openpic_init(NULL, &openpic_mem_index, 1);
set_irq = openpic_set_irq;
pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
/* XXX: use Mac Serial port */
serial_init(0x3f8, 4, serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
#if 1
ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(set_irq, pic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus, 0x0022);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
arch_name = "MAC99";
}
ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13);
ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x14);
/* cuda also initialize ADB */
cuda_mem_index = cuda_init(openpic, 0x19);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus);
nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device,
PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
@@ -230,4 +512,45 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
0,
graphic_width, graphic_height, graphic_depth);
/* No PCI init: the BIOS will do it */
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 0);
}
static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 1);
}
QEMUMachine core99_machine = {
"mac99",
"Mac99 based PowerMAC",
ppc_core99_init,
};
QEMUMachine heathrow_machine = {
"g3bw",
"Heathrow based PowerMAC",
ppc_heathrow_init,
};

View File

@@ -96,6 +96,14 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
return 0;
}
static void pic_irq_request(void *opaque, int level)
{
if (level)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PCI intack register */
/* Read-only register (?) */
static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -108,7 +116,7 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
uint32_t retval = 0;
if (addr == 0xBFFFFFF0)
retval = pic_intack_read(NULL);
retval = pic_intack_read(isa_pic);
// printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
return retval;
@@ -250,6 +258,7 @@ typedef struct sysctrl_t {
uint8_t syscontrol;
uint8_t fake_io[2];
int contiguous_map;
int endian;
} sysctrl_t;
enum {
@@ -289,8 +298,9 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
}
/* Check LE mode */
if (val & 0x02) {
printf("Little Endian mode isn't supported (yet ?)\n");
abort();
sysctrl->endian = 1;
} else {
sysctrl->endian = 0;
}
break;
case 0x0800:
@@ -505,22 +515,21 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = {
&PPC_prep_io_readl,
};
extern CPUPPCState *global_env;
#define NVRAM_SIZE 0x2000
/* PowerPC PREP hardware initialisation */
void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int PPC_io_memory;
int ret, linux_boot, i, nb_nics1;
int linux_boot, i, nb_nics1, bios_size;
unsigned long bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
@@ -535,14 +544,14 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
/* allocate and load BIOS */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(-BIOS_SIZE),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_single_env->nip = 0xfffffffc;
bios_size = (bios_size + 0xfff) & ~0xfff;
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
@@ -576,7 +585,14 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
}
/* Register CPU as a 604 */
cpu_ppc_register(cpu_single_env, 0x00040000);
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
@@ -590,11 +606,10 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
vga_ram_size, 0, 0);
rtc_init(0x70, 8);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pic_init(openpic);
pic_init();
isa_pic = pic_init(pic_irq_request, cpu_single_env);
// pit = pit_init(0x40, 0);
serial_init(0x3f8, 4, serial_hds[0]);
@@ -650,4 +665,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
/* Special port to get debug messages from Open-Firmware */
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
QEMUMachine prep_machine = {
"prep",
"PowerPC PREP platform",
ppc_prep_init,
};

View File

@@ -144,14 +144,14 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin
switch (saddr) {
case 2: // clear (enable)
// Force clear unused bits
val &= ~0x7fb2007f;
val &= ~0x4fb2007f;
s->intregm_disabled &= ~val;
DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
slavio_check_interrupts(s);
break;
case 3: // set (disable, clear pending)
// Force clear unused bits
val &= ~0x7fb2007f;
val &= ~0x4fb2007f;
s->intregm_disabled |= val;
s->intregm_pending &= ~val;
DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
@@ -208,7 +208,7 @@ void slavio_irq_info(void *opaque)
static const uint32_t intbit_to_level[32] = {
2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0,
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
};
static void slavio_check_interrupts(void *opaque)

240
hw/slavio_misc.c Normal file
View File

@@ -0,0 +1,240 @@
/*
* QEMU Sparc SLAVIO aux io port emulation
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
/* debug misc */
//#define DEBUG_MISC
/*
* This is the auxio port, chip control and system control part of
* chip STP2001 (Slave I/O), also produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
*
* This also includes the PMC CPU idle controller.
*/
#ifdef DEBUG_MISC
#define MISC_DPRINTF(fmt, args...) \
do { printf("MISC: " fmt , ##args); } while (0)
#else
#define MISC_DPRINTF(fmt, args...)
#endif
typedef struct MiscState {
int irq;
uint8_t config;
uint8_t aux1, aux2;
uint8_t diag, mctrl;
} MiscState;
#define MISC_MAXADDR 1
static void slavio_misc_update_irq(void *opaque)
{
MiscState *s = opaque;
if ((s->aux2 & 0x4) && (s->config & 0x8)) {
pic_set_irq(s->irq, 1);
} else {
pic_set_irq(s->irq, 0);
}
}
static void slavio_misc_reset(void *opaque)
{
MiscState *s = opaque;
// Diagnostic register not cleared in reset
s->config = s->aux1 = s->aux2 = s->mctrl = 0;
}
void slavio_set_power_fail(void *opaque, int power_failing)
{
MiscState *s = opaque;
MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
if (power_failing && (s->config & 0x8)) {
s->aux2 |= 0x4;
} else {
s->aux2 &= ~0x4;
}
slavio_misc_update_irq(s);
}
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
MiscState *s = opaque;
switch (addr & 0xfff0000) {
case 0x1800000:
MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
s->config = val & 0xff;
slavio_misc_update_irq(s);
break;
case 0x1900000:
MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
s->aux1 = val & 0xff;
break;
case 0x1910000:
val &= 0x3;
MISC_DPRINTF("Write aux2 %2.2x\n", val);
val |= s->aux2 & 0x4;
if (val & 0x2) // Clear Power Fail int
val &= 0x1;
s->aux2 = val;
if (val & 1)
qemu_system_shutdown_request();
slavio_misc_update_irq(s);
break;
case 0x1a00000:
MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
s->diag = val & 0xff;
break;
case 0x1b00000:
MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
s->mctrl = val & 0xff;
break;
case 0x1f00000:
MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
if (val & 1)
qemu_system_reset_request();
break;
case 0xa000000:
MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
#if 0
// XXX: halting CPU does not work
raise_exception(EXCP_HLT);
cpu_loop_exit();
#endif
break;
}
}
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
{
MiscState *s = opaque;
uint32_t ret = 0;
switch (addr & 0xfff0000) {
case 0x1800000:
ret = s->config;
MISC_DPRINTF("Read config %2.2x\n", ret);
break;
case 0x1900000:
ret = s->aux1;
MISC_DPRINTF("Read aux1 %2.2x\n", ret);
break;
case 0x1910000:
ret = s->aux2;
MISC_DPRINTF("Read aux2 %2.2x\n", ret);
break;
case 0x1a00000:
ret = s->diag;
MISC_DPRINTF("Read diag %2.2x\n", ret);
break;
case 0x1b00000:
ret = s->mctrl;
MISC_DPRINTF("Read modem control %2.2x\n", ret);
break;
case 0x1f00000:
MISC_DPRINTF("Read system control %2.2x\n", ret);
break;
case 0xa000000:
MISC_DPRINTF("Read power management %2.2x\n", ret);
break;
}
return ret;
}
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
slavio_misc_mem_readb,
slavio_misc_mem_readb,
slavio_misc_mem_readb,
};
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
slavio_misc_mem_writeb,
slavio_misc_mem_writeb,
slavio_misc_mem_writeb,
};
static void slavio_misc_save(QEMUFile *f, void *opaque)
{
MiscState *s = opaque;
qemu_put_be32s(f, &s->irq);
qemu_put_8s(f, &s->config);
qemu_put_8s(f, &s->aux1);
qemu_put_8s(f, &s->aux2);
qemu_put_8s(f, &s->diag);
qemu_put_8s(f, &s->mctrl);
}
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
{
MiscState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->irq);
qemu_get_8s(f, &s->config);
qemu_get_8s(f, &s->aux1);
qemu_get_8s(f, &s->aux2);
qemu_get_8s(f, &s->diag);
qemu_get_8s(f, &s->mctrl);
return 0;
}
void *slavio_misc_init(uint32_t base, int irq)
{
int slavio_misc_io_memory;
MiscState *s;
s = qemu_mallocz(sizeof(MiscState));
if (!s)
return NULL;
slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
// Slavio control
cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
// AUX 1
cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
// AUX 2
cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
// Diagnostics
cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
// Modem control
cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
// System control
cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
// Power management
cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
s->irq = irq;
register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
qemu_register_reset(slavio_misc_reset, s);
slavio_misc_reset(s);
return s;
}

View File

@@ -37,6 +37,7 @@
// bits
#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */
#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */
#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */
#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
#define PHYS_JJ_ESP_IRQ 18
@@ -55,6 +56,7 @@
#define PHYS_JJ_SER_IRQ 15
#define PHYS_JJ_FDC 0x71400000 /* Floppy */
#define PHYS_JJ_FLOPPY_IRQ 22
#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */
/* TSC handling */
@@ -202,11 +204,18 @@ uint32_t iommu_translate(uint32_t addr)
return iommu_translate_local(iommu, addr);
}
static void *slavio_misc;
void qemu_system_powerdown(void)
{
slavio_set_power_fail(slavio_misc, 1);
}
/* Sun4m hardware initialisation */
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot;
@@ -230,6 +239,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
prom_offset = ram_size + vram_size;
@@ -283,3 +293,9 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
}
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
}
QEMUMachine sun4m_machine = {
"sun4m",
"Sun4m platform",
sun4m_init,
};

375
hw/sun4u.c Normal file
View File

@@ -0,0 +1,375 @@
/*
* QEMU Sun4u System Emulator
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "m48t59.h"
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define INITRD_LOAD_ADDR 0x00300000
#define PROM_ADDR 0x1fff0000000ULL
#define APB_SPECIAL_BASE 0x1fe00000000ULL
#define APB_MEM_BASE 0x1ff00000000ULL
#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
#define PROM_FILENAMEB "proll-sparc64.bin"
#define PROM_FILENAMEE "proll-sparc64.elf"
#define NVRAM_SIZE 0x2000
/* TSC handling */
uint64_t cpu_get_tsc()
{
return qemu_get_clock(vm_clock);
}
int DMA_get_channel_mode (int nchan)
{
return 0;
}
int DMA_read_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
int DMA_write_memory (int nchan, void *buf, int pos, int size)
{
return 0;
}
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
void *opaque)
{
}
/* NVRAM helpers */
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value);
}
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
{
m48t59_set_addr(nvram, addr);
return m48t59_read(nvram);
}
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 8);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, value & 0xFF);
}
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
{
uint16_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
{
m48t59_set_addr(nvram, addr);
m48t59_write(nvram, value >> 24);
m48t59_set_addr(nvram, addr + 1);
m48t59_write(nvram, (value >> 16) & 0xFF);
m48t59_set_addr(nvram, addr + 2);
m48t59_write(nvram, (value >> 8) & 0xFF);
m48t59_set_addr(nvram, addr + 3);
m48t59_write(nvram, value & 0xFF);
}
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
{
uint32_t tmp;
m48t59_set_addr(nvram, addr);
tmp = m48t59_read(nvram) << 24;
m48t59_set_addr(nvram, addr + 1);
tmp |= m48t59_read(nvram) << 16;
m48t59_set_addr(nvram, addr + 2);
tmp |= m48t59_read(nvram) << 8;
m48t59_set_addr(nvram, addr + 3);
tmp |= m48t59_read(nvram);
return tmp;
}
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
const unsigned char *str, uint32_t max)
{
int i;
for (i = 0; i < max && str[i] != '\0'; i++) {
m48t59_set_addr(nvram, addr + i);
m48t59_write(nvram, str[i]);
}
m48t59_set_addr(nvram, addr + max - 1);
m48t59_write(nvram, '\0');
}
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
{
int i;
memset(dst, 0, max);
for (i = 0; i < max; i++) {
dst[i] = NVRAM_get_byte(nvram, addr + i);
if (dst[i] == '\0')
break;
}
return i;
}
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
{
uint16_t tmp;
uint16_t pd, pd1, pd2;
tmp = prev >> 8;
pd = prev ^ value;
pd1 = pd & 0x000F;
pd2 = ((pd >> 4) & 0x000F) ^ pd1;
tmp ^= (pd1 << 3) | (pd1 << 8);
tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
return tmp;
}
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
{
uint32_t i;
uint16_t crc = 0xFFFF;
int odd;
odd = count & 1;
count &= ~1;
for (i = 0; i != count; i++) {
crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
}
if (odd) {
crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
}
return crc;
}
extern int nographic;
int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
uint32_t RAM_size, int boot_device,
uint32_t kernel_image, uint32_t kernel_size,
const char *cmdline,
uint32_t initrd_image, uint32_t initrd_size,
uint32_t NVRAM_image,
int width, int height, int depth)
{
uint16_t crc;
/* Set parameters for Open Hack'Ware BIOS */
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
NVRAM_set_word(nvram, 0x14, NVRAM_size);
NVRAM_set_string(nvram, 0x20, arch, 16);
NVRAM_set_byte(nvram, 0x2f, nographic & 0xff);
NVRAM_set_lword(nvram, 0x30, RAM_size);
NVRAM_set_byte(nvram, 0x34, boot_device);
NVRAM_set_lword(nvram, 0x38, kernel_image);
NVRAM_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
/* XXX: put the cmdline in NVRAM too ? */
strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
} else {
NVRAM_set_lword(nvram, 0x40, 0);
NVRAM_set_lword(nvram, 0x44, 0);
}
NVRAM_set_lword(nvram, 0x48, initrd_image);
NVRAM_set_lword(nvram, 0x4C, initrd_size);
NVRAM_set_lword(nvram, 0x50, NVRAM_image);
NVRAM_set_word(nvram, 0x54, width);
NVRAM_set_word(nvram, 0x56, height);
NVRAM_set_word(nvram, 0x58, depth);
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
return 0;
}
void pic_info()
{
}
void irq_info()
{
}
void pic_set_irq(int irq, int level)
{
}
void pic_set_irq_new(void *opaque, int irq, int level)
{
}
void qemu_system_powerdown(void)
{
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
static const int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static const int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
static fdctrl_t *floppy_controller;
/* Sun4u hardware initialisation */
static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
m48t59_t *nvram;
int ret, linux_boot;
unsigned int i;
long prom_offset, initrd_size, kernel_size;
PCIBus *pci_bus;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
prom_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
ret = load_elf(buf, phys_ram_base + prom_offset);
if (ret < 0) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
ret = load_image(buf, phys_ram_base + prom_offset);
}
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
exit(1);
}
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
kernel_size = 0;
initrd_size = 0;
if (linux_boot) {
kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
}
if (initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
== 0x48647253) { // HdrS
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
break;
}
}
}
}
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
isa_mem_base = VGA_BASE;
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size);
//pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
}
}
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_cmd646_ide_init(pci_bus, bs_table, 1);
kbd_init();
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
KERNEL_LOAD_ADDR, kernel_size,
kernel_cmdline,
INITRD_LOAD_ADDR, initrd_size,
/* XXX: need an option to load a NVRAM image */
0,
graphic_width, graphic_height, graphic_depth);
}
QEMUMachine sun4u_machine = {
"sun4u",
"Sun4u platform",
sun4u_init,
};

View File

@@ -1654,8 +1654,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
VGAState *s = vga_state;
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
if (region_num == PCI_ROM_SLOT) {
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
} else {
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
}
}
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
@@ -1701,7 +1704,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size)
unsigned long vga_ram_offset, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size)
{
VGAState *s;
@@ -1776,6 +1780,17 @@ int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
/* XXX: vga_ram_size must be a power of two */
pci_register_io_region(d, 0, vga_ram_size,
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
if (vga_bios_size != 0) {
unsigned int bios_total_size;
s->bios_offset = vga_bios_offset;
s->bios_size = vga_bios_size;
/* must be a power of two */
bios_total_size = 1;
while (bios_total_size < vga_bios_size)
bios_total_size <<= 1;
pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size,
PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
}
} else {
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */

View File

@@ -78,6 +78,8 @@
uint8_t *vram_ptr; \
unsigned long vram_offset; \
unsigned int vram_size; \
unsigned long bios_offset; \
unsigned int bios_size; \
uint32_t latch; \
uint8_t sr_index; \
uint8_t sr[256]; \

View File

@@ -99,7 +99,7 @@ uint32_t do_arm_semihosting(CPUState *env)
else
return STDOUT_FILENO;
}
return set_swi_errno(ts, open(s, open_modeflags[ARG(1)]));
return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
case SYS_CLOSE:
return set_swi_errno(ts, close(ARG(0)));
case SYS_WRITEC:

View File

@@ -552,6 +552,7 @@ void cpu_loop (CPUSPARCState *env)
env->pc = env->npc;
env->npc = env->npc + 4;
break;
#ifndef TARGET_SPARC64
case TT_WIN_OVF: /* window overflow */
save_window(env);
break;
@@ -569,6 +570,9 @@ void cpu_loop (CPUSPARCState *env)
queue_signal(info.si_signo, &info);
}
break;
#else
// XXX
#endif
case 0x100: // XXX, why do we get these?
break;
case EXCP_DEBUG:
@@ -696,33 +700,28 @@ void cpu_loop(CPUPPCState *env)
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
case EXCP_DSI:
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
fprintf(stderr, "Invalid data memory access: 0x%08x\n",
env->spr[SPR_DAR]);
if (loglevel) {
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
env->spr[DAR]);
env->spr[SPR_DAR]);
}
switch (env->error_code & 0xF) {
case EXCP_DSI_TRANSLATE:
switch (env->error_code & 0xFF000000) {
case 0x40000000:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
case EXCP_DSI_NOTSUP:
case EXCP_DSI_EXTERNAL:
case 0x04000000:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLADR;
break;
case EXCP_DSI_PROT:
case 0x08000000:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_ACCERR;
break;
case EXCP_DSI_DABR:
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
break;
default:
/* Let's send a regular segfault... */
fprintf(stderr, "Invalid segfault errno (%02x)\n",
@@ -743,19 +742,14 @@ void cpu_loop(CPUPPCState *env)
fprintf(stderr, "Invalid instruction fetch\n");
if (loglevel)
fprintf(logfile, "Invalid instruction fetch\n");
switch (env->error_code) {
case EXCP_ISI_TRANSLATE:
switch (env->error_code & 0xFF000000) {
case 0x40000000:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
break;
case EXCP_ISI_GUARD:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLADR;
break;
case EXCP_ISI_NOEXEC:
case EXCP_ISI_PROT:
case 0x10000000:
case 0x08000000:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_ACCERR;
@@ -925,18 +919,6 @@ void cpu_loop(CPUPPCState *env)
if (loglevel)
fprintf(logfile, "Decrementer exception\n");
abort();
case EXCP_RESA: /* Implementation specific */
/* Should not happen ! */
fprintf(stderr, "RESA exception should never happen !\n");
if (loglevel)
fprintf(logfile, "RESA exception should never happen !\n");
abort();
case EXCP_RESB: /* Implementation specific */
/* Should not happen ! */
fprintf(stderr, "RESB exception should never happen !\n");
if (loglevel)
fprintf(logfile, "RESB exception should never happen !\n");
abort();
case EXCP_TRACE:
/* Do nothing: we use this to trace execution */
break;
@@ -958,12 +940,6 @@ void cpu_loop(CPUPPCState *env)
case EXCP_BRANCH:
/* We stopped because of a jump... */
break;
case EXCP_RFI:
/* Should not occur: we always are in user mode */
fprintf(stderr, "Return from interrupt ?\n");
if (loglevel)
fprintf(logfile, "Return from interrupt ?\n");
abort();
case EXCP_INTERRUPT:
/* Don't know why this should ever happen... */
break;
@@ -997,7 +973,7 @@ void cpu_loop(CPUPPCState *env)
void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
@@ -1239,7 +1215,25 @@ int main(int argc, char **argv)
}
#elif defined(TARGET_PPC)
{
ppc_def_t *def;
int i;
/* Choose and initialise CPU */
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def);
// ppc_find_by_name("750fx", &def);
// ppc_find_by_name("750p", &def);
ppc_find_by_name("750", &def);
// ppc_find_by_name("G3", &def);
// ppc_find_by_name("604r", &def);
// ppc_find_by_name("604e", &def);
// ppc_find_by_name("604", &def);
if (def == NULL) {
cpu_abort(cpu_single_env,
"Unable to find PowerPC CPU definition\n");
}
cpu_ppc_register(cpu_single_env, def);
for (i = 0; i < 32; i++) {
if (i != 12 && i != 6 && i != 13)
env->msr[i] = (regs->msr >> i) & 1;

View File

@@ -547,7 +547,21 @@ static long do_setsockopt(int sockfd, int level, int optname,
break;
case SOL_IP:
switch(optname) {
case IP_TOS:
case IP_TTL:
case IP_HDRINCL:
case IP_ROUTER_ALERT:
case IP_RECVOPTS:
case IP_RETOPTS:
case IP_PKTINFO:
case IP_MTU_DISCOVER:
case IP_RECVERR:
case IP_RECVTOS:
#ifdef IP_FREEBIND
case IP_FREEBIND:
#endif
case IP_MULTICAST_TTL:
case IP_MULTICAST_LOOP:
val = 0;
if (optlen >= sizeof(uint32_t)) {
if (get_user(val, (uint32_t *)optval))
@@ -619,6 +633,45 @@ static long do_getsockopt(int sockfd, int level, int optname,
/* These don't just return a single integer */
goto unimplemented;
default:
goto int_case;
}
break;
case SOL_TCP:
/* TCP options all take an 'int' value. */
int_case:
if (get_user(len, optlen))
return -EFAULT;
if (len < 0)
return -EINVAL;
lv = sizeof(int);
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
val = tswap32(val);
if (len > lv)
len = lv;
if (copy_to_user(optval, &val, len))
return -EFAULT;
if (put_user(len, optlen))
return -EFAULT;
break;
case SOL_IP:
switch(optname) {
case IP_TOS:
case IP_TTL:
case IP_HDRINCL:
case IP_ROUTER_ALERT:
case IP_RECVOPTS:
case IP_RETOPTS:
case IP_PKTINFO:
case IP_MTU_DISCOVER:
case IP_RECVERR:
case IP_RECVTOS:
#ifdef IP_FREEBIND
case IP_FREEBIND:
#endif
case IP_MULTICAST_TTL:
case IP_MULTICAST_LOOP:
if (get_user(len, optlen))
return -EFAULT;
if (len < 0)
@@ -627,14 +680,25 @@ static long do_getsockopt(int sockfd, int level, int optname,
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
val = tswap32(val);
if (len > lv)
len = lv;
if (copy_to_user(optval, &val, len))
return -EFAULT;
if (put_user(len, optlen))
return -EFAULT;
if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
unsigned char ucval = val;
len = 1;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval,&ucval,1))
return -EFAULT;
} else {
val = tswap32(val);
if (len > sizeof(int))
len = sizeof(int);
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
}
break;
default:
goto unimplemented;
}
break;
default:
@@ -2756,11 +2820,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#endif
#ifdef TARGET_NR_truncate64
case TARGET_NR_truncate64:
goto unimplemented;
ret = get_errno(truncate64((const char *)arg1, arg2));
break;
#endif
#ifdef TARGET_NR_ftruncate64
case TARGET_NR_ftruncate64:
goto unimplemented;
ret = get_errno(ftruncate64(arg1, arg2));
break;
#endif
#ifdef TARGET_NR_stat64
case TARGET_NR_stat64:

3998
mips-dis.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -222,7 +222,7 @@ static void do_info_registers(void)
{
#ifdef TARGET_I386
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
X86_DUMP_FPU | X86_DUMP_CCOP);
X86_DUMP_FPU);
#else
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
0);
@@ -562,6 +562,22 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne
term_printf("\n");
}
static void do_sum(uint32_t start, uint32_t size)
{
uint32_t addr;
uint8_t buf[1];
uint16_t sum;
sum = 0;
for(addr = start; addr < (start + size); addr++) {
cpu_physical_memory_rw(addr, buf, 1, 0);
/* BSD sum algorithm ('sum' Unix command) */
sum = (sum >> 1) | (sum << 15);
sum += buf[0];
}
term_printf("%05d\n", sum);
}
typedef struct {
int keycode;
const char *name;
@@ -751,6 +767,11 @@ static void do_system_reset(void)
qemu_system_reset_request();
}
static void do_system_powerdown(void)
{
qemu_system_powerdown_request();
}
#if defined(TARGET_I386)
static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
{
@@ -864,6 +885,20 @@ static void mem_info(void)
}
#endif
static void do_info_kqemu(void)
{
#ifdef USE_KQEMU
int val;
val = 0;
if (cpu_single_env)
val = cpu_single_env->kqemu_enabled;
term_printf("kqemu is %s\n", val ? "enabled" : "disabled");
#else
term_printf("kqemu support is not compiled\n");
#endif
}
static term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"[cmd]", "show the help" },
@@ -906,6 +941,10 @@ static term_cmd_t term_cmds[] = {
"keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
{ "system_reset", "", do_system_reset,
"", "reset the system" },
{ "system_powerdown", "", do_system_powerdown,
"", "send system power down event" },
{ "sum", "ii", do_sum,
"addr size", "compute the checksum of a memory region" },
{ NULL, NULL, },
};
@@ -934,6 +973,8 @@ static term_cmd_t info_cmds[] = {
#endif
{ "jit", "", do_info_jit,
"", "show dynamic compiler info", },
{ "kqemu", "", do_info_kqemu,
"", "show kqemu information", },
{ NULL, NULL, },
};

View File

@@ -5,9 +5,13 @@
project (http://www.nongnu.org/vgabios/).
- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
available at http://site.voila.fr/jmayer/OpenHackWare/index.htm.
available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
- Proll is a GPL'd boot PROM for Sparc JavaStations
(http://people.redhat.com/zaitcev/linux/).
Applying proll.patch allows circumventing some bugs and enables
faster kernel load through a hack.
- video.x is a PowerMac NDRV compatible driver for a VGA frame
buffer. It comes from the Mac-on-Linux project
(http://www.maconlinux.org/).

1843
pc-bios/ohw.diff Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
pc-bios/video.x Normal file

Binary file not shown.

View File

@@ -3067,11 +3067,12 @@ const struct powerpc_macro powerpc_macros[] = {
const int powerpc_num_macros =
sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int dialect);
static int
print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
int dialect);
/* Print a big endian PowerPC instruction. For convenience, also
disassemble instructions supported by the Motorola PowerPC 601. */
#include "cpu.h"
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
{
@@ -3083,14 +3084,19 @@ int print_insn_ppc (bfd_vma pc, disassemble_info *info)
opc = bfd_getb32(buf);
else
opc = bfd_getl32(buf);
return print_insn_powerpc (info->stream, opc, pc,
PPC | B32 | M601);
if (info->mach == bfd_mach_ppc64) {
return print_insn_powerpc (info, opc, pc,
PPC | B64);
} else {
return print_insn_powerpc (info, opc, pc,
PPC | B32 | M601);
}
}
/* Print a PowerPC or POWER instruction. */
static int
print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
int dialect)
{
const struct powerpc_opcode *opcode;
@@ -3136,9 +3142,9 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
continue;
/* The instruction is valid. */
fprintf(out, "%s", opcode->name);
(*info->fprintf_func)(info->stream, "%s", opcode->name);
if (opcode->operands[0] != 0)
fprintf(out, "\t");
(*info->fprintf_func)(info->stream, "\t");
/* Now extract and print the operands. */
need_comma = 0;
@@ -3175,26 +3181,26 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
if (need_comma)
{
fprintf(out, ",");
(*info->fprintf_func)(info->stream, ",");
need_comma = 0;
}
/* Print the operand as directed by the flags. */
if ((operand->flags & PPC_OPERAND_GPR) != 0)
fprintf(out, "r%d", value);
(*info->fprintf_func)(info->stream, "r%d", value);
else if ((operand->flags & PPC_OPERAND_FPR) != 0)
fprintf(out, "f%d", value);
(*info->fprintf_func)(info->stream, "f%d", value);
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
fprintf(out, "%08X", memaddr + value);
(*info->fprintf_func)(info->stream, "%08X", memaddr + value);
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
fprintf(out, "%08X", value & 0xffffffff);
(*info->fprintf_func)(info->stream, "%08X", value & 0xffffffff);
else if ((operand->flags & PPC_OPERAND_CR) == 0
|| (dialect & PPC_OPCODE_PPC) == 0)
fprintf(out, "%d", value);
(*info->fprintf_func)(info->stream, "%d", value);
else
{
if (operand->bits == 3)
fprintf(out, "cr%d", value);
(*info->fprintf_func)(info->stream, "cr%d", value);
else
{
static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
@@ -3203,20 +3209,20 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
cr = value >> 2;
if (cr != 0)
fprintf(out, "4*cr%d", cr);
(*info->fprintf_func)(info->stream, "4*cr%d", cr);
cc = value & 3;
if (cc != 0)
{
if (cr != 0)
fprintf(out, "+");
fprintf(out, "%s", cbnames[cc]);
(*info->fprintf_func)(info->stream, "+");
(*info->fprintf_func)(info->stream, "%s", cbnames[cc]);
}
}
}
if (need_paren)
{
fprintf(out, ")");
(*info->fprintf_func)(info->stream, ")");
need_paren = 0;
}
@@ -3224,7 +3230,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
need_comma = 1;
else
{
fprintf(out, "(");
(*info->fprintf_func)(info->stream, "(");
need_paren = 1;
}
}
@@ -3234,7 +3240,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr,
}
/* We could not find a match. */
fprintf(out, ".long 0x%x", insn);
(*info->fprintf_func)(info->stream, ".long 0x%x", insn);
return 4;
}

10
ppc.ld
View File

@@ -53,6 +53,16 @@ SECTIONS
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }

View File

@@ -22,7 +22,7 @@ QEMU has two operating modes:
@item
Full system emulation. In this mode, QEMU emulates a full system (for
example a PC), including a processor and various peripherials. It can
example a PC), including a processor and various peripherals. It can
be used to launch different Operating Systems without rebooting the
PC or to debug system code.
@@ -39,13 +39,16 @@ performance.
For system emulation, the following hardware targets are supported:
@itemize
@item PC (x86 processor)
@item PC (x86 or x86_64 processor)
@item PREP (PowerPC processor)
@item PowerMac (PowerPC processor, in progress)
@item Sun4m (Sparc processor, in progress)
@item G3 BW PowerMac (PowerPC processor)
@item Mac99 PowerMac (PowerPC processor, in progress)
@item Sun4m (32-bit Sparc processor)
@item Sun4u (64-bit Sparc processor, in progress)
@item Malta board (32-bit MIPS processor, in progress)
@end itemize
For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported.
For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
@chapter Installation
@@ -73,7 +76,7 @@ Download the experimental binary installer at
@c man begin DESCRIPTION
The QEMU System emulator simulates the
following PC peripherials:
following PC peripherals:
@itemize @minus
@item
@@ -192,6 +195,11 @@ Start in full screen.
Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
from a script.
@item -win2k-hack
Use it when installing Windows 2000 to avoid a disk full bug. After
Windows 2000 is installed, you no longer need this option (this option
slows down the IDE transfers).
@end table
Network options:
@@ -203,6 +211,10 @@ Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script
is launched to configure the host network interface (usually tun0)
corresponding to the virtual NE2000 card.
@item -nics n
Simulate @var{n} network cards (the default is 1).
@item -macaddr addr
Set the mac address of the first interface (the format is
@@ -892,16 +904,13 @@ idle. You can install the utility from
@url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this
problem. Note that no such tool is needed for NT, 2000 or XP.
@subsubsection Windows 2000 disk full problems
@subsubsection Windows 2000 disk full problem
Currently (release 0.6.0) QEMU has a bug which gives a @code{disk
full} error during installation of some releases of Windows 2000. The
workaround is to stop QEMU as soon as you notice that your disk image
size is growing too fast (monitor it with @code{ls -ls}). Then
relaunch QEMU to continue the installation. If you still experience
the problem, relaunch QEMU again.
Future QEMU releases are likely to correct this bug.
Windows 2000 has a bug which gives a disk full problem during its
installation. When installing it, use the @option{-win2k-hack} QEMU
option to enable a specific workaround. After Windows 2000 is
installed, you no longer need this option (this option slows down the
IDE transfers).
@subsubsection Windows XP security problems
@@ -930,7 +939,7 @@ problem.
Use the executable @file{qemu-system-ppc} to simulate a complete PREP
or PowerMac PowerPC system.
QEMU emulates the following PowerMac peripherials:
QEMU emulates the following PowerMac peripherals:
@itemize @minus
@item
@@ -947,7 +956,7 @@ Non Volatile RAM
VIA-CUDA with ADB keyboard and mouse.
@end itemize
QEMU emulates the following PREP peripherials:
QEMU emulates the following PREP peripherals:
@itemize @minus
@item
@@ -995,15 +1004,15 @@ Set the initial VGA graphic mode. The default is 800x600x15.
More information is available at
@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
@chapter Sparc System emulator invocation
@chapter Sparc32 System emulator invocation
Use the executable @file{qemu-system-sparc} to simulate a JavaStation
(sun4m architecture). The emulation is far from complete.
(sun4m architecture). The emulation is somewhat complete.
QEMU emulates the following sun4m peripherials:
QEMU emulates the following sun4m peripherals:
@itemize @minus
@item
@item
IOMMU
@item
TCX Frame buffer
@@ -1012,14 +1021,60 @@ Lance (Am7990) Ethernet
@item
Non Volatile RAM M48T08
@item
Slave I/O: timers, interrupt controllers, Zilog serial ports
Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard
and power/reset logic
@item
ESP SCSI controller with hard disk and CD-ROM support
@item
Floppy drive
@end itemize
QEMU uses the Proll, a PROM replacement available at
@url{http://people.redhat.com/zaitcev/linux/}.
The number of peripherals is fixed in the architecture.
A sample Linux kernel and ram disk image are available on the QEMU web
site.
QEMU uses the Proll, a PROM replacement available at
@url{http://people.redhat.com/zaitcev/linux/}. The required
QEMU-specific patches are included with the sources.
A sample Linux 2.6 series kernel and ram disk image are available on
the QEMU web site. Please note that currently neither Linux 2.4
series, NetBSD, nor OpenBSD kernels work.
@c man begin OPTIONS
The following options are specific to the Sparc emulation:
@table @option
@item -g WxH
Set the initial TCX graphic mode. The default is 1024x768.
@end table
@c man end
@chapter Sparc64 System emulator invocation
Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
The emulator is not usable for anything yet.
QEMU emulates the following sun4u peripherals:
@itemize @minus
@item
UltraSparc IIi APB PCI Bridge
@item
PCI VGA compatible card with VESA Bochs Extensions
@item
Non Volatile RAM M48T59
@item
PC-compatible serial ports
@end itemize
@chapter MIPS System emulator invocation
Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
The emulator begins to launch a Linux kernel.
@chapter QEMU User space emulator invocation

View File

@@ -127,7 +127,7 @@ static void format_print(void *opaque, const char *name)
void help(void)
{
printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n"
printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n"
"usage: qemu-img command [command options]\n"
"QEMU disk image utility\n"
"\n"
@@ -658,9 +658,10 @@ static int img_info(int argc, char **argv)
get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
allocated_size = get_allocated_file_size(filename);
if (allocated_size < 0)
error("Could not get file size '%s'", filename);
get_human_readable_size(dsize_buf, sizeof(dsize_buf),
allocated_size);
sprintf(dsize_buf, "unavailable");
else
get_human_readable_size(dsize_buf, sizeof(dsize_buf),
allocated_size);
printf("image: %s\n"
"file format: %s\n"
"virtual size: %s (%lld bytes)\n"

View File

@@ -44,8 +44,7 @@ User Mode Linux Copy On Write image format. Used to be the only growable
image format in QEMU. It is supported only for compatibility with
previous versions. It does not work on win32.
@item vmdk
VMware 3 and 4 compatible image format. Currently only supported as
read-only.
VMware 3 and 4 compatible image format.
@item cloop
Linux Compressed Loop image, useful only to reuse directly compressed
CD-ROM images present for example in the Knoppix CD-ROMs.

View File

@@ -22,7 +22,7 @@ QEMU has two operating modes:
@item
Full system emulation. In this mode, QEMU emulates a full system
(usually a PC), including a processor and various peripherials. It can
(usually a PC), including a processor and various peripherals. It can
be used to launch an different Operating System without rebooting the
PC or to debug system code.
@@ -138,9 +138,31 @@ FPU and MMU.
@itemize
@item Somewhat complete SPARC V8 emulation, including privileged
instructions, FPU and MMU.
instructions, FPU and MMU. SPARC V9 emulation includes most privileged
instructions, FPU and I/D MMU, but misses VIS instructions.
@item Can run some SPARC Linux binaries.
@item Can run some 32-bit SPARC Linux binaries.
@end itemize
Current QEMU limitations:
@itemize
@item Tagged add/subtract instructions are not supported, but they are
probably not used.
@item IPC syscalls are missing.
@item 128-bit floating point operations are not supported, though none of the
real CPUs implement them either. FCMPE[SD] are not correctly
implemented. Floating point exception support is untested.
@item Alignment is not enforced at all.
@item Atomic instructions are not correctly implemented.
@item Sparc64 emulators are not usable for anything yet.
@end itemize

1
sdl.c
View File

@@ -53,7 +53,6 @@ static void sdl_resize(DisplayState *ds, int w, int h)
// printf("resizing to %d %d\n", w, h);
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
flags |= SDL_RESIZABLE;
if (gui_fullscreen)
flags |= SDL_FULLSCREEN;
screen = SDL_SetVideoMode(w, h, 0, flags);

View File

@@ -238,7 +238,7 @@ static void bootp_reply(struct bootp_t *bp)
void bootp_input(struct mbuf *m)
{
struct bootp_t *bp = (struct bootp_t *)m->m_data;
struct bootp_t *bp = mtod(m, struct bootp_t *);
if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(bp);

View File

@@ -97,9 +97,9 @@ struct bootp_t {
uint8_t bp_htype;
uint8_t bp_hlen;
uint8_t bp_hops;
unsigned long bp_xid;
unsigned short bp_secs;
unsigned short unused;
uint32_t bp_xid;
uint16_t bp_secs;
uint16_t unused;
struct in_addr bp_ciaddr;
struct in_addr bp_yiaddr;
struct in_addr bp_siaddr;

View File

@@ -83,8 +83,8 @@ struct icmp {
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
u_long id_mask;
char id_data[1];
uint32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime

View File

@@ -9,6 +9,10 @@ int inet_aton(const char *cp, struct in_addr *ia);
#include <arpa/inet.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
void slirp_init(void);
void slirp_select_fill(int *pnfds,
@@ -29,4 +33,8 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
extern const char *tftp_prefix;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -149,8 +149,7 @@
#define SIZEOF_INT 4
/* Define to sizeof(char *) */
/* XXX: patch it */
#define SIZEOF_CHAR_P 4
#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8)
/* Define if you have random() */
#undef HAVE_RANDOM

View File

@@ -420,10 +420,16 @@ struct talk_request {
#endif
struct cu_header {
char dest[8];
short family;
u_short port;
u_long addr;
uint16_t d_family; // destination family
uint16_t d_port; // destination port
uint32_t d_addr; // destination address
uint16_t s_family; // source family
uint16_t s_port; // source port
uint32_t so_addr; // source address
uint32_t seqn; // sequence number
uint16_t message; // message
uint16_t data_type; // data type
uint16_t pkt_len; // packet length
} *cu_head;
switch(so->so_emu) {
@@ -610,8 +616,8 @@ struct cu_header {
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
return;
cu_head = mtod(m, struct cu_header *);
cu_head->port = addr.sin_port;
cu_head->addr = (u_long) our_addr.s_addr;
cu_head->s_port = addr.sin_port;
cu_head->so_addr = our_addr.s_addr;
}
return;

View File

@@ -94,6 +94,7 @@ struct udpstat {
extern struct udpstat udpstat;
extern struct socket udb;
struct mbuf;
void udp_init _P((void));
void udp_input _P((register struct mbuf *, int));

View File

@@ -55,6 +55,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
#elif defined (TARGET_MIPS)
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
#elif defined (TARGET_SPARC)
#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif
@@ -66,6 +68,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
#elif defined (TARGET_MIPS)
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
#elif defined (TARGET_SPARC)
#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif

View File

@@ -48,7 +48,7 @@
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
int is_user,
void *retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
target_ulong tlb_addr)
{
DATA_TYPE res;
@@ -76,7 +76,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
DATA_TYPE res;
int index;
target_ulong tlb_addr;
unsigned long physaddr;
target_phys_addr_t physaddr;
void *retaddr;
/* test if there is match for unaligned or IO access */
@@ -99,7 +99,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
is_user, retaddr);
} else {
/* unaligned access in the same page */
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
}
} else {
/* the page is not in the TLB : fill it */
@@ -117,7 +117,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
{
DATA_TYPE res, res1, res2;
int index, shift;
unsigned long physaddr;
target_phys_addr_t physaddr;
target_ulong tlb_addr, addr1, addr2;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -148,7 +148,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
res = (DATA_TYPE)res;
} else {
/* unaligned/aligned access in the same page */
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
}
} else {
/* the page is not in the TLB : fill it */
@@ -165,7 +165,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
int is_user,
void *retaddr);
static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
DATA_TYPE val,
target_ulong tlb_addr,
void *retaddr)
@@ -192,7 +192,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
DATA_TYPE val,
int is_user)
{
unsigned long physaddr;
target_phys_addr_t physaddr;
target_ulong tlb_addr;
void *retaddr;
int index;
@@ -215,7 +215,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
is_user, retaddr);
} else {
/* aligned/unaligned access in the same page */
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
}
} else {
/* the page is not in the TLB : fill it */
@@ -231,7 +231,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
int is_user,
void *retaddr)
{
unsigned long physaddr;
target_phys_addr_t physaddr;
target_ulong tlb_addr;
int index, i;
@@ -259,7 +259,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
}
} else {
/* aligned/unaligned access in the same page */
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
}
} else {
/* the page is not in the TLB : fill it */

View File

@@ -805,6 +805,23 @@ void OPPROTO op_subl_T0_T1_saturate(void)
FORCE_RET();
}
void OPPROTO op_double_T1_saturate(void)
{
int32_t val;
val = T1;
if (val >= 0x40000000) {
T1 = 0x7fffffff;
env->QF = 1;
} else if (val <= (int32_t)0xc0000000) {
T1 = 0x80000000;
env->QF = 1;
} else {
T1 = val << 1;
}
FORCE_RET();
}
/* thumb shift by immediate */
void OPPROTO op_shll_T0_im_thumb(void)
{

View File

@@ -1019,20 +1019,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0x5: /* saturating add/subtract */
rd = (insn >> 12) & 0xf;
rn = (insn >> 16) & 0xf;
gen_movl_T0_reg(s, rn);
if (op1 & 2) {
gen_movl_T1_reg(s, rn);
if (op1 & 1)
gen_op_subl_T0_T1_saturate();
else
gen_op_addl_T0_T1_saturate();
}
gen_movl_T1_reg(s, rm);
gen_movl_T0_reg(s, rm);
gen_movl_T1_reg(s, rn);
if (op1 & 2)
gen_op_double_T1_saturate();
if (op1 & 1)
gen_op_subl_T0_T1_saturate();
else
gen_op_addl_T0_T1_saturate();
gen_movl_reg_T0(s, rn);
gen_movl_reg_T0(s, rd);
break;
case 0x8: /* signed multiply */
case 0xa:
@@ -2196,7 +2191,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
int flags)
{
int i;
struct {
union {
uint32_t i;
float s;
} s0, s1;

View File

@@ -214,6 +214,12 @@
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define MSR_MCG_CAP 0x179
#define MSR_MCG_STATUS 0x17a
#define MSR_MCG_CTL 0x17b
#define MSR_PAT 0x277
#define MSR_EFER 0xc0000080
#define MSR_EFER_SCE (1 << 0)
@@ -246,6 +252,8 @@
#define CPUID_PGE (1 << 13)
#define CPUID_MCA (1 << 14)
#define CPUID_CMOV (1 << 15)
#define CPUID_PAT (1 << 16)
#define CPUID_CLFLUSH (1 << 19)
/* ... */
#define CPUID_MMX (1 << 23)
#define CPUID_FXSR (1 << 24)
@@ -474,6 +482,8 @@ typedef struct CPUX86State {
target_ulong kernelgsbase;
#endif
uint64_t pat;
/* temporary data for USE_CODE_COPY mode */
#ifdef USE_CODE_COPY
uint32_t tmp0;

View File

@@ -157,11 +157,11 @@ void helper_lldt_T0(void);
void helper_ltr_T0(void);
void helper_movl_crN_T0(int reg);
void helper_movl_drN_T0(int reg);
void helper_invlpg(unsigned int addr);
void helper_invlpg(target_ulong addr);
void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
int is_write, int is_user, int is_softmmu);
void tlb_fill(target_ulong addr, int is_write, int is_user,
@@ -190,6 +190,7 @@ void helper_idivq_EAX_T0(void);
void helper_cmpxchg8b(void);
void helper_cpuid(void);
void helper_enter_level(int level, int data32);
void helper_enter64_level(int level, int data64);
void helper_sysenter(void);
void helper_sysexit(void);
void helper_syscall(int next_eip_addend);
@@ -336,6 +337,7 @@ static inline void stfl(target_ulong ptr, float v)
#define atan2 atan2l
#define floor floorl
#define ceil ceill
#define ldexp ldexpl
#else
#define floatx_to_int32 float64_to_int32
#define floatx_to_int64 float64_to_int64

View File

@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index)
#ifdef BUGGY_GCC_DIV64
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
call it from another function */
uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den)
uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
{
*q_ptr = num / den;
return num % den;
}
int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
{
*q_ptr = num / den;
return num % den;
@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
void helper_divl_EAX_T0(void)
{
unsigned int den, q, r;
uint64_t num;
unsigned int den, r;
uint64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0;
@@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void)
q = (num / den);
r = (num % den);
#endif
if (q > 0xffffffff)
raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q;
EDX = (uint32_t)r;
}
void helper_idivl_EAX_T0(void)
{
int den, q, r;
int64_t num;
int den, r;
int64_t num, q;
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
den = T0;
@@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void)
q = (num / den);
r = (num % den);
#endif
if (q != (int32_t)q)
raise_exception(EXCP00_DIVZ);
EAX = (uint32_t)q;
EDX = (uint32_t)r;
}
@@ -1334,6 +1338,20 @@ void helper_cpuid(void)
ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
break;
case 0x80000005:
/* cache info (L1 cache) */
EAX = 0x01ff01ff;
EBX = 0x01ff01ff;
ECX = 0x40020140;
EDX = 0x40020140;
break;
case 0x80000006:
/* cache info (L2 cache) */
EAX = 0;
EBX = 0x42004200;
ECX = 0x02008140;
EDX = 0;
break;
case 0x80000008:
/* virtual & phys address size in low 2 bytes. */
EAX = 0x00003028;
@@ -1383,6 +1401,37 @@ void helper_enter_level(int level, int data32)
}
}
#ifdef TARGET_X86_64
void helper_enter64_level(int level, int data64)
{
target_ulong esp, ebp;
ebp = EBP;
esp = ESP;
if (data64) {
/* 64 bit */
esp -= 8;
while (--level) {
esp -= 8;
ebp -= 8;
stq(esp, ldq(ebp));
}
esp -= 8;
stq(esp, T1);
} else {
/* 16 bit */
esp -= 2;
while (--level) {
esp -= 2;
ebp -= 2;
stw(esp, lduw(ebp));
}
esp -= 2;
stw(esp, T1);
}
}
#endif
void helper_lldt_T0(void)
{
int selector;
@@ -1963,6 +2012,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
#endif
sp_mask = get_sp_mask(env->segs[R_SS].flags);
sp = ESP;
/* XXX: ssp is zero in 64 bit ? */
ssp = env->segs[R_SS].base;
new_eflags = 0; /* avoid warning */
#ifdef TARGET_X86_64
@@ -2271,7 +2321,7 @@ void helper_movl_drN_T0(int reg)
env->dr[reg] = T0;
}
void helper_invlpg(unsigned int addr)
void helper_invlpg(target_ulong addr)
{
cpu_x86_flush_tlb(env, addr);
}
@@ -2332,6 +2382,9 @@ void helper_wrmsr(void)
case MSR_STAR:
env->star = val;
break;
case MSR_PAT:
env->pat = val;
break;
#ifdef TARGET_X86_64
case MSR_LSTAR:
env->lstar = val;
@@ -2380,6 +2433,9 @@ void helper_rdmsr(void)
case MSR_STAR:
val = env->star;
break;
case MSR_PAT:
val = env->pat;
break;
#ifdef TARGET_X86_64
case MSR_LSTAR:
val = env->lstar;
@@ -2832,11 +2888,7 @@ void helper_frndint(void)
void helper_fscale(void)
{
CPU86_LDouble fpsrcop, fptemp;
fpsrcop = 2.0;
fptemp = pow(fpsrcop,ST1);
ST0 *= fptemp;
ST0 = ldexp (ST0, (int)(ST1));
}
void helper_fsin(void)
@@ -3202,8 +3254,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
}
}
/* XXX: overflow support */
static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
/* return TRUE if overflow */
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
{
uint64_t q, r, a1, a0;
int i, qb;
@@ -3216,6 +3268,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
*plow = q;
*phigh = r;
} else {
if (a1 >= b)
return 1;
/* XXX: use a better algorithm */
for(i = 0; i < 64; i++) {
a1 = (a1 << 1) | (a0 >> 63);
@@ -3234,9 +3288,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
*plow = a0;
*phigh = a1;
}
return 0;
}
static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
/* return TRUE if overflow */
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
{
int sa, sb;
sa = ((int64_t)*phigh < 0);
@@ -3245,11 +3301,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
sb = (b < 0);
if (sb)
b = -b;
div64(plow, phigh, b);
if (sa ^ sb)
if (div64(plow, phigh, b) != 0)
return 1;
if (sa ^ sb) {
if (*plow > (1ULL << 63))
return 1;
*plow = - *plow;
} else {
if (*plow >= (1ULL << 63))
return 1;
}
if (sa)
*phigh = - *phigh;
return 0;
}
void helper_mulq_EAX_T0(void)
@@ -3292,7 +3356,8 @@ void helper_divq_EAX_T0(void)
}
r0 = EAX;
r1 = EDX;
div64(&r0, &r1, T0);
if (div64(&r0, &r1, T0))
raise_exception(EXCP00_DIVZ);
EAX = r0;
EDX = r1;
}
@@ -3305,7 +3370,8 @@ void helper_idivq_EAX_T0(void)
}
r0 = EAX;
r1 = EDX;
idiv64(&r0, &r1, T0);
if (idiv64(&r0, &r1, T0))
raise_exception(EXCP00_DIVZ);
EAX = r0;
EDX = r1;
}

View File

@@ -106,7 +106,9 @@ CPUX86State *cpu_x86_init(void)
env->cpuid_version = (family << 8) | (model << 4) | stepping;
env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
CPUID_TSC | CPUID_MSR | CPUID_MCE |
CPUID_CX8 | CPUID_PGE | CPUID_CMOV);
CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
CPUID_PAT);
env->pat = 0x0007040600070406ULL;
env->cpuid_ext_features = 0;
env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
env->cpuid_xlevel = 0;
@@ -128,6 +130,9 @@ CPUX86State *cpu_x86_init(void)
env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
env->cpuid_xlevel = 0x80000008;
/* these features are needed for Win64 and aren't fully implemented */
env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
#endif
}
cpu_single_env = env;
@@ -250,7 +255,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
{
int eflags, i;
int eflags, i, nb;
char cc_op_name[32];
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
@@ -398,16 +403,54 @@ void cpu_dump_state(CPUState *env, FILE *f,
}
}
if (flags & X86_DUMP_FPU) {
cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
(double)env->fpregs[0].d,
(double)env->fpregs[1].d,
(double)env->fpregs[2].d,
(double)env->fpregs[3].d);
cpu_fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
(double)env->fpregs[4].d,
(double)env->fpregs[5].d,
(double)env->fpregs[7].d,
(double)env->fpregs[8].d);
int fptag;
fptag = 0;
for(i = 0; i < 8; i++) {
fptag |= ((!env->fptags[i]) << i);
}
cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
env->fpuc,
(env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
env->fpstt,
fptag,
env->mxcsr);
for(i=0;i<8;i++) {
#if defined(USE_X86LDOUBLE)
union {
long double d;
struct {
uint64_t lower;
uint16_t upper;
} l;
} tmp;
tmp.d = env->fpregs[i].d;
cpu_fprintf(f, "FPR%d=%016llx %04x",
i, tmp.l.lower, tmp.l.upper);
#else
cpu_fprintf(f, "FPR%d=%016llx",
i, env->fpregs[i].mmx.q);
#endif
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
cpu_fprintf(f, " ");
}
if (env->hflags & HF_CS64_MASK)
nb = 16;
else
nb = 8;
for(i=0;i<nb;i++) {
cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
i,
env->xmm_regs[i].XMM_L(3),
env->xmm_regs[i].XMM_L(2),
env->xmm_regs[i].XMM_L(1),
env->xmm_regs[i].XMM_L(0));
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
cpu_fprintf(f, " ");
}
}
}
@@ -508,7 +551,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
}
/* XXX: also flush 4MB pages */
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
{
tlb_flush_page(env, addr);
}

View File

@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
#endif
/* division, flags are undefined */
/* XXX: add exceptions for overflow */
void OPPROTO op_divb_AL_T0(void)
{
@@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void)
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xff;
q = (num / den);
if (q > 0xff)
raise_exception(EXCP00_DIVZ);
q &= 0xff;
r = (num % den) & 0xff;
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
@@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void)
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xff;
q = (num / den);
if (q != (int8_t)q)
raise_exception(EXCP00_DIVZ);
q &= 0xff;
r = (num % den) & 0xff;
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
@@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void)
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xffff;
q = (num / den);
if (q > 0xffff)
raise_exception(EXCP00_DIVZ);
q &= 0xffff;
r = (num % den) & 0xffff;
EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r;
@@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void)
if (den == 0) {
raise_exception(EXCP00_DIVZ);
}
q = (num / den) & 0xffff;
q = (num / den);
if (q != (int16_t)q)
raise_exception(EXCP00_DIVZ);
q &= 0xffff;
r = (num % den) & 0xffff;
EAX = (EAX & ~0xffff) | q;
EDX = (EDX & ~0xffff) | r;
@@ -898,6 +909,11 @@ void op_addw_ESP_im(void)
}
#ifdef TARGET_X86_64
void op_subq_A0_2(void)
{
A0 -= 2;
}
void op_subq_A0_8(void)
{
A0 -= 8;
@@ -929,6 +945,13 @@ void OPPROTO op_enter_level(void)
helper_enter_level(PARAM1, PARAM2);
}
#ifdef TARGET_X86_64
void OPPROTO op_enter64_level(void)
{
helper_enter64_level(PARAM1, PARAM2);
}
#endif
void OPPROTO op_sysenter(void)
{
helper_sysenter();

View File

@@ -1627,7 +1627,14 @@ static void gen_add_A0_ds_seg(DisasContext *s)
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
#ifdef TARGET_X86_64
if (CODE64(s)) {
gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
} else
#endif
{
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
}
}
}
@@ -1948,10 +1955,14 @@ static void gen_push_T0(DisasContext *s)
{
#ifdef TARGET_X86_64
if (CODE64(s)) {
/* XXX: check 16 bit behaviour */
gen_op_movq_A0_reg[R_ESP]();
gen_op_subq_A0_8();
gen_op_st_T0_A0[OT_QUAD + s->mem_index]();
if (s->dflag) {
gen_op_subq_A0_8();
gen_op_st_T0_A0[OT_QUAD + s->mem_index]();
} else {
gen_op_subq_A0_2();
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
}
gen_op_movq_ESP_A0();
} else
#endif
@@ -1985,10 +1996,14 @@ static void gen_push_T1(DisasContext *s)
{
#ifdef TARGET_X86_64
if (CODE64(s)) {
/* XXX: check 16 bit behaviour */
gen_op_movq_A0_reg[R_ESP]();
gen_op_subq_A0_8();
gen_op_st_T1_A0[OT_QUAD + s->mem_index]();
if (s->dflag) {
gen_op_subq_A0_8();
gen_op_st_T1_A0[OT_QUAD + s->mem_index]();
} else {
gen_op_subq_A0_2();
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
}
gen_op_movq_ESP_A0();
} else
#endif
@@ -2020,9 +2035,8 @@ static void gen_pop_T0(DisasContext *s)
{
#ifdef TARGET_X86_64
if (CODE64(s)) {
/* XXX: check 16 bit behaviour */
gen_op_movq_A0_reg[R_ESP]();
gen_op_ld_T0_A0[OT_QUAD + s->mem_index]();
gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index]();
} else
#endif
{
@@ -2041,7 +2055,7 @@ static void gen_pop_T0(DisasContext *s)
static void gen_pop_update(DisasContext *s)
{
#ifdef TARGET_X86_64
if (CODE64(s)) {
if (CODE64(s) && s->dflag) {
gen_stack_update(s, 8);
} else
#endif
@@ -2105,26 +2119,48 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
{
int ot, opsize;
ot = s->dflag + OT_WORD;
level &= 0x1f;
opsize = 2 << s->dflag;
#ifdef TARGET_X86_64
if (CODE64(s)) {
ot = s->dflag ? OT_QUAD : OT_WORD;
opsize = 1 << ot;
gen_op_movl_A0_ESP();
gen_op_addq_A0_im(-opsize);
gen_op_movl_T1_A0();
gen_op_movl_A0_ESP();
gen_op_addl_A0_im(-opsize);
if (!s->ss32)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
/* push bp */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_st_T0_A0[ot + s->mem_index]();
if (level) {
gen_op_enter_level(level, s->dflag);
/* push bp */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_st_T0_A0[ot + s->mem_index]();
if (level) {
gen_op_enter64_level(level, (ot == OT_QUAD));
}
gen_op_mov_reg_T1[ot][R_EBP]();
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
gen_op_mov_reg_T1[OT_QUAD][R_ESP]();
} else
#endif
{
ot = s->dflag + OT_WORD;
opsize = 2 << s->dflag;
gen_op_movl_A0_ESP();
gen_op_addl_A0_im(-opsize);
if (!s->ss32)
gen_op_andl_A0_ffff();
gen_op_movl_T1_A0();
if (s->addseg)
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
/* push bp */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_st_T0_A0[ot + s->mem_index]();
if (level) {
gen_op_enter_level(level, s->dflag);
}
gen_op_mov_reg_T1[ot][R_EBP]();
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
}
gen_op_mov_reg_T1[ot][R_EBP]();
gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
}
static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
@@ -2901,7 +2937,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (mod != 3)
goto illegal_op;
#ifdef TARGET_X86_64
if (CODE64(s)) {
if (s->aflag == 2) {
gen_op_movq_A0_reg[R_EDI]();
} else
#endif
@@ -3697,7 +3733,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 0xc8: /* enter */
{
/* XXX: long mode support */
int level;
val = lduw_code(s->pc);
s->pc += 2;
@@ -3707,7 +3742,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 0xc9: /* leave */
/* XXX: exception not precise (ESP is updated before potential exception) */
/* XXX: may be invalid for 16 bit in long mode */
if (CODE64(s)) {
gen_op_mov_TN_reg[OT_QUAD][0][R_EBP]();
gen_op_mov_reg_T0[OT_QUAD][R_ESP]();
@@ -3926,7 +3960,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
#ifdef TARGET_X86_64
if (CODE64(s)) {
if (s->aflag == 2) {
offset_addr = ldq_code(s->pc);
s->pc += 8;
if (offset_addr == (int32_t)offset_addr)
@@ -3955,7 +3989,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 0xd7: /* xlat */
#ifdef TARGET_X86_64
if (CODE64(s)) {
if (s->aflag == 2) {
gen_op_movq_A0_reg[R_EBX]();
gen_op_addq_A0_AL();
} else
@@ -4779,6 +4813,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
val = ldsw_code(s->pc);
s->pc += 2;
gen_pop_T0(s);
if (CODE64(s) && s->dflag)
s->dflag = 2;
gen_stack_update(s, val + (2 << s->dflag));
if (s->dflag == 0)
gen_op_andl_T0_ffff();
@@ -5782,14 +5818,30 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 5: /* lfence */
case 6: /* mfence */
case 7: /* sfence */
if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
goto illegal_op;
break;
case 7: /* sfence / clflush */
if ((modrm & 0xc7) == 0xc0) {
/* sfence */
if (!(s->cpuid_features & CPUID_SSE))
goto illegal_op;
} else {
/* clflush */
if (!(s->cpuid_features & CPUID_CLFLUSH))
goto illegal_op;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
}
break;
default:
goto illegal_op;
}
break;
case 0x10d: /* prefetch */
modrm = ldub_code(s->pc++);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
/* ignore for now */
break;
case 0x110 ... 0x117:
case 0x128 ... 0x12f:
case 0x150 ... 0x177:

247
target-mips/cpu.h Normal file
View File

@@ -0,0 +1,247 @@
#if !defined (__MIPS_CPU_H__)
#define __MIPS_CPU_H__
#include "mips-defs.h"
#include "cpu-defs.h"
#include "config.h"
#include "softfloat.h"
typedef union fpr_t fpr_t;
union fpr_t {
double d;
float f;
uint32_t u[2];
};
#if defined(MIPS_USES_R4K_TLB)
typedef struct tlb_t tlb_t;
struct tlb_t {
target_ulong VPN;
target_ulong end;
uint8_t ASID;
uint8_t G;
uint8_t C[2];
uint8_t V[2];
uint8_t D[2];
target_ulong PFN[2];
};
#endif
typedef struct CPUMIPSState CPUMIPSState;
struct CPUMIPSState {
/* General integer registers */
target_ulong gpr[32];
/* Special registers */
target_ulong PC;
uint32_t HI, LO;
uint32_t DCR; /* ? */
#if defined(MIPS_USES_FPU)
/* Floating point registers */
fpr_t fpr[16];
/* Floating point special purpose registers */
uint32_t fcr0;
uint32_t fcr25;
uint32_t fcr26;
uint32_t fcr28;
uint32_t fcsr;
#endif
#if defined(MIPS_USES_R4K_TLB)
tlb_t tlb[16];
#endif
uint32_t CP0_index;
uint32_t CP0_random;
uint32_t CP0_EntryLo0;
uint32_t CP0_EntryLo1;
uint32_t CP0_Context;
uint32_t CP0_PageMask;
uint32_t CP0_Wired;
uint32_t CP0_BadVAddr;
uint32_t CP0_Count;
uint32_t CP0_EntryHi;
uint32_t CP0_Compare;
uint32_t CP0_Status;
#define CP0St_CU3 31
#define CP0St_CU2 30
#define CP0St_CU1 29
#define CP0St_CU0 28
#define CP0St_RP 27
#define CP0St_RE 25
#define CP0St_BEV 22
#define CP0St_TS 21
#define CP0St_SR 20
#define CP0St_NMI 19
#define CP0St_IM 8
#define CP0St_UM 4
#define CP0St_ERL 2
#define CP0St_EXL 1
#define CP0St_IE 0
uint32_t CP0_Cause;
#define CP0Ca_IV 23
uint32_t CP0_EPC;
uint32_t CP0_PRid;
uint32_t CP0_Config0;
#define CP0C0_M 31
#define CP0C0_K23 28
#define CP0C0_KU 25
#define CP0C0_MDU 20
#define CP0C0_MM 17
#define CP0C0_BM 16
#define CP0C0_BE 15
#define CP0C0_AT 13
#define CP0C0_AR 10
#define CP0C0_MT 7
#define CP0C0_K0 0
uint32_t CP0_Config1;
#define CP0C1_MMU 25
#define CP0C1_IS 22
#define CP0C1_IL 19
#define CP0C1_IA 16
#define CP0C1_DS 13
#define CP0C1_DL 10
#define CP0C1_DA 7
#define CP0C1_PC 4
#define CP0C1_WR 3
#define CP0C1_CA 2
#define CP0C1_EP 1
#define CP0C1_FP 0
uint32_t CP0_LLAddr;
uint32_t CP0_WatchLo;
uint32_t CP0_WatchHi;
uint32_t CP0_Debug;
#define CPDB_DBD 31
#define CP0DB_DM 30
#define CP0DB_LSNM 28
#define CP0DB_Doze 27
#define CP0DB_Halt 26
#define CP0DB_CNT 25
#define CP0DB_IBEP 24
#define CP0DB_DBEP 21
#define CP0DB_IEXI 20
#define CP0DB_VER 15
#define CP0DB_DEC 10
#define CP0DB_SSt 8
#define CP0DB_DINT 5
#define CP0DB_DIB 4
#define CP0DB_DDBS 3
#define CP0DB_DDBL 2
#define CP0DB_DBp 1
#define CP0DB_DSS 0
uint32_t CP0_DEPC;
uint32_t CP0_TagLo;
uint32_t CP0_DataLo;
uint32_t CP0_ErrorEPC;
uint32_t CP0_DESAVE;
/* Qemu */
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
double ft0, ft1, ft2;
#endif
struct QEMUTimer *timer; /* Internal timer */
int interrupt_request;
jmp_buf jmp_env;
int exception_index;
int error_code;
int user_mode_only; /* user mode only simulation */
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
#define MIPS_HFLAGS_TMASK 0x00FF
#define MIPS_HFLAG_MODE 0x001F /* execution modes */
#define MIPS_HFLAG_UM 0x0001 /* user mode */
#define MIPS_HFLAG_ERL 0x0002 /* Error mode */
#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */
#define MIPS_HFLAG_DM 0x0008 /* Debug mode */
#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */
/* Those flags keep the branch state if the translation is interrupted
* between the branch instruction and the delay slot
*/
#define MIPS_HFLAG_BMASK 0x0F00
#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */
#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */
#define MIPS_HFLAG_BL 0x0400 /* Likely branch */
#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */
target_ulong btarget; /* Jump / branch target */
int bcond; /* Branch condition (if needed) */
struct TranslationBlock *current_tb; /* currently executing TB */
/* soft mmu support */
/* in order to avoid passing too many arguments to the memory
write helpers, we store some rarely used information in the CPU
context) */
target_ulong mem_write_pc; /* host pc at which the memory was
written */
unsigned long mem_write_vaddr; /* target virtual addr at which the
memory was written */
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
/* ice debug support */
target_ulong breakpoints[MAX_BREAKPOINTS];
int nb_breakpoints;
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
/* user data */
void *opaque;
};
#include "cpu-all.h"
/* Memory access type :
* may be needed for precise access rights control and precise exceptions.
*/
enum {
/* 1 bit to define user level / supervisor access */
ACCESS_USER = 0x00,
ACCESS_SUPER = 0x01,
/* 1 bit to indicate direction */
ACCESS_STORE = 0x02,
/* Type of instruction that generated the access */
ACCESS_CODE = 0x10, /* Code fetch access */
ACCESS_INT = 0x20, /* Integer load/store access */
ACCESS_FLOAT = 0x30, /* floating point load/store access */
};
/* Exceptions */
enum {
EXCP_NONE = -1,
EXCP_RESET = 0,
EXCP_SRESET,
EXCP_DSS,
EXCP_DINT,
EXCP_NMI,
EXCP_MCHECK,
EXCP_EXT_INTERRUPT,
EXCP_DFWATCH,
EXCP_DIB, /* 8 */
EXCP_IWATCH,
EXCP_AdEL,
EXCP_AdES,
EXCP_TLBF,
EXCP_IBE,
EXCP_DBp,
EXCP_SYSCALL,
EXCP_BREAK,
EXCP_CpU, /* 16 */
EXCP_RI,
EXCP_OVERFLOW,
EXCP_TRAP,
EXCP_DDBS,
EXCP_DWATCH,
EXCP_LAE, /* 22 */
EXCP_SAE,
EXCP_LTLBL,
EXCP_TLBL,
EXCP_TLBS,
EXCP_DBE,
EXCP_DDBL,
EXCP_MTCP0 = 0x104, /* mtmsr instruction: */
/* may change privilege level */
EXCP_BRANCH = 0x108, /* branch instruction */
EXCP_ERET = 0x10C, /* return from interrupt */
EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
EXCP_FLUSH = 0x109,
};
int cpu_mips_exec(CPUMIPSState *s);
CPUMIPSState *cpu_mips_init(void);
uint32_t cpu_mips_get_clock (void);
#endif /* !defined (__MIPS_CPU_H__) */

166
target-mips/exec.h Normal file
View File

@@ -0,0 +1,166 @@
#if !defined(__QEMU_MIPS_EXEC_H__)
#define __QEMU_MIPS_EXEC_H__
#define DEBUG_OP
#include "mips-defs.h"
#include "dyngen-exec.h"
register struct CPUMIPSState *env asm(AREG0);
#if defined (USE_64BITS_REGS)
typedef int64_t host_int_t;
typedef uint64_t host_uint_t;
#else
typedef int32_t host_int_t;
typedef uint32_t host_uint_t;
#endif
register host_uint_t T0 asm(AREG1);
register host_uint_t T1 asm(AREG2);
register host_uint_t T2 asm(AREG3);
#if defined (USE_HOST_FLOAT_REGS)
register double FT0 asm(FREG0);
register double FT1 asm(FREG1);
register double FT2 asm(FREG2);
#else
#define FT0 (env->ft0.d)
#define FT1 (env->ft1.d)
#define FT2 (env->ft2.d)
#endif
#if defined (DEBUG_OP)
#define RETURN() __asm__ __volatile__("nop");
#else
#define RETURN() __asm__ __volatile__("");
#endif
#include "cpu.h"
#include "exec-all.h"
#if !defined(CONFIG_USER_ONLY)
#define ldul_user ldl_user
#define ldul_kernel ldl_kernel
#define ACCESS_TYPE 0
#define MEMSUFFIX _kernel
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ACCESS_TYPE 1
#define MEMSUFFIX _user
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
/* these access are slower, they must be as rare as possible */
#define ACCESS_TYPE 2
#define MEMSUFFIX _data
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ldub(p) ldub_data(p)
#define ldsb(p) ldsb_data(p)
#define lduw(p) lduw_data(p)
#define ldsw(p) ldsw_data(p)
#define ldl(p) ldl_data(p)
#define ldq(p) ldq_data(p)
#define stb(p, v) stb_data(p, v)
#define stw(p, v) stw_data(p, v)
#define stl(p, v) stl_data(p, v)
#define stq(p, v) stq_data(p, v)
#endif /* !defined(CONFIG_USER_ONLY) */
static inline void env_to_regs(void)
{
}
static inline void regs_to_env(void)
{
}
#if (HOST_LONG_BITS == 32)
void do_mult (void);
void do_multu (void);
void do_madd (void);
void do_maddu (void);
void do_msub (void);
void do_msubu (void);
#endif
void do_mfc0(int reg, int sel);
void do_mtc0(int reg, int sel);
void do_tlbwi (void);
void do_tlbwr (void);
void do_tlbp (void);
void do_tlbr (void);
void do_lwl_raw (void);
void do_lwr_raw (void);
void do_swl_raw (void);
void do_swr_raw (void);
#if !defined(CONFIG_USER_ONLY)
void do_lwl_user (void);
void do_lwl_kernel (void);
void do_lwr_user (void);
void do_lwr_kernel (void);
void do_swl_user (void);
void do_swl_kernel (void);
void do_swr_user (void);
void do_swr_kernel (void);
#endif
void do_pmon (int function);
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu);
void do_interrupt (CPUState *env);
void cpu_loop_exit(void);
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
void cpu_mips_irqctrl_init (void);
uint32_t cpu_mips_get_random (CPUState *env);
uint32_t cpu_mips_get_count (CPUState *env);
void cpu_mips_store_count (CPUState *env, uint32_t value);
void cpu_mips_store_compare (CPUState *env, uint32_t value);
void cpu_mips_clock_init (CPUState *env);
#endif /* !defined(__QEMU_MIPS_EXEC_H__) */

422
target-mips/helper.c Normal file
View File

@@ -0,0 +1,422 @@
/*
* MIPS emulation helpers for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <assert.h>
#include "cpu.h"
#include "exec-all.h"
/* MIPS32 4K MMU emulation */
#ifdef MIPS_USES_R4K_TLB
static int map_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type)
{
tlb_t *tlb;
target_ulong tag;
uint8_t ASID;
int i, n;
int ret;
ret = -2;
tag = (address & 0xFFFFE000);
ASID = env->CP0_EntryHi & 0x000000FF;
for (i = 0; i < MIPS_TLB_NB; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) &&
tlb->VPN == tag && address < tlb->end) {
/* TLB match */
n = (address >> 12) & 1;
/* Check access rights */
if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) {
*physical = tlb->PFN[n] | (address & 0xFFF);
*prot = PAGE_READ;
if (tlb->D[n])
*prot |= PAGE_WRITE;
return 0;
} else if (!(tlb->V[n] & 2)) {
return -3;
} else {
return -4;
}
}
}
return ret;
}
#endif
int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type)
{
int user_mode;
int ret;
/* User mode can only access useg */
user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0;
#if 0
if (logfile) {
fprintf(logfile, "user mode %d h %08x\n",
user_mode, env->hflags);
}
#endif
if (user_mode && address > 0x7FFFFFFFUL)
return -1;
ret = 0;
if (address < 0x80000000UL) {
if (!(env->hflags & MIPS_HFLAG_ERL)) {
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
*physical = address + 0x40000000UL;
*prot = PAGE_READ | PAGE_WRITE;
#endif
} else {
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
}
} else if (address < 0xA0000000UL) {
/* kseg0 */
/* XXX: check supervisor mode */
*physical = address - 0x80000000UL;
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xC0000000UL) {
/* kseg1 */
/* XXX: check supervisor mode */
*physical = address - 0xA0000000UL;
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xE0000000UL) {
/* kseg2 */
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
#endif
} else {
/* kseg3 */
/* XXX: check supervisor mode */
/* XXX: debug segment is not emulated */
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
#endif
}
#if 0
if (logfile) {
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
access_type, *physical, *prot, ret);
}
#endif
return ret;
}
#if defined(CONFIG_USER_ONLY)
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#else
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
target_ulong phys_addr;
int prot;
if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
return -1;
return phys_addr;
}
void cpu_mips_init_mmu (CPUState *env)
{
}
#endif /* !defined(CONFIG_USER_ONLY) */
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
target_ulong physical;
int prot;
int exception = 0, error_code = 0;
int access_type;
int ret = 0;
if (logfile) {
cpu_dump_state(env, logfile, fprintf, 0);
fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
__func__, env->PC, address, rw, is_user, is_softmmu);
}
/* data access */
/* XXX: put correct access by using cpu_restore_state()
correctly */
access_type = ACCESS_INT;
if (env->user_mode_only) {
/* user mode only emulation */
ret = -2;
goto do_fault;
}
ret = get_physical_address(env, &physical, &prot,
address, rw, access_type);
if (logfile) {
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
__func__, address, ret, physical, prot);
}
if (ret == 0) {
ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
is_user, is_softmmu);
} else if (ret < 0) {
do_fault:
switch (ret) {
default:
case -1:
/* Reference to kernel address from user mode or supervisor mode */
/* Reference to supervisor address from user mode */
if (rw)
exception = EXCP_AdES;
else
exception = EXCP_AdEL;
break;
case -2:
/* No TLB match for a mapped address */
if (rw)
exception = EXCP_TLBS;
else
exception = EXCP_TLBL;
error_code = 1;
break;
case -3:
/* TLB match with no valid bit */
if (rw)
exception = EXCP_TLBS;
else
exception = EXCP_TLBL;
error_code = 0;
break;
case -4:
/* TLB match but 'D' bit is cleared */
exception = EXCP_LTLBL;
break;
}
/* Raise exception */
env->CP0_BadVAddr = address;
env->CP0_Context = (env->CP0_Context & 0xff800000) |
((address >> 8) & 0x007ffff0);
env->CP0_EntryHi =
(env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000);
env->exception_index = exception;
env->error_code = error_code;
ret = 1;
}
return ret;
}
void do_interrupt (CPUState *env)
{
target_ulong pc, offset;
int cause = -1;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index);
}
if (env->exception_index == EXCP_EXT_INTERRUPT &&
(env->hflags & MIPS_HFLAG_DM))
env->exception_index = EXCP_DINT;
offset = 0x180;
switch (env->exception_index) {
case EXCP_DSS:
env->CP0_Debug |= 1 << CP0DB_DSS;
/* Debug single step cannot be raised inside a delay slot and
* resume will always occur on the next instruction
* (but we assume the pc has always been updated during
* code translation).
*/
env->CP0_DEPC = env->PC;
goto enter_debug_mode;
case EXCP_DINT:
env->CP0_Debug |= 1 << CP0DB_DINT;
goto set_DEPC;
case EXCP_DIB:
env->CP0_Debug |= 1 << CP0DB_DIB;
goto set_DEPC;
case EXCP_DBp:
env->CP0_Debug |= 1 << CP0DB_DBp;
goto set_DEPC;
case EXCP_DDBS:
env->CP0_Debug |= 1 << CP0DB_DDBS;
goto set_DEPC;
case EXCP_DDBL:
env->CP0_Debug |= 1 << CP0DB_DDBL;
goto set_DEPC;
set_DEPC:
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_DEPC = env->PC - 4;
} else {
env->CP0_DEPC = env->PC;
}
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM;
/* EJTAG probe trap enable is not implemented... */
pc = 0xBFC00480;
break;
case EXCP_RESET:
#ifdef MIPS_USES_R4K_TLB
env->CP0_random = MIPS_TLB_NB - 1;
#endif
env->CP0_Wired = 0;
env->CP0_Config0 = MIPS_CONFIG0;
#if defined (MIPS_CONFIG1)
env->CP0_Config1 = MIPS_CONFIG1;
#endif
#if defined (MIPS_CONFIG2)
env->CP0_Config2 = MIPS_CONFIG2;
#endif
#if defined (MIPS_CONFIG3)
env->CP0_Config3 = MIPS_CONFIG3;
#endif
env->CP0_WatchLo = 0;
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
goto set_error_EPC;
case EXCP_SRESET:
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
(1 << CP0St_SR);
env->CP0_WatchLo = 0;
goto set_error_EPC;
case EXCP_NMI:
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
(1 << CP0St_NMI);
set_error_EPC:
env->hflags = MIPS_HFLAG_ERL;
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_ErrorEPC = env->PC - 4;
} else {
env->CP0_ErrorEPC = env->PC;
}
pc = 0xBFC00000;
break;
case EXCP_MCHECK:
cause = 24;
goto set_EPC;
case EXCP_EXT_INTERRUPT:
cause = 0;
if (env->CP0_Cause & (1 << CP0Ca_IV))
offset = 0x200;
goto set_EPC;
case EXCP_DWATCH:
cause = 23;
/* XXX: TODO: manage defered watch exceptions */
goto set_EPC;
case EXCP_AdEL:
case EXCP_AdES:
cause = 4;
goto set_EPC;
case EXCP_TLBL:
case EXCP_TLBF:
cause = 2;
if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
offset = 0x000;
goto set_EPC;
case EXCP_IBE:
cause = 6;
goto set_EPC;
case EXCP_DBE:
cause = 7;
goto set_EPC;
case EXCP_SYSCALL:
cause = 8;
goto set_EPC;
case EXCP_BREAK:
cause = 9;
goto set_EPC;
case EXCP_RI:
cause = 10;
goto set_EPC;
case EXCP_CpU:
cause = 11;
/* XXX: fill in the faulty unit number */
goto set_EPC;
case EXCP_OVERFLOW:
cause = 12;
goto set_EPC;
case EXCP_TRAP:
cause = 13;
goto set_EPC;
case EXCP_LTLBL:
cause = 1;
goto set_EPC;
case EXCP_TLBS:
cause = 3;
if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
offset = 0x000;
goto set_EPC;
set_EPC:
if (env->CP0_Status & (1 << CP0St_BEV)) {
pc = 0xBFC00200;
} else {
pc = 0x80000000;
}
env->hflags |= MIPS_HFLAG_EXL;
pc += offset;
env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_EPC = env->PC - 4;
env->CP0_Cause |= 0x80000000;
} else {
env->CP0_EPC = env->PC;
env->CP0_Cause &= ~0x80000000;
}
break;
default:
if (logfile) {
fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
env->exception_index);
}
printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
exit(1);
}
env->PC = pc;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
" S %08x C %08x A %08x D %08x\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
env->exception_index = EXCP_NONE;
}

58
target-mips/mips-defs.h Normal file
View File

@@ -0,0 +1,58 @@
#if !defined (__QEMU_MIPS_DEFS_H__)
#define __QEMU_MIPS_DEFS_H__
/* If we want to use 64 bits host regs... */
//#define USE_64BITS_REGS
/* If we want to use host float regs... */
//#define USE_HOST_FLOAT_REGS
enum {
MIPS_R4Kc = 0x00018000,
MIPS_R4Kp = 0x00018300,
};
/* Emulate MIPS R4Kc for now */
#define MIPS_CPU MIPS_R4Kc
#if (MIPS_CPU == MIPS_R4Kc)
/* 32 bits target */
#define TARGET_LONG_BITS 32
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
#define MIPS_USES_R4K_EXT
/* Uses MIPS R4Kc TLB model */
#define MIPS_USES_R4K_TLB
#define MIPS_TLB_NB 16
/* Have config1, runs in big-endian mode, uses TLB */
#define MIPS_CONFIG0 \
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \
(1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0))
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
* 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
* no performance counters, watch registers present, no code compression,
* EJTAG present, no FPU
*/
#define MIPS_CONFIG1 \
((15 << CP0C1_MMU) | \
(0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
(0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
(1 << CP0C1_EP) | (0 << CP0C1_FP))
#elif defined (MIPS_CPU == MIPS_R4Kp)
/* 32 bits target */
#define TARGET_LONG_BITS 32
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
#define MIPS_USES_R4K_EXT
/* Uses MIPS R4Km FPM MMU model */
#define MIPS_USES_R4K_FPM
#else
#error "MIPS CPU not defined"
/* Remainder for other flags */
//#define TARGET_MIPS64
//define MIPS_USES_FPU
#endif
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */

668
target-mips/op.c Normal file
View File

@@ -0,0 +1,668 @@
/*
* MIPS emulation micro-operations for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "exec.h"
#ifndef CALL_FROM_TB0
#define CALL_FROM_TB0(func) func();
#endif
#ifndef CALL_FROM_TB1
#define CALL_FROM_TB1(func, arg0) func(arg0);
#endif
#ifndef CALL_FROM_TB1_CONST16
#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
#endif
#ifndef CALL_FROM_TB2
#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
#endif
#ifndef CALL_FROM_TB2_CONST16
#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
CALL_FROM_TB2(func, arg0, arg1);
#endif
#ifndef CALL_FROM_TB3
#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
#endif
#ifndef CALL_FROM_TB4
#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
func(arg0, arg1, arg2, arg3);
#endif
#define REG 1
#include "op_template.c"
#undef REG
#define REG 2
#include "op_template.c"
#undef REG
#define REG 3
#include "op_template.c"
#undef REG
#define REG 4
#include "op_template.c"
#undef REG
#define REG 5
#include "op_template.c"
#undef REG
#define REG 6
#include "op_template.c"
#undef REG
#define REG 7
#include "op_template.c"
#undef REG
#define REG 8
#include "op_template.c"
#undef REG
#define REG 9
#include "op_template.c"
#undef REG
#define REG 10
#include "op_template.c"
#undef REG
#define REG 11
#include "op_template.c"
#undef REG
#define REG 12
#include "op_template.c"
#undef REG
#define REG 13
#include "op_template.c"
#undef REG
#define REG 14
#include "op_template.c"
#undef REG
#define REG 15
#include "op_template.c"
#undef REG
#define REG 16
#include "op_template.c"
#undef REG
#define REG 17
#include "op_template.c"
#undef REG
#define REG 18
#include "op_template.c"
#undef REG
#define REG 19
#include "op_template.c"
#undef REG
#define REG 20
#include "op_template.c"
#undef REG
#define REG 21
#include "op_template.c"
#undef REG
#define REG 22
#include "op_template.c"
#undef REG
#define REG 23
#include "op_template.c"
#undef REG
#define REG 24
#include "op_template.c"
#undef REG
#define REG 25
#include "op_template.c"
#undef REG
#define REG 26
#include "op_template.c"
#undef REG
#define REG 27
#include "op_template.c"
#undef REG
#define REG 28
#include "op_template.c"
#undef REG
#define REG 29
#include "op_template.c"
#undef REG
#define REG 30
#include "op_template.c"
#undef REG
#define REG 31
#include "op_template.c"
#undef REG
#define TN T0
#include "op_template.c"
#undef TN
#define TN T1
#include "op_template.c"
#undef TN
#define TN T2
#include "op_template.c"
#undef TN
void op_dup_T0 (void)
{
T2 = T0;
RETURN();
}
void op_load_HI (void)
{
T0 = env->HI;
RETURN();
}
void op_store_HI (void)
{
env->HI = T0;
RETURN();
}
void op_load_LO (void)
{
T0 = env->LO;
RETURN();
}
void op_store_LO (void)
{
env->LO = T0;
RETURN();
}
/* Load and store */
#define MEMSUFFIX _raw
#include "op_mem.c"
#undef MEMSUFFIX
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "op_mem.c"
#undef MEMSUFFIX
#define MEMSUFFIX _kernel
#include "op_mem.c"
#undef MEMSUFFIX
#endif
/* Arithmetic */
void op_add (void)
{
T0 += T1;
RETURN();
}
void op_addo (void)
{
target_ulong tmp;
tmp = T0;
T0 += T1;
if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
void op_sub (void)
{
T0 -= T1;
RETURN();
}
void op_subo (void)
{
target_ulong tmp;
tmp = T0;
T0 = (int32_t)T0 - (int32_t)T1;
if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
void op_mul (void)
{
T0 = (int32_t)T0 * (int32_t)T1;
RETURN();
}
void op_div (void)
{
if (T1 != 0) {
env->LO = (int32_t)T0 / (int32_t)T1;
env->HI = (int32_t)T0 % (int32_t)T1;
}
RETURN();
}
void op_divu (void)
{
if (T1 != 0) {
env->LO = T0 / T1;
env->HI = T0 % T1;
}
RETURN();
}
/* Logical */
void op_and (void)
{
T0 &= T1;
RETURN();
}
void op_nor (void)
{
T0 = ~(T0 | T1);
RETURN();
}
void op_or (void)
{
T0 |= T1;
RETURN();
}
void op_xor (void)
{
T0 ^= T1;
RETURN();
}
void op_sll (void)
{
T0 = T0 << T1;
RETURN();
}
void op_sra (void)
{
T0 = (int32_t)T0 >> T1;
RETURN();
}
void op_srl (void)
{
T0 = T0 >> T1;
RETURN();
}
void op_sllv (void)
{
T0 = T1 << (T0 & 0x1F);
RETURN();
}
void op_srav (void)
{
T0 = (int32_t)T1 >> (T0 & 0x1F);
RETURN();
}
void op_srlv (void)
{
T0 = T1 >> (T0 & 0x1F);
RETURN();
}
void op_clo (void)
{
int n;
if (T0 == (target_ulong)-1) {
T0 = 32;
} else {
for (n = 0; n < 32; n++) {
if (!(T0 & (1 << 31)))
break;
T0 = T0 << 1;
}
T0 = n;
}
RETURN();
}
void op_clz (void)
{
int n;
if (T0 == 0) {
T0 = 32;
} else {
for (n = 0; n < 32; n++) {
if (T0 & (1 << 31))
break;
T0 = T0 << 1;
}
T0 = n;
}
RETURN();
}
/* 64 bits arithmetic */
#if (HOST_LONG_BITS == 64)
static inline uint64_t get_HILO (void)
{
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
}
static inline void set_HILO (uint64_t HILO)
{
env->LO = HILO & 0xFFFFFFFF;
env->HI = HILO >> 32;
}
void op_mult (void)
{
set_HILO((int64_t)T0 * (int64_t)T1);
RETURN();
}
void op_multu (void)
{
set_HILO((uint64_t)T0 * (uint64_t)T1);
RETURN();
}
void op_madd (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() + tmp);
RETURN();
}
void op_maddu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() + tmp);
RETURN();
}
void op_msub (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() - tmp);
RETURN();
}
void op_msubu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() - tmp);
RETURN();
}
#else
void op_mult (void)
{
CALL_FROM_TB0(do_mult);
RETURN();
}
void op_multu (void)
{
CALL_FROM_TB0(do_multu);
RETURN();
}
void op_madd (void)
{
CALL_FROM_TB0(do_madd);
RETURN();
}
void op_maddu (void)
{
CALL_FROM_TB0(do_maddu);
RETURN();
}
void op_msub (void)
{
CALL_FROM_TB0(do_msub);
RETURN();
}
void op_msubu (void)
{
CALL_FROM_TB0(do_msubu);
RETURN();
}
#endif
/* Conditional moves */
void op_movn (void)
{
if (T1 != 0)
env->gpr[PARAM1] = T0;
RETURN();
}
void op_movz (void)
{
if (T1 == 0)
env->gpr[PARAM1] = T0;
RETURN();
}
/* Tests */
#define OP_COND(name, cond) \
void glue(op_, name) (void) \
{ \
if (cond) { \
T0 = 1; \
} else { \
T0 = 0; \
} \
RETURN(); \
}
OP_COND(eq, T0 == T1);
OP_COND(ne, T0 != T1);
OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
OP_COND(geu, T0 >= T1);
OP_COND(lt, (int32_t)T0 < (int32_t)T1);
OP_COND(ltu, T0 < T1);
OP_COND(gez, (int32_t)T0 >= 0);
OP_COND(gtz, (int32_t)T0 > 0);
OP_COND(lez, (int32_t)T0 <= 0);
OP_COND(ltz, (int32_t)T0 < 0);
/* Branchs */
//#undef USE_DIRECT_JUMP
#define EIP env->PC
/* Branch to register */
void op_save_breg_target (void)
{
env->btarget = T2;
}
void op_restore_breg_target (void)
{
T2 = env->btarget;
}
void op_breg (void)
{
env->PC = T2;
RETURN();
}
/* Unconditional branch */
void op_branch (void)
{
JUMP_TB(branch, PARAM1, 0, PARAM2);
RETURN();
}
void op_save_btarget (void)
{
env->btarget = PARAM1;
RETURN();
}
/* Conditional branch */
void op_set_bcond (void)
{
T2 = T0;
RETURN();
}
void op_save_bcond (void)
{
env->bcond = T2;
RETURN();
}
void op_restore_bcond (void)
{
T2 = env->bcond;
RETURN();
}
void op_bcond (void)
{
if (T2) {
JUMP_TB(bcond, PARAM1, 0, PARAM2);
} else {
JUMP_TB(bcond, PARAM1, 1, PARAM3);
}
RETURN();
}
/* Likely branch (used to skip the delay slot) */
void op_blikely (void)
{
/* If the test is false, skip the delay slot */
if (T2 == 0) {
env->hflags = PARAM3;
JUMP_TB(blikely, PARAM1, 1, PARAM2);
}
RETURN();
}
/* CP0 functions */
void op_mfc0 (void)
{
CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
RETURN();
}
void op_mtc0 (void)
{
CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
RETURN();
}
#if defined(MIPS_USES_R4K_TLB)
void op_tlbwi (void)
{
CALL_FROM_TB0(do_tlbwi);
RETURN();
}
void op_tlbwr (void)
{
CALL_FROM_TB0(do_tlbwr);
RETURN();
}
void op_tlbp (void)
{
CALL_FROM_TB0(do_tlbp);
RETURN();
}
void op_tlbr (void)
{
CALL_FROM_TB0(do_tlbr);
RETURN();
}
#endif
/* Specials */
void op_pmon (void)
{
CALL_FROM_TB1(do_pmon, PARAM1);
}
void op_trap (void)
{
if (T0) {
CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
}
RETURN();
}
void op_set_lladdr (void)
{
env->CP0_LLAddr = T2;
}
void debug_eret (void);
void op_eret (void)
{
CALL_FROM_TB0(debug_eret);
if (env->hflags & MIPS_HFLAG_ERL) {
env->PC = env->CP0_ErrorEPC;
env->hflags &= ~MIPS_HFLAG_ERL;
} else {
env->PC = env->CP0_EPC;
env->hflags &= ~MIPS_HFLAG_EXL;
}
env->CP0_LLAddr = 1;
}
void op_deret (void)
{
CALL_FROM_TB0(debug_eret);
env->PC = env->CP0_DEPC;
}
void op_save_state (void)
{
env->hflags = PARAM1;
RETURN();
}
void op_save_pc (void)
{
env->PC = PARAM1;
RETURN();
}
void op_raise_exception (void)
{
CALL_FROM_TB1(do_raise_exception, PARAM1);
RETURN();
}
void op_raise_exception_err (void)
{
CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
RETURN();
}
void op_exit_tb (void)
{
EXIT_TB();
}

677
target-mips/op_helper.c Normal file
View File

@@ -0,0 +1,677 @@
/*
* MIPS emulation helpers for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include "exec.h"
#define MIPS_DEBUG_DISAS
/*****************************************************************************/
/* Exceptions processing helpers */
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
void do_raise_exception_err (uint32_t exception, int error_code)
{
#if 1
if (logfile && exception < 0x100)
fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
#endif
env->exception_index = exception;
env->error_code = error_code;
T0 = 0;
cpu_loop_exit();
}
void do_raise_exception (uint32_t exception)
{
do_raise_exception_err(exception, 0);
}
#define MEMSUFFIX _raw
#include "op_helper_mem.c"
#undef MEMSUFFIX
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "op_helper_mem.c"
#undef MEMSUFFIX
#define MEMSUFFIX _kernel
#include "op_helper_mem.c"
#undef MEMSUFFIX
#endif
/* 64 bits arithmetic for 32 bits hosts */
#if (HOST_LONG_BITS == 32)
static inline uint64_t get_HILO (void)
{
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
}
static inline void set_HILO (uint64_t HILO)
{
env->LO = HILO & 0xFFFFFFFF;
env->HI = HILO >> 32;
}
void do_mult (void)
{
set_HILO((int64_t)T0 * (int64_t)T1);
}
void do_multu (void)
{
set_HILO((uint64_t)T0 * (uint64_t)T1);
}
void do_madd (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() + tmp);
}
void do_maddu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() + tmp);
}
void do_msub (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() - tmp);
}
void do_msubu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() - tmp);
}
#endif
/* CP0 helpers */
void do_mfc0 (int reg, int sel)
{
const unsigned char *rn;
if (sel != 0 && reg != 16 && reg != 28) {
rn = "invalid";
goto print;
}
switch (reg) {
case 0:
T0 = env->CP0_index;
rn = "Index";
break;
case 1:
T0 = cpu_mips_get_random(env);
rn = "Random";
break;
case 2:
T0 = env->CP0_EntryLo0;
rn = "EntryLo0";
break;
case 3:
T0 = env->CP0_EntryLo1;
rn = "EntryLo1";
break;
case 4:
T0 = env->CP0_Context;
rn = "Context";
break;
case 5:
T0 = env->CP0_PageMask;
rn = "PageMask";
break;
case 6:
T0 = env->CP0_Wired;
rn = "Wired";
break;
case 8:
T0 = env->CP0_BadVAddr;
rn = "BadVaddr";
break;
case 9:
T0 = cpu_mips_get_count(env);
rn = "Count";
break;
case 10:
T0 = env->CP0_EntryHi;
rn = "EntryHi";
break;
case 11:
T0 = env->CP0_Compare;
rn = "Compare";
break;
case 12:
T0 = env->CP0_Status;
if (env->hflags & MIPS_HFLAG_UM)
T0 |= (1 << CP0St_UM);
if (env->hflags & MIPS_HFLAG_ERL)
T0 |= (1 << CP0St_ERL);
if (env->hflags & MIPS_HFLAG_EXL)
T0 |= (1 << CP0St_EXL);
rn = "Status";
break;
case 13:
T0 = env->CP0_Cause;
rn = "Cause";
break;
case 14:
T0 = env->CP0_EPC;
rn = "EPC";
break;
case 15:
T0 = env->CP0_PRid;
rn = "PRid";
break;
case 16:
switch (sel) {
case 0:
T0 = env->CP0_Config0;
rn = "Config";
break;
case 1:
T0 = env->CP0_Config1;
rn = "Config1";
break;
default:
rn = "Unknown config register";
break;
}
break;
case 17:
T0 = env->CP0_LLAddr >> 4;
rn = "LLAddr";
break;
case 18:
T0 = env->CP0_WatchLo;
rn = "WatchLo";
break;
case 19:
T0 = env->CP0_WatchHi;
rn = "WatchHi";
break;
case 23:
T0 = env->CP0_Debug;
if (env->hflags & MIPS_HFLAG_DM)
T0 |= 1 << CP0DB_DM;
rn = "Debug";
break;
case 24:
T0 = env->CP0_DEPC;
rn = "DEPC";
break;
case 28:
switch (sel) {
case 0:
T0 = env->CP0_TagLo;
rn = "TagLo";
break;
case 1:
T0 = env->CP0_DataLo;
rn = "DataLo";
break;
default:
rn = "unknown sel";
break;
}
break;
case 30:
T0 = env->CP0_ErrorEPC;
rn = "ErrorEPC";
break;
case 31:
T0 = env->CP0_DESAVE;
rn = "DESAVE";
break;
default:
rn = "unknown";
break;
}
print:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
env->PC, rn, T0, reg, sel);
}
#endif
return;
}
void do_mtc0 (int reg, int sel)
{
const unsigned char *rn;
uint32_t val, old, mask;
if (sel != 0 && reg != 16 && reg != 28) {
val = -1;
old = -1;
rn = "invalid";
goto print;
}
switch (reg) {
case 0:
val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
old = env->CP0_index;
env->CP0_index = val;
rn = "Index";
break;
case 2:
val = T0 & 0x03FFFFFFF;
old = env->CP0_EntryLo0;
env->CP0_EntryLo0 = val;
rn = "EntryLo0";
break;
case 3:
val = T0 & 0x03FFFFFFF;
old = env->CP0_EntryLo1;
env->CP0_EntryLo1 = val;
rn = "EntryLo1";
break;
case 4:
val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
old = env->CP0_Context;
env->CP0_Context = val;
rn = "Context";
break;
case 5:
val = T0 & 0x01FFE000;
old = env->CP0_PageMask;
env->CP0_PageMask = val;
rn = "PageMask";
break;
case 6:
val = T0 & 0x0000000F;
old = env->CP0_Wired;
env->CP0_Wired = val;
rn = "Wired";
break;
case 9:
val = T0;
old = cpu_mips_get_count(env);
cpu_mips_store_count(env, val);
rn = "Count";
break;
case 10:
val = T0 & 0xFFFFF0FF;
old = env->CP0_EntryHi;
env->CP0_EntryHi = val;
rn = "EntryHi";
break;
case 11:
val = T0;
old = env->CP0_Compare;
cpu_mips_store_compare(env, val);
rn = "Compare";
break;
case 12:
val = T0 & 0xFA78FF01;
if (T0 & (1 << CP0St_UM))
env->hflags |= MIPS_HFLAG_UM;
else
env->hflags &= ~MIPS_HFLAG_UM;
if (T0 & (1 << CP0St_ERL))
env->hflags |= MIPS_HFLAG_ERL;
else
env->hflags &= ~MIPS_HFLAG_ERL;
if (T0 & (1 << CP0St_EXL))
env->hflags |= MIPS_HFLAG_EXL;
else
env->hflags &= ~MIPS_HFLAG_EXL;
old = env->CP0_Status;
env->CP0_Status = val;
/* If we unmasked an asserted IRQ, raise it */
mask = 0x0000FF00;
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
old, val, env->CP0_Cause, old & mask, val & mask,
env->CP0_Cause & mask);
}
#if 1
if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM) &&
(env->CP0_Status & env->CP0_Cause & mask)) {
if (logfile)
fprintf(logfile, "Raise pending IRQs\n");
env->interrupt_request |= CPU_INTERRUPT_HARD;
do_raise_exception(EXCP_EXT_INTERRUPT);
} else if (!(val & 0x00000001) && (old & 0x00000001)) {
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
#endif
rn = "Status";
break;
case 13:
val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
old = env->CP0_Cause;
env->CP0_Cause = val;
#if 0
{
int i;
/* Check if we ever asserted a software IRQ */
for (i = 0; i < 2; i++) {
mask = 0x100 << i;
if ((val & mask) & !(old & mask))
mips_set_irq(i);
}
}
#endif
rn = "Cause";
break;
case 14:
val = T0;
old = env->CP0_EPC;
env->CP0_EPC = val;
rn = "EPC";
break;
case 16:
switch (sel) {
case 0:
#if defined(MIPS_USES_R4K_TLB)
val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
#else
val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
#endif
old = env->CP0_Config0;
env->CP0_Config0 = val;
rn = "Config0";
break;
default:
val = -1;
old = -1;
rn = "bad config selector";
break;
}
break;
case 18:
val = T0;
old = env->CP0_WatchLo;
env->CP0_WatchLo = val;
rn = "WatchLo";
break;
case 19:
val = T0 & 0x40FF0FF8;
old = env->CP0_WatchHi;
env->CP0_WatchHi = val;
rn = "WatchHi";
break;
case 23:
val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
if (T0 & (1 << CP0DB_DM))
env->hflags |= MIPS_HFLAG_DM;
else
env->hflags &= ~MIPS_HFLAG_DM;
old = env->CP0_Debug;
env->CP0_Debug = val;
rn = "Debug";
break;
case 24:
val = T0;
old = env->CP0_DEPC;
env->CP0_DEPC = val;
rn = "DEPC";
break;
case 28:
switch (sel) {
case 0:
val = T0 & 0xFFFFFCF6;
old = env->CP0_TagLo;
env->CP0_TagLo = val;
rn = "TagLo";
break;
default:
val = -1;
old = -1;
rn = "invalid sel";
break;
}
break;
case 30:
val = T0;
old = env->CP0_ErrorEPC;
env->CP0_ErrorEPC = val;
rn = "EPC";
break;
case 31:
val = T0;
old = env->CP0_DESAVE;
env->CP0_DESAVE = val;
rn = "DESAVE";
break;
default:
val = -1;
old = -1;
rn = "unknown";
break;
}
print:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
env->PC, rn, T0, val, reg, sel, old);
}
#endif
return;
}
/* TLB management */
#if defined(MIPS_USES_R4K_TLB)
static void invalidate_tb (int idx)
{
tlb_t *tlb;
target_ulong addr, end;
tlb = &env->tlb[idx];
if (tlb->V[0]) {
addr = tlb->PFN[0];
end = addr + (tlb->end - tlb->VPN);
tb_invalidate_page_range(addr, end);
}
if (tlb->V[1]) {
addr = tlb->PFN[1];
end = addr + (tlb->end - tlb->VPN);
tb_invalidate_page_range(addr, end);
}
}
static void fill_tb (int idx)
{
tlb_t *tlb;
int size;
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb[idx];
tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
tlb->ASID = env->CP0_EntryHi & 0x000000FF;
size = env->CP0_PageMask >> 13;
size = 4 * (size + 1);
tlb->end = tlb->VPN + (1 << (8 + size));
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
tlb->V[0] = env->CP0_EntryLo0 & 2;
tlb->D[0] = env->CP0_EntryLo0 & 4;
tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
tlb->V[1] = env->CP0_EntryLo1 & 2;
tlb->D[1] = env->CP0_EntryLo1 & 4;
tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}
void do_tlbwi (void)
{
/* Wildly undefined effects for CP0_index containing a too high value and
MIPS_TLB_NB not being a power of two. But so does real silicon. */
invalidate_tb(env->CP0_index & (MIPS_TLB_NB - 1));
fill_tb(env->CP0_index & (MIPS_TLB_NB - 1));
}
void do_tlbwr (void)
{
int r = cpu_mips_get_random(env);
invalidate_tb(r);
fill_tb(r);
}
void do_tlbp (void)
{
tlb_t *tlb;
target_ulong tag;
uint8_t ASID;
int i;
tag = (env->CP0_EntryHi & 0xFFFFE000);
ASID = env->CP0_EntryHi & 0x000000FF;
for (i = 0; i < MIPS_TLB_NB; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
/* TLB match */
env->CP0_index = i;
break;
}
}
if (i == MIPS_TLB_NB) {
env->CP0_index |= 0x80000000;
}
}
void do_tlbr (void)
{
tlb_t *tlb;
int size;
tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
env->CP0_EntryHi = tlb->VPN | tlb->ASID;
size = (tlb->end - tlb->VPN) >> 12;
env->CP0_PageMask = (size - 1) << 13;
env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
(tlb->PFN[0] >> 6);
env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
(tlb->PFN[1] >> 6);
}
#endif
void op_dump_ldst (const unsigned char *func)
{
if (loglevel)
fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
}
void dump_sc (void)
{
if (loglevel) {
fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
T1, T0, env->CP0_LLAddr);
}
}
void debug_eret (void)
{
if (loglevel) {
fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
}
}
void do_pmon (int function)
{
function /= 2;
switch (function) {
case 2: /* TODO: char inbyte(int waitflag); */
if (env->gpr[4] == 0)
env->gpr[2] = -1;
/* Fall through */
case 11: /* TODO: char inbyte (void); */
env->gpr[2] = -1;
break;
case 3:
case 12:
printf("%c", env->gpr[4] & 0xFF);
break;
case 17:
break;
case 158:
{
unsigned char *fmt = (void *)env->gpr[4];
printf("%s", fmt);
}
break;
}
}
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _mmu
#define GETPC() (__builtin_return_address(0))
#define SHIFT 0
#include "softmmu_template.h"
#define SHIFT 1
#include "softmmu_template.h"
#define SHIFT 2
#include "softmmu_template.h"
#define SHIFT 3
#include "softmmu_template.h"
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
{
TranslationBlock *tb;
CPUState *saved_env;
unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
env = cpu_single_env;
ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, NULL);
}
}
do_raise_exception_err(env->exception_index, env->error_code);
}
env = saved_env;
}
#endif

143
target-mips/op_helper_mem.c Normal file
View File

@@ -0,0 +1,143 @@
void glue(do_lwl, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav = T0;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
T0 = tmp;
break;
case 1:
T0 = (tmp << 8) | (T1 & 0x000000FF);
break;
case 2:
T0 = (tmp << 16) | (T1 & 0x0000FFFF);
break;
case 3:
T0 = (tmp << 24) | (T1 & 0x00FFFFFF);
break;
}
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, sav, tmp, T1, T0);
}
#endif
RETURN();
}
void glue(do_lwr, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav = T0;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
break;
case 1:
T0 = (tmp >> 16) | (T1 & 0xFFFF0000);
break;
case 2:
T0 = (tmp >> 8) | (T1 & 0xFF000000);
break;
case 3:
T0 = tmp;
break;
}
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, sav, tmp, T1, T0);
}
#endif
RETURN();
}
void glue(do_swl, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
#if defined (DEBUG_OP)
sav = tmp;
#endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
tmp = T1;
break;
case 1:
tmp = (tmp & 0xFF000000) | (T1 >> 8);
break;
case 2:
tmp = (tmp & 0xFFFF0000) | (T1 >> 16);
break;
case 3:
tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
break;
}
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
RETURN();
}
void glue(do_swr, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
#if defined (DEBUG_OP)
sav = tmp;
#endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
break;
case 1:
tmp = (tmp & 0x0000FFFF) | (T1 << 16);
break;
case 2:
tmp = (tmp & 0x000000FF) | (T1 << 8);
break;
case 3:
tmp = T1;
break;
}
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
RETURN();
}

113
target-mips/op_mem.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* MIPS emulation memory micro-operations for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Standard loads and stores */
void glue(op_lb, MEMSUFFIX) (void)
{
T0 = glue(ldsb, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_lbu, MEMSUFFIX) (void)
{
T0 = glue(ldub, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sb, MEMSUFFIX) (void)
{
glue(stb, MEMSUFFIX)(T0, T1);
RETURN();
}
void glue(op_lh, MEMSUFFIX) (void)
{
T0 = glue(ldsw, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_lhu, MEMSUFFIX) (void)
{
T0 = glue(lduw, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sh, MEMSUFFIX) (void)
{
glue(stw, MEMSUFFIX)(T0, T1);
RETURN();
}
void glue(op_lw, MEMSUFFIX) (void)
{
T0 = glue(ldl, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sw, MEMSUFFIX) (void)
{
glue(stl, MEMSUFFIX)(T0, T1);
RETURN();
}
/* "half" load and stores */
void glue(op_lwl, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX));
RETURN();
}
void glue(op_lwr, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX));
RETURN();
}
void glue(op_swl, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_swl, MEMSUFFIX));
RETURN();
}
void glue(op_swr, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_swr, MEMSUFFIX));
RETURN();
}
void glue(op_ll, MEMSUFFIX) (void)
{
T1 = T0;
T0 = glue(ldl, MEMSUFFIX)(T0);
env->CP0_LLAddr = T1;
RETURN();
}
void glue(op_sc, MEMSUFFIX) (void)
{
CALL_FROM_TB0(dump_sc);
if (T0 == env->CP0_LLAddr) {
glue(stl, MEMSUFFIX)(T0, T1);
T0 = 1;
} else {
T0 = 0;
}
RETURN();
}

65
target-mips/op_template.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* MIPS emulation micro-operations templates for reg load & store for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if defined(REG)
void glue(op_load_gpr_T0_gpr, REG) (void)
{
T0 = env->gpr[REG];
RETURN();
}
void glue(op_store_T0_gpr_gpr, REG) (void)
{
env->gpr[REG] = T0;
RETURN();
}
void glue(op_load_gpr_T1_gpr, REG) (void)
{
T1 = env->gpr[REG];
RETURN();
}
void glue(op_store_T1_gpr_gpr, REG) (void)
{
env->gpr[REG] = T1;
RETURN();
}
void glue(op_load_gpr_T2_gpr, REG) (void)
{
T2 = env->gpr[REG];
RETURN();
}
#endif
#if defined (TN)
void glue(op_set_, TN) (void)
{
TN = PARAM1;
RETURN();
}
void glue (op_reset_, TN) (void)
{
TN = 0;
RETURN();
}
#endif

1688
target-mips/translate.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* PPC emulation definitions for qemu.
* PowerPC emulation definitions for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,8 +20,12 @@
#if !defined (__PPC_H__)
#define __PPC_H__
#include "config.h"
#include "dyngen-exec.h"
#define TARGET_LONG_BITS 32
register struct CPUPPCState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
@@ -119,15 +123,6 @@ static inline uint32_t rotl (uint32_t i, int n)
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
void do_load_cr (void);
void do_store_cr (uint32_t mask);
void do_load_xer (void);
void do_store_xer (void);
void do_load_msr (void);
void do_store_msr (void);
void do_load_fpscr (void);
void do_store_fpscr (uint32_t mask);
void do_sraw(void);
void do_fctiw (void);
@@ -143,20 +138,9 @@ void do_fcmpo (void);
void do_check_reservation (void);
void do_icbi (void);
void do_store_sr (uint32_t srnum);
void do_store_ibat (int ul, int nr);
void do_store_dbat (int ul, int nr);
void do_tlbia (void);
void do_tlbie (void);
void dump_state (void);
void dump_rfi (void);
void dump_store_sr (int srnum);
void dump_store_ibat (int ul, int nr);
void dump_store_dbat (int ul, int nr);
void dump_store_tb (int ul);
void dump_update_tb(uint32_t param);
static inline void env_to_regs(void)
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* PPC emulation micro-operations for qemu.
* PowerPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -130,7 +130,7 @@
#define REG 31
#include "op_template.h"
/* PPC state maintenance operations */
/* PowerPC state maintenance operations */
/* set_Rc0 */
PPC_OP(set_Rc0)
{
@@ -204,16 +204,6 @@ PPC_OP(update_nip)
env->nip = PARAM(1);
}
PPC_OP(debug)
{
env->nip = PARAM(1);
#if defined (DEBUG_OP)
dump_state();
#endif
do_raise_exception(EXCP_DEBUG);
RETURN();
}
/* Segment registers load and store with immediate index */
PPC_OP(load_srin)
{
@@ -223,7 +213,7 @@ PPC_OP(load_srin)
PPC_OP(store_srin)
{
do_store_sr(T1 >> 28);
do_store_sr(env, ((uint32_t)T1 >> 28), T0);
RETURN();
}
@@ -235,7 +225,7 @@ PPC_OP(load_sdr1)
PPC_OP(store_sdr1)
{
regs->sdr1 = T0;
do_store_sdr1(env, T0);
RETURN();
}
@@ -247,13 +237,13 @@ PPC_OP(exit_tb)
/* Load/store special registers */
PPC_OP(load_cr)
{
do_load_cr();
T0 = do_load_cr(env);
RETURN();
}
PPC_OP(store_cr)
{
do_store_cr(PARAM(1));
do_store_cr(env, T0, PARAM(1));
RETURN();
}
@@ -279,25 +269,25 @@ PPC_OP(load_xer_bc)
PPC_OP(load_xer)
{
do_load_xer();
T0 = do_load_xer(env);
RETURN();
}
PPC_OP(store_xer)
{
do_store_xer();
do_store_xer(env, T0);
RETURN();
}
PPC_OP(load_msr)
{
do_load_msr();
T0 = do_load_msr(env);
RETURN();
}
PPC_OP(store_msr)
{
do_store_msr();
do_store_msr(env, T0);
RETURN();
}
@@ -378,9 +368,20 @@ PPC_OP(load_ibat)
T0 = regs->IBAT[PARAM(1)][PARAM(2)];
}
PPC_OP(store_ibat)
void op_store_ibatu (void)
{
do_store_ibat(PARAM(1), PARAM(2));
do_store_ibatu(env, PARAM1, T0);
RETURN();
}
void op_store_ibatl (void)
{
#if 1
env->IBAT[1][PARAM1] = T0;
#else
do_store_ibatl(env, PARAM1, T0);
#endif
RETURN();
}
PPC_OP(load_dbat)
@@ -388,21 +389,32 @@ PPC_OP(load_dbat)
T0 = regs->DBAT[PARAM(1)][PARAM(2)];
}
PPC_OP(store_dbat)
void op_store_dbatu (void)
{
do_store_dbat(PARAM(1), PARAM(2));
do_store_dbatu(env, PARAM1, T0);
RETURN();
}
void op_store_dbatl (void)
{
#if 1
env->DBAT[1][PARAM1] = T0;
#else
do_store_dbatl(env, PARAM1, T0);
#endif
RETURN();
}
/* FPSCR */
PPC_OP(load_fpscr)
{
do_load_fpscr();
FT0 = do_load_fpscr(env);
RETURN();
}
PPC_OP(store_fpscr)
{
do_store_fpscr(PARAM(1));
do_store_fpscr(env, FT0, PARAM1);
RETURN();
}
@@ -446,7 +458,7 @@ PPC_OP(b)
PPC_OP(b_T1)
{
regs->nip = T1;
regs->nip = T1 & ~3;
}
PPC_OP(btest)
@@ -536,16 +548,10 @@ PPC_OP(add)
RETURN();
}
PPC_OP(addo)
void do_addo (void);
void op_addo (void)
{
T2 = T0;
T0 += T1;
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
do_addo();
RETURN();
}
@@ -562,53 +568,24 @@ PPC_OP(addc)
RETURN();
}
PPC_OP(addco)
void do_addco (void);
void op_addco (void)
{
T2 = T0;
T0 += T1;
if (T0 < T2) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
do_addco();
RETURN();
}
/* add extended */
/* candidate for helper (too long) */
PPC_OP(adde)
void do_adde (void);
void op_adde (void)
{
T2 = T0;
T0 += T1 + xer_ca;
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
do_adde();
}
void do_addeo (void);
PPC_OP(addeo)
{
T2 = T0;
T0 += T1 + xer_ca;
if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
do_addeo();
RETURN();
}
@@ -642,18 +619,10 @@ PPC_OP(addme)
RETURN();
}
PPC_OP(addmeo)
void do_addmeo (void);
void op_addmeo (void)
{
T1 = T0;
T0 += xer_ca + (-1);
if (T1 & (T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T1 != 0)
xer_ca = 1;
do_addmeo();
RETURN();
}
@@ -670,26 +639,14 @@ PPC_OP(addze)
RETURN();
}
PPC_OP(addzeo)
void do_addzeo (void);
void op_addzeo (void)
{
T1 = T0;
T0 += xer_ca;
if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T0 < T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
do_addzeo();
RETURN();
}
/* divide word */
/* candidate for helper (too long) */
PPC_OP(divw)
{
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
@@ -700,16 +657,10 @@ PPC_OP(divw)
RETURN();
}
PPC_OP(divwo)
void do_divwo (void);
void op_divwo (void)
{
if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
xer_so = 1;
xer_ov = 1;
T0 = (-1) * (T0 >> 31);
} else {
xer_ov = 0;
T0 = (Ts0 / Ts1);
}
do_divwo();
RETURN();
}
@@ -724,16 +675,10 @@ PPC_OP(divwu)
RETURN();
}
PPC_OP(divwuo)
void do_divwuo (void);
void op_divwuo (void)
{
if (T1 == 0) {
xer_so = 1;
xer_ov = 1;
T0 = 0;
} else {
xer_ov = 0;
T0 /= T1;
}
do_divwuo();
RETURN();
}
@@ -765,17 +710,10 @@ PPC_OP(mullw)
RETURN();
}
PPC_OP(mullwo)
void do_mullwo (void);
void op_mullwo (void)
{
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
if ((int32_t)res != res) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
}
T0 = (int32_t)res;
do_mullwo();
RETURN();
}
@@ -788,15 +726,10 @@ PPC_OP(neg)
RETURN();
}
PPC_OP(nego)
void do_nego (void);
void op_nego (void)
{
if (T0 == 0x80000000) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
T0 = -Ts0;
}
do_nego();
RETURN();
}
@@ -807,16 +740,10 @@ PPC_OP(subf)
RETURN();
}
PPC_OP(subfo)
void do_subfo (void);
void op_subfo (void)
{
T2 = T0;
T0 = T1 - T0;
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
do_subfo();
RETURN();
}
@@ -832,52 +759,25 @@ PPC_OP(subfc)
RETURN();
}
PPC_OP(subfco)
void do_subfco (void);
void op_subfco (void)
{
T2 = T0;
T0 = T1 - T0;
if (T0 <= T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
do_subfco();
RETURN();
}
/* substract from extended */
/* candidate for helper (too long) */
PPC_OP(subfe)
void do_subfe (void);
void op_subfe (void)
{
T0 = T1 + ~T0 + xer_ca;
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
do_subfe();
RETURN();
}
void do_subfeo (void);
PPC_OP(subfeo)
{
T2 = T0;
T0 = T1 + ~T0 + xer_ca;
if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
xer_ca = 1;
} else {
xer_ca = 0;
}
do_subfeo();
RETURN();
}
@@ -903,18 +803,10 @@ PPC_OP(subfme)
RETURN();
}
PPC_OP(subfmeo)
void do_subfmeo (void);
void op_subfmeo (void)
{
T1 = T0;
T0 = ~T0 + xer_ca - 1;
if (~T1 & (~T1 ^ T0) & (1 << 31)) {
xer_so = 1;
xer_ov = 1;
} else {
xer_ov = 0;
}
if (T1 != -1)
xer_ca = 1;
do_subfmeo();
RETURN();
}
@@ -931,21 +823,10 @@ PPC_OP(subfze)
RETURN();
}
PPC_OP(subfzeo)
void do_subfzeo (void);
void op_subfzeo (void)
{
T1 = T0;
T0 = ~T0 + xer_ca;
if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
xer_ov = 1;
xer_so = 1;
} else {
xer_ov = 0;
}
if (T0 < ~T1) {
xer_ca = 1;
} else {
xer_ca = 0;
}
do_subfzeo();
RETURN();
}
@@ -1162,7 +1043,7 @@ PPC_OP(slw)
}
/* shift right algebraic word */
PPC_OP(sraw)
void op_sraw (void)
{
do_sraw();
RETURN();
@@ -1215,10 +1096,9 @@ PPC_OP(fmul)
}
/* fdiv - fdiv. */
void do_fdiv (void);
PPC_OP(fdiv)
{
do_fdiv();
FT0 = float64_div(FT0, FT1, &env->fp_status);
RETURN();
}
@@ -1319,25 +1199,24 @@ PPC_OP(fcmpo)
/*** Floating-point move ***/
/* fabs */
void do_fabs (void);
PPC_OP(fabs)
{
do_fabs();
FT0 = float64_abs(FT0);
RETURN();
}
/* fnabs */
void do_fnabs (void);
PPC_OP(fnabs)
{
do_fnabs();
FT0 = float64_abs(FT0);
FT0 = float64_chs(FT0);
RETURN();
}
/* fneg */
PPC_OP(fneg)
{
FT0 = -FT0;
FT0 = float64_chs(FT0);
RETURN();
}
@@ -1355,48 +1234,30 @@ PPC_OP(fneg)
/* Special op to check and maybe clear reservation */
PPC_OP(check_reservation)
{
do_check_reservation();
if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
env->reserve = -1;
RETURN();
}
/* Return from interrupt */
PPC_OP(rfi)
void do_rfi (void);
void op_rfi (void)
{
regs->nip = regs->spr[SRR0] & ~0x00000003;
#if 1 // TRY
T0 = regs->spr[SRR1] & ~0xFFF00000;
#else
T0 = regs->spr[SRR1] & ~0xFFFF0000;
#endif
do_store_msr();
#if defined (DEBUG_OP)
dump_rfi();
#endif
// do_tlbia();
do_raise_exception(EXCP_RFI);
do_rfi();
RETURN();
}
/* Trap word */
PPC_OP(tw)
void do_tw (uint32_t cmp, int flags);
void op_tw (void)
{
if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) ||
(Ts0 > Ts1 && (PARAM(1) & 0x08)) ||
(Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
(T0 < T1 && (PARAM(1) & 0x02)) ||
(T0 > T1 && (PARAM(1) & 0x01)))
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
do_tw(T1, PARAM(1));
RETURN();
}
PPC_OP(twi)
void op_twi (void)
{
if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) ||
(Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) ||
(Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
(T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
(T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
do_tw(PARAM(1), PARAM(2));
RETURN();
}
@@ -1420,3 +1281,9 @@ PPC_OP(tlbie)
do_tlbie();
RETURN();
}
void op_store_pir (void)
{
env->spr[SPR_PIR] = T0 & 0x0000000FUL;
RETURN();
}

View File

@@ -1,7 +1,7 @@
/*
* PPC emulation helpers for qemu.
* PowerPC emulation helpers for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,14 @@
#include "op_helper_mem.h"
#endif
//#define DEBUG_OP
//#define DEBUG_EXCEPTIONS
//#define FLUSH_ALL_TLBS
#define Ts0 (long)((target_long)T0)
#define Ts1 (long)((target_long)T1)
#define Ts2 (long)((target_long)T2)
/*****************************************************************************/
/* Exceptions processing helpers */
void cpu_loop_exit(void)
@@ -42,12 +50,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
printf("Raise exception %3x code : %d\n", exception, error_code);
#endif
switch (exception) {
case EXCP_EXTERNAL:
case EXCP_DECR:
printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n");
if (msr_ee == 0)
return;
break;
case EXCP_PROGRAM:
if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
return;
@@ -66,90 +68,229 @@ void do_raise_exception (uint32_t exception)
}
/*****************************************************************************/
/* Helpers for "fat" micro operations */
/* Special registers load and store */
void do_load_cr (void)
/* Fixed point operations helpers */
void do_addo (void)
{
T0 = (env->crf[0] << 28) |
(env->crf[1] << 24) |
(env->crf[2] << 20) |
(env->crf[3] << 16) |
(env->crf[4] << 12) |
(env->crf[5] << 8) |
(env->crf[6] << 4) |
(env->crf[7] << 0);
}
void do_store_cr (uint32_t mask)
{
int i, sh;
for (i = 0, sh = 7; i < 8; i++, sh --) {
if (mask & (1 << sh))
env->crf[i] = (T0 >> (sh * 4)) & 0xF;
T2 = T0;
T0 += T1;
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
}
void do_load_xer (void)
void do_addco (void)
{
T0 = (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
(xer_bc << XER_BC);
}
void do_store_xer (void)
{
xer_so = (T0 >> XER_SO) & 0x01;
xer_ov = (T0 >> XER_OV) & 0x01;
xer_ca = (T0 >> XER_CA) & 0x01;
xer_bc = (T0 >> XER_BC) & 0x1f;
}
void do_load_msr (void)
{
T0 = (msr_pow << MSR_POW) |
(msr_ile << MSR_ILE) |
(msr_ee << MSR_EE) |
(msr_pr << MSR_PR) |
(msr_fp << MSR_FP) |
(msr_me << MSR_ME) |
(msr_fe0 << MSR_FE0) |
(msr_se << MSR_SE) |
(msr_be << MSR_BE) |
(msr_fe1 << MSR_FE1) |
(msr_ip << MSR_IP) |
(msr_ir << MSR_IR) |
(msr_dr << MSR_DR) |
(msr_ri << MSR_RI) |
(msr_le << MSR_LE);
}
void do_store_msr (void)
{
#if 1 // TRY
if (((T0 >> MSR_IR) & 0x01) != msr_ir ||
((T0 >> MSR_DR) & 0x01) != msr_dr ||
((T0 >> MSR_PR) & 0x01) != msr_pr)
{
do_tlbia();
T2 = T0;
T0 += T1;
if (likely(T0 >= T2)) {
xer_ca = 0;
} else {
xer_ca = 1;
}
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
}
void do_adde (void)
{
T2 = T0;
T0 += T1 + xer_ca;
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
void do_addeo (void)
{
T2 = T0;
T0 += T1 + xer_ca;
if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
}
void do_addmeo (void)
{
T1 = T0;
T0 += xer_ca + (-1);
if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
if (likely(T1 != 0))
xer_ca = 1;
}
void do_addzeo (void)
{
T1 = T0;
T0 += xer_ca;
if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
if (likely(T0 >= T1)) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
void do_divwo (void)
{
if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
xer_ov = 0;
T0 = (Ts0 / Ts1);
} else {
xer_so = 1;
xer_ov = 1;
T0 = (-1) * ((uint32_t)T0 >> 31);
}
}
void do_divwuo (void)
{
if (likely((uint32_t)T1 != 0)) {
xer_ov = 0;
T0 = (uint32_t)T0 / (uint32_t)T1;
} else {
xer_so = 1;
xer_ov = 1;
T0 = 0;
}
}
void do_mullwo (void)
{
int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
if (likely((int32_t)res == res)) {
xer_ov = 0;
} else {
xer_ov = 1;
xer_so = 1;
}
T0 = (int32_t)res;
}
void do_nego (void)
{
if (likely(T0 != INT32_MIN)) {
xer_ov = 0;
T0 = -Ts0;
} else {
xer_ov = 1;
xer_so = 1;
}
}
void do_subfo (void)
{
T2 = T0;
T0 = T1 - T0;
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
RETURN();
}
void do_subfco (void)
{
T2 = T0;
T0 = T1 - T0;
if (likely(T0 > T1)) {
xer_ca = 0;
} else {
xer_ca = 1;
}
if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
}
void do_subfe (void)
{
T0 = T1 + ~T0 + xer_ca;
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
void do_subfeo (void)
{
T2 = T0;
T0 = T1 + ~T0 + xer_ca;
if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
void do_subfmeo (void)
{
T1 = T0;
T0 = ~T0 + xer_ca - 1;
if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
if (likely(T1 != -1))
xer_ca = 1;
}
void do_subfzeo (void)
{
T1 = T0;
T0 = ~T0 + xer_ca;
if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
xer_ov = 0;
} else {
xer_ov = 1;
xer_so = 1;
}
if (likely(T0 >= ~T1)) {
xer_ca = 0;
} else {
xer_ca = 1;
}
#endif
msr_pow = (T0 >> MSR_POW) & 0x03;
msr_ile = (T0 >> MSR_ILE) & 0x01;
msr_ee = (T0 >> MSR_EE) & 0x01;
msr_pr = (T0 >> MSR_PR) & 0x01;
msr_fp = (T0 >> MSR_FP) & 0x01;
msr_me = (T0 >> MSR_ME) & 0x01;
msr_fe0 = (T0 >> MSR_FE0) & 0x01;
msr_se = (T0 >> MSR_SE) & 0x01;
msr_be = (T0 >> MSR_BE) & 0x01;
msr_fe1 = (T0 >> MSR_FE1) & 0x01;
msr_ip = (T0 >> MSR_IP) & 0x01;
msr_ir = (T0 >> MSR_IR) & 0x01;
msr_dr = (T0 >> MSR_DR) & 0x01;
msr_ri = (T0 >> MSR_RI) & 0x01;
msr_le = (T0 >> MSR_LE) & 0x01;
}
/* shift right arithmetic helper */
@@ -157,95 +298,31 @@ void do_sraw (void)
{
int32_t ret;
if (likely(!(T1 & 0x20UL))) {
if (likely(T1 != 0)) {
ret = (int32_t)T0 >> (T1 & 0x1fUL);
if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
xer_ca = 0;
if (T1 & 0x20) {
ret = (-1) * (T0 >> 31);
if (ret < 0 && (T0 & ~0x80000000) != 0)
} else {
xer_ca = 1;
#if 1 // TRY
} else if (T1 == 0) {
}
} else {
ret = T0;
#endif
xer_ca = 0;
}
} else {
ret = (-1) * ((uint32_t)T0 >> 31);
if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
xer_ca = 0;
} else {
ret = (int32_t)T0 >> (T1 & 0x1f);
if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0)
xer_ca = 1;
}
}
T0 = ret;
}
/*****************************************************************************/
/* Floating point operations helpers */
void do_load_fpscr (void)
{
/* The 32 MSB of the target fpr are undefined.
* They'll be zero...
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i;
#ifdef WORDS_BIGENDIAN
#define WORD0 0
#define WORD1 1
#else
#define WORD0 1
#define WORD1 0
#endif
u.s.u[WORD0] = 0;
u.s.u[WORD1] = 0;
for (i = 0; i < 8; i++)
u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
FT0 = u.d;
}
void do_store_fpscr (uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
*/
union {
double d;
struct {
uint32_t u[2];
} s;
} u;
int i, rnd_type;
u.d = FT0;
if (mask & 0x80)
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
for (i = 1; i < 7; i++) {
if (mask & (1 << (7 - i)))
env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
}
/* TODO: update FEX & VX */
/* Set rounding mode */
switch (env->fpscr[0] & 0x3) {
case 0:
/* Best approximation (round to nearest) */
rnd_type = float_round_nearest_even;
break;
case 1:
/* Smaller magnitude (round toward zero) */
rnd_type = float_round_to_zero;
break;
case 2:
/* Round toward +infinite */
rnd_type = float_round_up;
break;
default:
case 3:
/* Round toward -infinite */
rnd_type = float_round_down;
break;
}
set_float_rounding_mode(rnd_type, &env->fp_status);
}
void do_fctiw (void)
{
union {
@@ -254,7 +331,7 @@ void do_fctiw (void)
} p;
/* XXX: higher bits are not supposed to be significant.
* to make tests easier, return the same as a real PPC 750 (aka G3)
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
p.i = float64_to_int32(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
@@ -269,7 +346,7 @@ void do_fctiwz (void)
} p;
/* XXX: higher bits are not supposed to be significant.
* to make tests easier, return the same as a real PPC 750 (aka G3)
* to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
@@ -278,29 +355,23 @@ void do_fctiwz (void)
void do_fnmadd (void)
{
FT0 = (FT0 * FT1) + FT2;
if (!isnan(FT0))
FT0 = -FT0;
FT0 = float64_mul(FT0, FT1, &env->fp_status);
FT0 = float64_add(FT0, FT2, &env->fp_status);
if (likely(!isnan(FT0)))
FT0 = float64_chs(FT0);
}
void do_fnmsub (void)
{
FT0 = (FT0 * FT1) - FT2;
if (!isnan(FT0))
FT0 = -FT0;
}
void do_fdiv (void)
{
if (FT0 == -0.0 && FT1 == -0.0)
FT0 = 0.0 / 0.0;
else
FT0 /= FT1;
FT0 = float64_mul(FT0, FT1, &env->fp_status);
FT0 = float64_sub(FT0, FT2, &env->fp_status);
if (likely(!isnan(FT0)))
FT0 = float64_chs(FT0);
}
void do_fsqrt (void)
{
FT0 = sqrt(FT0);
FT0 = float64_sqrt(FT0, &env->fp_status);
}
void do_fres (void)
@@ -310,7 +381,7 @@ void do_fres (void)
uint64_t i;
} p;
if (isnormal(FT0)) {
if (likely(isnormal(FT0))) {
FT0 = (float)(1.0 / FT0);
} else {
p.d = FT0;
@@ -336,8 +407,9 @@ void do_frsqrte (void)
uint64_t i;
} p;
if (isnormal(FT0) && FT0 > 0.0) {
FT0 = (float)(1.0 / sqrt(FT0));
if (likely(isnormal(FT0) && FT0 > 0.0)) {
FT0 = float64_sqrt(FT0, &env->fp_status);
FT0 = float32_div(1.0, FT0, &env->fp_status);
} else {
p.d = FT0;
if (p.i == 0x8000000000000000ULL) {
@@ -366,16 +438,18 @@ void do_fsel (void)
void do_fcmpu (void)
{
if (isnan(FT0) || isnan(FT1)) {
T0 = 0x01;
if (likely(!isnan(FT0) && !isnan(FT1))) {
if (float64_lt(FT0, FT1, &env->fp_status)) {
T0 = 0x08UL;
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
T0 = 0x04UL;
} else {
T0 = 0x02UL;
}
} else {
T0 = 0x01UL;
env->fpscr[4] |= 0x1;
env->fpscr[6] |= 0x1;
} else if (FT0 < FT1) {
T0 = 0x08;
} else if (FT0 > FT1) {
T0 = 0x04;
} else {
T0 = 0x02;
}
env->fpscr[3] = T0;
}
@@ -383,8 +457,16 @@ void do_fcmpu (void)
void do_fcmpo (void)
{
env->fpscr[4] &= ~0x1;
if (isnan(FT0) || isnan(FT1)) {
T0 = 0x01;
if (likely(!isnan(FT0) && !isnan(FT1))) {
if (float64_lt(FT0, FT1, &env->fp_status)) {
T0 = 0x08UL;
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
T0 = 0x04UL;
} else {
T0 = 0x02UL;
}
} else {
T0 = 0x01UL;
env->fpscr[4] |= 0x1;
/* I don't know how to test "quiet" nan... */
if (0 /* || ! quiet_nan(...) */) {
@@ -394,56 +476,51 @@ void do_fcmpo (void)
} else {
env->fpscr[4] |= 0x8;
}
} else if (FT0 < FT1) {
T0 = 0x08;
} else if (FT0 > FT1) {
T0 = 0x04;
} else {
T0 = 0x02;
}
env->fpscr[3] = T0;
}
void do_fabs (void)
void do_rfi (void)
{
union {
double d;
uint64_t i;
} p;
p.d = FT0;
p.i &= ~0x8000000000000000ULL;
FT0 = p.d;
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
do_store_msr(env, T0);
#if defined (DEBUG_OP)
dump_rfi();
#endif
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
void do_fnabs (void)
void do_tw (uint32_t cmp, int flags)
{
union {
double d;
uint64_t i;
} p;
p.d = FT0;
p.i |= 0x8000000000000000ULL;
FT0 = p.d;
if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
(Ts0 > (int32_t)cmp && (flags & 0x08)) ||
(Ts0 == (int32_t)cmp && (flags & 0x04)) ||
(T0 < cmp && (flags & 0x02)) ||
(T0 > cmp && (flags & 0x01)))))
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
}
/* Instruction cache invalidation helper */
#define ICACHE_LINE_SIZE 32
void do_check_reservation (void)
{
if ((env->reserve & ~0x03) == T0)
env->reserve = -1;
}
void do_icbi (void)
{
/* Invalidate one cache line */
uint32_t tmp;
/* Invalidate one cache line :
* PowerPC specification says this is to be treated like a load
* (not a fetch) by the MMU. To be sure it will be so,
* do the load "by hand".
*/
#if defined(TARGET_PPC64)
if (!msr_sf)
T0 &= 0xFFFFFFFFULL;
#endif
tmp = ldl_kernel(T0);
T0 &= ~(ICACHE_LINE_SIZE - 1);
tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
}
/*****************************************************************************/
/* MMU related helpers */
/* TLB invalidation helpers */
void do_tlbia (void)
{
@@ -452,119 +529,62 @@ void do_tlbia (void)
void do_tlbie (void)
{
#if !defined(FLUSH_ALL_TLBS)
tlb_flush_page(env, T0);
}
void do_store_sr (uint32_t srnum)
{
#if defined (DEBUG_OP)
dump_store_sr(srnum);
#endif
#if 0 // TRY
{
uint32_t base, page;
base = srnum << 28;
for (page = base; page != base + 0x100000000; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
do_tlbia();
#endif
env->sr[srnum] = T0;
}
/* For BATs, we may not invalidate any TLBs if the change is only on
* protection bits for user mode.
*/
void do_store_ibat (int ul, int nr)
{
#if defined (DEBUG_OP)
dump_store_ibat(ul, nr);
#endif
#if 0 // TRY
{
uint32_t base, length, page;
base = env->IBAT[0][nr];
length = (((base >> 2) & 0x000007FF) + 1) << 17;
base &= 0xFFFC0000;
for (page = base; page != base + length; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
#endif
env->IBAT[ul][nr] = T0;
}
void do_store_dbat (int ul, int nr)
{
#if defined (DEBUG_OP)
dump_store_dbat(ul, nr);
#endif
#if 0 // TRY
{
uint32_t base, length, page;
base = env->DBAT[0][nr];
length = (((base >> 2) & 0x000007FF) + 1) << 17;
base &= 0xFFFC0000;
for (page = base; page != base + length; page += 0x1000)
tlb_flush_page(env, page);
}
#else
tlb_flush(env, 1);
#endif
env->DBAT[ul][nr] = T0;
}
/*****************************************************************************/
/* Special helpers for debug */
void dump_state (void)
{
// cpu_dump_state(env, stdout, fprintf, 0);
}
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)
void dump_rfi (void)
{
#if 0
printf("Return from interrupt => 0x%08x\n", env->nip);
// cpu_dump_state(env, stdout, fprintf, 0);
#endif
}
#define MMUSUFFIX _mmu
#define GETPC() (__builtin_return_address(0))
void dump_store_sr (int srnum)
{
#if 0
printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0);
#endif
}
#define SHIFT 0
#include "softmmu_template.h"
static void _dump_store_bat (char ID, int ul, int nr)
{
printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n",
ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip);
}
#define SHIFT 1
#include "softmmu_template.h"
void dump_store_ibat (int ul, int nr)
{
_dump_store_bat('I', ul, nr);
}
#define SHIFT 2
#include "softmmu_template.h"
void dump_store_dbat (int ul, int nr)
{
_dump_store_bat('D', ul, nr);
}
#define SHIFT 3
#include "softmmu_template.h"
void dump_store_tb (int ul)
/* try to fill the TLB and return an exception if error. If retaddr is
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
{
printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0);
}
TranslationBlock *tb;
CPUState *saved_env;
target_phys_addr_t pc;
int ret;
void dump_update_tb(uint32_t param)
{
#if 0
printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0);
#endif
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
env = cpu_single_env;
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
if (!likely(ret == 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
pc = (target_phys_addr_t)retaddr;
tb = tb_find_pc(pc);
if (likely(tb)) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, NULL);
}
}
do_raise_exception_err(env->exception_index, env->error_code);
}
env = saved_env;
}
#endif /* !CONFIG_USER_ONLY */

View File

@@ -3,10 +3,12 @@ void glue(do_lsw, MEMSUFFIX) (int dst)
uint32_t tmp;
int sh;
#if 0
if (loglevel > 0) {
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
__func__, T0, T1, dst);
}
#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
if (dst == 32)
@@ -25,10 +27,12 @@ void glue(do_stsw, MEMSUFFIX) (int src)
{
int sh;
#if 0
if (loglevel > 0) {
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
__func__, T0, T1, src);
}
#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
glue(stl, MEMSUFFIX)(T0, ugpr(src++));
if (src == 32)
@@ -45,10 +49,12 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
uint32_t tmp;
int sh;
#if 0
if (loglevel > 0) {
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
__func__, T0, T1, dst);
}
#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
tmp = glue(ldl, MEMSUFFIX)(T0);
ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
@@ -70,10 +76,12 @@ void glue(do_stsw_le, MEMSUFFIX) (int src)
uint32_t tmp;
int sh;
#if 0
if (loglevel > 0) {
fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
__func__, T0, T1, src);
}
#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
tmp = ((ugpr(src++) & 0xFF000000) >> 24);
tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);

View File

@@ -1,7 +1,7 @@
/*
* PPC emulation micro-operations for qemu.
* PowerPC emulation micro-operations for qemu.
*
* Copyright (c) 2003 Jocelyn Mayer
* Copyright (c) 2003-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -175,7 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void)
void OPPROTO glue(op_store_sr, REG)(void)
{
do_store_sr(REG);
do_store_sr(env, REG, T0);
RETURN();
}
#endif

File diff suppressed because it is too large Load Diff

2069
target-ppc/translate_init.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,12 +6,13 @@
#if !defined(TARGET_SPARC64)
#define TARGET_LONG_BITS 32
#define TARGET_FPREGS 32
#define TARGET_FPREG_T float
#define TARGET_PAGE_BITS 12 /* 4k */
#else
#define TARGET_LONG_BITS 64
#define TARGET_FPREGS 64
#define TARGET_FPREG_T double
#define TARGET_PAGE_BITS 12 /* XXX */
#endif
#define TARGET_FPREG_T float
#include "cpu-defs.h"
@@ -22,6 +23,7 @@
/*#define EXCP_INTERRUPT 0x100*/
/* trap definitions */
#ifndef TARGET_SPARC64
#define TT_TFAULT 0x01
#define TT_ILL_INSN 0x02
#define TT_PRIV_INSN 0x03
@@ -33,6 +35,25 @@
#define TT_EXTINT 0x10
#define TT_DIV_ZERO 0x2a
#define TT_TRAP 0x80
#else
#define TT_TFAULT 0x08
#define TT_TMISS 0x09
#define TT_ILL_INSN 0x10
#define TT_PRIV_INSN 0x11
#define TT_NFPU_INSN 0x20
#define TT_FP_EXCP 0x21
#define TT_CLRWIN 0x24
#define TT_DIV_ZERO 0x28
#define TT_DFAULT 0x30
#define TT_DMISS 0x31
#define TT_DPROT 0x32
#define TT_PRIV_ACT 0x37
#define TT_EXTINT 0x40
#define TT_SPILL 0x80
#define TT_FILL 0xc0
#define TT_WOTHER 0x10
#define TT_TRAP 0x100
#endif
#define PSR_NEG (1<<23)
#define PSR_ZERO (1<<22)
@@ -49,6 +70,17 @@
/* Trap base register */
#define TBR_BASE_MASK 0xfffff000
#if defined(TARGET_SPARC64)
#define PS_IG (1<<11)
#define PS_MG (1<<10)
#define PS_RED (1<<5)
#define PS_PEF (1<<4)
#define PS_AM (1<<3)
#define PS_PRIV (1<<2)
#define PS_IE (1<<1)
#define PS_AG (1<<0)
#endif
/* Fcc */
#define FSR_RD1 (1<<31)
#define FSR_RD0 (1<<30)
@@ -119,15 +151,15 @@ typedef struct CPUSPARCState {
target_ulong npc; /* next program counter */
target_ulong y; /* multiply/divide register */
uint32_t psr; /* processor state register */
uint32_t fsr; /* FPU state register */
target_ulong fsr; /* FPU state register */
uint32_t cwp; /* index of current register window (extracted
from PSR) */
uint32_t wim; /* window invalid mask */
uint32_t tbr; /* trap base register */
target_ulong tbr; /* trap base register */
int psrs; /* supervisor mode (extracted from PSR) */
int psrps; /* previous supervisor mode */
int psret; /* enable traps */
int psrpil; /* interrupt level */
uint32_t psrpil; /* interrupt level */
int psref; /* enable fpu */
jmp_buf jmp_env;
int user_mode_only;
@@ -144,19 +176,51 @@ typedef struct CPUSPARCState {
context) */
unsigned long mem_write_pc; /* host pc at which the memory was
written */
unsigned long mem_write_vaddr; /* target virtual addr at which the
target_ulong mem_write_vaddr; /* target virtual addr at which the
memory was written */
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
/* MMU regs */
#if defined(TARGET_SPARC64)
uint64_t lsu;
#define DMMU_E 0x8
#define IMMU_E 0x4
uint64_t immuregs[16];
uint64_t dmmuregs[16];
uint64_t itlb_tag[64];
uint64_t itlb_tte[64];
uint64_t dtlb_tag[64];
uint64_t dtlb_tte[64];
#else
uint32_t mmuregs[16];
#endif
/* temporary float registers */
float ft0, ft1, ft2;
double dt0, dt1, dt2;
float ft0, ft1;
double dt0, dt1;
float_status fp_status;
#if defined(TARGET_SPARC64)
target_ulong t0, t1, t2;
#define MAXTL 4
uint64_t t0, t1, t2;
uint64_t tpc[MAXTL];
uint64_t tnpc[MAXTL];
uint64_t tstate[MAXTL];
uint32_t tt[MAXTL];
uint32_t xcc; /* Extended integer condition codes */
uint32_t asi;
uint32_t pstate;
uint32_t tl;
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
uint64_t agregs[8]; /* alternate general registers */
uint64_t bgregs[8]; /* backup for normal global registers */
uint64_t igregs[8]; /* interrupt general registers */
uint64_t mgregs[8]; /* mmu general registers */
uint64_t version;
uint64_t fprs;
uint64_t tick_cmpr, stick_cmpr;
#endif
#if !defined(TARGET_SPARC64) && !defined(reg_T2)
target_ulong t2;
#endif
/* ice debug support */
@@ -165,6 +229,24 @@ typedef struct CPUSPARCState {
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
} CPUSPARCState;
#if defined(TARGET_SPARC64)
#define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \
} while (0)
#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL)
#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \
env->fsr = _tmp & 0x3fcfc1c3ffULL; \
} while (0)
// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II)
#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \
(0 << 24) | (MAXTL << 8) | (NWINDOWS - 1))
#else
#define GET_FSR32(env) (env->fsr)
#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
env->fsr = _tmp & 0xcfc1ffff; \
} while (0)
#endif
CPUSPARCState *cpu_sparc_init(void);
int cpu_sparc_exec(CPUSPARCState *s);
@@ -194,10 +276,17 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \
} while (0)
#ifdef TARGET_SPARC64
#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC))
#define PUT_CCR(env, val) do { int _tmp = val; \
env->xcc = _tmp >> 4; \
env->psr = (_tmp & 0xf) << 20; \
} while (0)
#endif
struct siginfo;
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
#define TARGET_PAGE_BITS 12 /* 4k */
#include "cpu-all.h"
#endif

View File

@@ -1,23 +1,41 @@
#ifndef EXEC_SPARC_H
#define EXEC_SPARC_H 1
#include "dyngen-exec.h"
#include "config.h"
register struct CPUSPARCState *env asm(AREG0);
#ifdef TARGET_SPARC64
#define T0 (env->t0)
#define T1 (env->t1)
#define T2 (env->t2)
#define REGWPTR env->regwptr
#else
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#undef REG_REGWPTR // Broken
#ifdef REG_REGWPTR
register uint32_t *REGWPTR asm(AREG3);
#define reg_REGWPTR
#ifdef AREG4
register uint32_t T2 asm(AREG4);
#define reg_T2
#else
#define T2 (env->t2)
#endif
#else
#define REGWPTR env->regwptr
register uint32_t T2 asm(AREG3);
#define reg_T2
#endif
#endif
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
#define DT0 (env->dt0)
#define DT1 (env->dt1)
#define DT2 (env->dt2)
#include "cpu.h"
#include "exec-all.h"
@@ -38,14 +56,27 @@ void do_fsqrts(void);
void do_fsqrtd(void);
void do_fcmps(void);
void do_fcmpd(void);
#ifdef TARGET_SPARC64
void do_fabsd(void);
void do_fcmps_fcc1(void);
void do_fcmpd_fcc1(void);
void do_fcmps_fcc2(void);
void do_fcmpd_fcc2(void);
void do_fcmps_fcc3(void);
void do_fcmpd_fcc3(void);
void do_popc();
void do_wrpstate();
void do_done();
void do_retry();
#endif
void do_ldd_kernel(target_ulong addr);
void do_ldd_user(target_ulong addr);
void do_ldd_raw(target_ulong addr);
void do_interrupt(int intno);
void raise_exception(int tt);
void memcpy32(target_ulong *dst, const target_ulong *src);
target_ulong mmu_probe(target_ulong address, int mmulev);
void dump_mmu(void);
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
void dump_mmu(CPUState *env);
void helper_debug();
void do_wrpsr();
void do_rdpsr();

Some files were not shown because too many files have changed in this diff Show More