Compare commits

..

503 Commits

Author SHA1 Message Date
(no author)
efb602cda3 This commit was manufactured by cvs2svn to create tag
'release_0_9_0'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_9_0@2402 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 22:06:28 +00:00
bellard
26a16623b8 darwin fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2401 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 22:06:27 +00:00
bellard
d8ecc0b913 Make cpu_signal_handler work on Mac OS X/Darwin x86
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2400 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 21:41:46 +00:00
bellard
19c80e50ee update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2399 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 21:22:42 +00:00
bellard
a0f51eadc6 removed
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2398 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 21:09:14 +00:00
bellard
b6aaab3b86 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2397 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 21:06:29 +00:00
bellard
df517cec51 int conversion test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2396 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:52:39 +00:00
bellard
2afbeee757 update path
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2395 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:51:14 +00:00
bellard
7b9c30c5ee update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2394 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:46:55 +00:00
bellard
c636bb66cc gdbserver fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2393 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:46:05 +00:00
bellard
84f2e8ef05 copyright update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2392 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:21:32 +00:00
bellard
a9ce859052 info vnc command (Anthony Liguori)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2391 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:20:30 +00:00
bellard
564c337efd Mouse relative offset VNC extension (Anthony Liguori)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2390 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 20:14:10 +00:00
bellard
2a2528266e This patch fixes typos in the commpage definition (Pierre d'Herbemont).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2389 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 19:50:01 +00:00
bellard
263466f53a This patch cleans up target_mach_msg_trap(), removes unuseful do_pread, begins sysctl implementation and implements fcntl (Pierre d'Herbemont).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2388 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 19:47:42 +00:00
bellard
1e2bed4f7e Darwin cleanup usage (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2387 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 19:43:27 +00:00
bellard
831952376e Darwin user help (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2386 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 19:42:07 +00:00
bellard
4fe8b87a7c gcc version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2385 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-05 19:38:35 +00:00
pbrook
1057eaa709 Fix 64-bit host register corruption.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2384 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-04 13:37:44 +00:00
ths
d96372efaa sem* and msg* for qemu, part2, by Kirill Shutemov.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2383 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 22:05:44 +00:00
ths
fa2948167f sem* and msg* for qemu, part1, by Kirill Shutemov.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2382 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 22:05:00 +00:00
ths
b49d07ba03 Use target_ulong type for emulator registers.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2381 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 03:57:09 +00:00
ths
33ef55bd96 Mingw build fix, by Johannes Schindelin.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2380 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 03:30:54 +00:00
ths
3fffc2234f PIIX4 SMBus host, EEPROM device emulation, by Ed Swierk.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2379 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 03:13:18 +00:00
ths
4a109bfbca Update MIPS TODO.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2378 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 02:56:33 +00:00
ths
01d6a890b4 Sparc arm/mips/sparc register patch, by Martin Bochnig.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2377 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 01:03:34 +00:00
ths
6a1cbf68b7 script=no for the TUN/TAP net option, by Jean-Christian de Rivaz
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2376 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-02 00:37:56 +00:00
bellard
c4e27dd441 64 bit syscall fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2375 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-01 22:12:43 +00:00
bellard
d80c7d1c47 64 bit syscall fixes - more logical mwait/monitor ECX test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2374 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-01 22:12:19 +00:00
bellard
0499e4a02a cwde and cdq fix in 64 bit mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2373 c046a42c-6fe2-441c-8c8c-71466251a162
2007-02-01 22:11:07 +00:00
ths
0dcece76f0 Remove redundant ENOMEDIUM define.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2372 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 13:34:07 +00:00
ths
01feaa058e Save some vm space for the regular program loading zone, by
Pierre d'Herbemont


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2371 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:24:18 +00:00
ths
bf53ca0190 Upgrade the apic version_id, by Don Laor.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2370 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:22:18 +00:00
ths
5a7b542bbd siginfo fix for Darwin/Mac OS X, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2369 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:16:51 +00:00
ths
fd6776422b Use Cocoa and CoreAudio backend by default on Darwin systems, by Pierre
d'Herbemont.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2368 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:10:07 +00:00
ths
46ea33974d Fix set_error return value, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2367 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:08:13 +00:00
ths
90e950d17f Fix GT64120 mapping with REDBOOT, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2366 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 12:02:12 +00:00
ths
3ddd00658e Fix 64bit-induced MIPS Malta breakage, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2365 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-31 11:48:27 +00:00
pbrook
a2d1ebaf89 GDB hosted syscalls.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2364 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-28 03:10:55 +00:00
pbrook
4046d9130e Use standard character device interface for gdbstub.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2363 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-28 01:53:16 +00:00
pbrook
f749998939 Add nodelay option for TCP character devices.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2362 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-28 00:10:01 +00:00
pbrook
e5b0bc445e Rearrange char event handlers to fix CHR_EVENT_RESET.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2361 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-27 23:46:43 +00:00
pbrook
dff5efc848 Accept --foo as an alias for -foo.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2360 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-27 17:19:39 +00:00
pbrook
64423fb206 Accept -help.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2359 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-27 17:11:41 +00:00
ths
6c3675cac3 ENODEV works also for __sun__, the magic number 4097 stemmed from the
windows support.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2358 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-26 17:18:49 +00:00
ths
71c2fd5cdf Define ENOMEDIUM to match ENODEV if it isn't available.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2357 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-26 15:37:46 +00:00
ths
df5cf72160 Make the tarball's VERSION part overridable from make invocation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2356 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 22:56:36 +00:00
ths
44cbbf18b9 Fix malta emulation for 64bit qemu.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2355 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 22:00:13 +00:00
ths
6070dd07e9 Split out SDL X keymap, by Bernhard Fischer.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2354 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 21:40:21 +00:00
ths
e6a71ae327 Add support for 82371FB (Step A1) and Improved support for 82371SB
(Function 1), by Carlo Marcelo Arenas Belon.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2353 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 21:35:22 +00:00
ths
5f4da8c0f3 New multiple snapshot support for VMDK, by Igor Lvovsky.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2352 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 21:05:24 +00:00
ths
b29a0341d7 EBase is limited to KSEG0/KSEG1 even on 64bit CPUs.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2351 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 18:01:23 +00:00
ths
4de9b249d3 Reworking MIPS interrupt handling, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2350 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 01:47:51 +00:00
ths
30c4bbace1 Fix DMA timeouts on FreeBSD, by Carlo Marcelo Arenas Belon.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2349 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-24 01:12:42 +00:00
ths
9c2149c8e0 Implementing dmfc/dmtc.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2348 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-23 22:45:22 +00:00
ths
17c275d9ce Update .cvsignore.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2347 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-23 01:47:46 +00:00
ths
81e1e20979 Update TODO.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2346 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-22 20:57:17 +00:00
ths
3b1c8be4f4 Fix PageMask handling, second part.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2345 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-22 20:50:42 +00:00
ths
c281868e26 Add dependency for fop_template.c.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2344 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-21 22:40:04 +00:00
pbrook
3c07f8e894 Don't resume guest when gdb connection terminates and -S specified.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2343 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-21 16:47:01 +00:00
ths
72f341ed1e TLB address wraparound hopefully fixed now.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2342 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-21 03:13:58 +00:00
ths
bc814401c2 Bring TLB / PageSize handling in line with real hardware behaviour.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2341 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-21 03:12:25 +00:00
pbrook
8e71621f78 Add ARM Angel semihosting to system emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2340 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-20 17:12:09 +00:00
pbrook
57be54bb3e Fix "make test2".
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2339 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-20 16:52:55 +00:00
ths
5f12ab4b10 Add more ATAPI CDROM DMA support, by Juergen Keil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2338 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-20 01:12:17 +00:00
ths
af23902bd9 Fix typo.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2337 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-20 00:29:01 +00:00
ths
472c5273e2 Change display colors, the LED bar is green and the text display is red.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2336 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-20 00:27:42 +00:00
ths
15dcf5aa86 Note more issues.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2335 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-19 17:56:23 +00:00
ths
7f1c9da998 Darwin build fix, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2334 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-18 22:43:16 +00:00
ths
284ec167e7 Add Darwin userspace emulation to Changelog.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2333 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-18 22:14:53 +00:00
ths
831b78254c Darwin userspace emulation, by Pierre d'Herbemont.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-18 20:06:33 +00:00
ths
54421cb17b Fix CDROM permission check, by Kazu <kazoo@r3.dion.ne.jp>.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2331 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-18 00:22:11 +00:00
ths
0da75eb135 Big endian support for Gallileo, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2330 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 23:35:01 +00:00
ths
605686cd7a Kqemu support for Solaris, by Ben Taylor.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2329 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 23:31:19 +00:00
ths
8182266352 Fix USB buffer size, by Herbert Xu.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2328 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 23:08:17 +00:00
ths
54fd9cdfb4 Slirp UDP fix, by Jason Wessel.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2327 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 22:47:40 +00:00
ths
9dbd25e664 Note newsworthy changes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2326 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 21:32:49 +00:00
ths
2c52c8169a Keep track of mips related issues.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2325 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 20:03:15 +00:00
ths
f1770b3e1f Disable Malta floppy controller for now, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2324 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 15:15:52 +00:00
pbrook
72742c8626 ARM boot fix (Jason Wessel).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2323 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-17 08:59:26 +00:00
ths
adb4796796 Improved console handling, thanks Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2322 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-16 23:02:36 +00:00
bellard
dabd98ddf5 fixed movd mmx/sse insn
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2321 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-16 19:28:58 +00:00
pbrook
daf90626be ARM ELF loader.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2320 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-16 18:54:31 +00:00
ths
5856de800d MIPS Malta system and devices support, by Aurelien Jarno and Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2319 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-15 23:58:11 +00:00
ths
fde7d5bd73 Gallileo GT64xxx support, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2318 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-15 18:32:02 +00:00
ths
5c2b87e34d PIIX4 support, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2317 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-15 17:08:08 +00:00
ths
567daa491f Increase MIPS BIOS from 128kB to 4MB, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2316 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-10 16:25:04 +00:00
ths
8f1c91d801 Devfn number for the PIIX3 southbridge, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2315 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-10 16:23:41 +00:00
ths
abcebc7e80 Devfn number for network PCI cards, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2314 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-10 16:17:21 +00:00
ths
f158755072 Restore SCSI disk attaching, by Igor Kovalenko.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2313 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-10 11:46:13 +00:00
bellard
bf8c534200 ifname arg fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2312 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-09 19:44:41 +00:00
bellard
0178196398 win32: physical drive support (initial patch by kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2311 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 22:43:30 +00:00
bellard
18607dcb7c added cutils.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2310 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 22:04:40 +00:00
ths
96d30e4801 Revert -disk patch, as requested by Fabrice. The general idea of this
patch is sound, but the implementation is just too ugly.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2309 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 20:42:14 +00:00
pbrook
2f67a0d55a Script to check for missing FORCE_RET.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2308 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 19:38:08 +00:00
bellard
21664424ed path_is_absolute() fix for win32
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2307 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 18:22:37 +00:00
bellard
3b39528c15 removed redundant qemu_aio_flush()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2306 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 17:33:20 +00:00
bellard
3b9f94e1a8 win32 block device fixes (initial patch by kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2305 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 17:27:07 +00:00
bellard
f5e25d7007 Japanese keyboard patch (kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2304 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-07 17:12:41 +00:00
ths
2909b29aee Unbreak the last patch.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2303 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-06 02:24:15 +00:00
ths
f7bcd4e373 Different MIPS BIOS binary names per endianness, and more relaxed size
rules for the binaries, by Alec Voropay.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2302 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-06 01:37:51 +00:00
ths
43c1b7e4c3 Add new Etherboot ROMs for PXE boot.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2301 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 23:48:51 +00:00
ths
86e94dea5b Reinitialize monitor upon reconnect, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2300 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 22:01:59 +00:00
ths
8f28f3fbbe Configure check for alsa, by Bernhard Fischer.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2299 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 21:25:54 +00:00
ths
43f238d7b6 Support fcntl F_GETLK64, F_SETLK64, F_SETLKW64, by Kirill A. Shutemov.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2298 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 20:55:49 +00:00
ths
4dbb0f5006 Fix for hard disk translation hints, by Volker Ruppert.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2297 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 18:58:34 +00:00
ths
6850dd945e Support for Bochs "growing" images, by Volker Ruppert.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2296 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 18:56:04 +00:00
ths
b92090309e Fix comment, by Volker Ruppert.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2295 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 18:52:57 +00:00
ths
2e9671daee patch for block-raw.c for Solaris, by Ben Taylor.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2294 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 17:44:41 +00:00
ths
eec85c2a0d Add -boot n option for x86 using PXE, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2293 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 17:41:07 +00:00
ths
9ae0255520 Add -option-rom option to allow loading of PCI option ROMs, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2292 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 17:39:04 +00:00
ths
a0ae05aa63 PPC32 Trace Exception and Trap instruction, by Jason Wessel.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2291 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 16:54:16 +00:00
ths
455204eb1a Dynamic handling of guest mice, by Lonnie Mendez.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2290 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 16:42:13 +00:00
ths
6f30fa853b Untangle the various CFLAGS/LDFLAGS flavours. Allow overriding the
optional flags at make time.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2289 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-05 01:00:47 +00:00
bellard
b371dc594b memsave monitor command
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2288 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-03 15:20:39 +00:00
bellard
2ee4aed86f moved invalidate_tlb() to helper.c as a work around for gcc 3.2.2 bug - suppressed invalid tb_invalidate_page_range() calls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2287 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-03 15:18:08 +00:00
pbrook
df628ff14e Arm GIC stuck interrupt fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2286 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-02 19:33:15 +00:00
ths
240f24e013 Fix Makefile weirdness.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2285 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 21:31:01 +00:00
ths
0feef828e1 Fix bad data type.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2284 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 20:35:21 +00:00
ths
3a3f24fce8 Fix lwl/lwr for 64bit emulation, also debug output spec for 64bit emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2283 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 20:34:37 +00:00
ths
7495fd0f4a Simplify code and fix formatting.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2282 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 20:32:08 +00:00
ths
f8c6ff6c3c Fix initrd load address.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2281 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 20:31:07 +00:00
pbrook
04e897efdd Remove duplicate TARGET_M68K case.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2280 c046a42c-6fe2-441c-8c8c-71466251a162
2007-01-01 14:14:34 +00:00
pbrook
388c45084d bFLT loader commandline fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2279 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-26 18:27:07 +00:00
ths
fa1fb14cd2 Fix SCSI cdrom boot, thanks Blue Swirl.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2278 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-24 17:12:43 +00:00
ths
1f95844967 Null character instead of numeric null.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2277 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 22:51:27 +00:00
pbrook
a14d6c8c65 Solaris SMBD hacks (Ben Taylor).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2276 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 15:37:33 +00:00
ths
04d4b0c33f Simplify error handling again.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2275 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 15:18:47 +00:00
ths
9042c0e20d Check ELF binaries for machine type and endianness.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2274 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 14:18:40 +00:00
ths
70ead43412 Use memory barriers in FORCE_RET / RETURN.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2273 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 00:49:32 +00:00
ths
5bf089345b Fix spelling.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2272 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 00:33:26 +00:00
ths
eddbd288a0 More serial ports for the mips machine.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2271 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 00:23:19 +00:00
ths
28d657fc0b Fix build warning on Windows.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2270 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-23 00:03:15 +00:00
pbrook
4258b780af Sparc64 build fix (Igor Kovalenko).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2269 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 22:35:25 +00:00
ths
52f61fdeec Windows build fix, namespace cleanup, fix error message, by Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2268 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 21:20:52 +00:00
ths
c26c1c4b3d Support for unidirectional pipes, by Ed Swierk.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2267 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 19:25:31 +00:00
ths
c032e2a98c Fix -cdrom breakage.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2266 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 17:29:05 +00:00
ths
42550fde7e SCSI emulation improvements, by Chuck Brazie.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2265 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 16:34:12 +00:00
ths
62ee021121 Build fix for AIO (-dummy) on Windows, by Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2264 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 14:19:53 +00:00
ths
fef3074347 Escape filname printout properly, by Anthony Liguori and Julian Seward.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2263 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 14:11:32 +00:00
ths
bd491d6a4e Fix CDROM change, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2262 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 02:14:49 +00:00
ths
71e3ceb800 Daemonize option, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2261 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 02:11:31 +00:00
ths
73fc97427b Unix domain socket support for VNC, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2260 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-22 02:09:07 +00:00
ths
ffd843bcdc Run monitor over unix domain sockets, by Anthony Liguori.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2259 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 19:46:43 +00:00
ths
1cb6c3fd38 Fix "inaccessible boot device" on FreeBSD, by Juergen Lock.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2258 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 19:14:11 +00:00
ths
eaf7e70b01 Enable TCP_NODELAY, by Daniel Jacobowitz.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2257 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 19:10:59 +00:00
ths
8bdc2159db Don't cast lvalues, fixes compiler warning.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2256 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 17:24:45 +00:00
ths
416b5d366d Avoid "unused variable" compiler warning.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2255 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 17:23:49 +00:00
ths
d8b20157fc Remove unused variable.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2254 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 16:50:54 +00:00
ths
92190c648a Silence a spurious gcc warning.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2253 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 16:50:09 +00:00
ths
a86c8f29de Fix compiler warnings, add signed versions of some swab functions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2252 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 16:49:27 +00:00
ths
5dc4b74480 Scrap SIGN_EXTEND32.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2251 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 13:48:28 +00:00
ths
c570fd169c Preliminiary MIPS64 support, disabled by default due to performance impact.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2250 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-21 01:19:56 +00:00
pbrook
328a42406d Look for gcc3 (Anthony Liguori).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2249 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-19 03:31:34 +00:00
pbrook
67d3b957e6 Add unassigned memory debugging code.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2248 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-18 05:03:52 +00:00
ths
179e32bbcc Fix erraneous fallthrough in MIPS trap implementation, thanks Atsushi Nemoto.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2247 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-16 16:45:18 +00:00
ths
e4630047e1 Simple test for mips/mipsel, based on a test by Alexander Voropay.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2246 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-14 14:48:11 +00:00
ths
73e14b623f Reduce VNC resize traffic, thanks Eduardo Felipe.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2245 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-14 13:36:01 +00:00
ths
768a4a36a4 Fix userland ELF loader for zero sized BSS.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2244 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-14 13:32:11 +00:00
ths
0d3267a728 MIPS has also a fixed MMAP_SHIFT of 12.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2243 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-11 22:04:25 +00:00
ths
8e33c08c84 MIPS FPU support for the gdb stub, by Daniel Jacobowitz.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2242 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-11 19:22:27 +00:00
ths
197ea35ab2 Fix addrlen size, by David Woodhouse.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2241 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-11 19:13:59 +00:00
ths
366dfc521e Spelling fixes, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2240 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-11 18:35:08 +00:00
ths
667accab8e Implement -no-quit option, by Xavier Gnata.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2239 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-11 02:08:05 +00:00
ths
a2d4e44b48 Fix PCI config space overflow, by Herbert Xu.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2238 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-10 23:20:45 +00:00
ths
3bcb80f1af Fix sector size overflow, by Herbert Xu.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2237 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-10 23:07:39 +00:00
ths
a42aa81571 Build fix for newer kernel headers, thanks Jason Wessel.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2236 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-10 22:11:04 +00:00
ths
ca7c2b1b9f Handle invalid accesses as SIGILL for mips/mipsel userland emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2235 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-10 22:08:10 +00:00
ths
7d600c804d Fix fstat for MIPS userland emulation, and add support for a cacheflush
syscall, thanks to Dave Denholm.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2234 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-08 01:32:58 +00:00
ths
71fb7241c6 Fix build of MIPS target without FPU support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2233 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 20:07:37 +00:00
ths
9f08349345 Spelling fixes, thanks to Stefan Weil.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2232 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 18:28:42 +00:00
ths
afdfa781e6 MIPS RTC emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2231 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 18:15:35 +00:00
ths
cd75cf10ca .cvsignore m68k-user.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2230 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 17:18:01 +00:00
ths
ea55ffb373 Move date/time init to the RTC implementation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2229 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 17:16:55 +00:00
ths
aa328addc0 Fix reset handling, CP0 isn't enabled by default (a fact which doesn't
matter when running in kernel space).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2228 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 16:22:15 +00:00
ths
e144966416 Simplify mask construction.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2227 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-07 00:30:19 +00:00
ths
bb8a53ad91 Update copyright notice.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2226 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 23:12:49 +00:00
ths
e16fe40c87 Move the MIPS CPU timer in a seperate file, by Alec Voropay.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2225 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 21:38:37 +00:00
ths
7a387fffce Add MIPS32R2 instructions, and generally straighten out the instruction
decoding. This is also the first percent towards MIPS64 support.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2224 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 20:17:30 +00:00
ths
8c0fdd856c Dynamically translate MIPS mtc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2223 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 18:19:33 +00:00
ths
873eb01234 Dynamically translate MIPS mfc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2222 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 17:59:07 +00:00
ths
6ae817752b Halt/reboot support for Linux, by Daniel Jacobowitz. This is a band-aid
until we emulate real MIPS hardware with real firmware.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2221 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 17:48:52 +00:00
ths
814b9a4749 MIPS TLB performance improvements, by Daniel Jacobowitz.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2220 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 17:42:40 +00:00
ths
ec2309289d sparc-softmmu build fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2219 c046a42c-6fe2-441c-8c8c-71466251a162
2006-12-06 15:51:39 +00:00
pbrook
29bfb11725 Add casts for 64-bit hosts.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2218 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-19 23:07:17 +00:00
pbrook
08f396d720 Add missing ARM syscall numbers.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2217 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-19 21:51:51 +00:00
pbrook
38d0662a4c Arm semihosted commandline support (Wolfgang Schildbach).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2216 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-19 20:29:35 +00:00
pbrook
1be9e1dc56 Remove do_socketcallwrapper.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2215 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-19 15:26:04 +00:00
pbrook
ec2db7de7a ARM timer counts down, not up.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2214 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-14 21:13:53 +00:00
pbrook
417f38f066 MIPS FPU fixes (Daniel Jacobowitz).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2213 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-12 23:54:39 +00:00
pbrook
2d37be61e3 M68k build fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2212 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-12 21:31:18 +00:00
pbrook
483dcf538e Avoid redundant TLB flushes (Daniel Jacobowitz).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2211 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-12 20:55:05 +00:00
pbrook
b362e5e067 Speed up tlb_flush_page (Daniel Jacobowitz).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2210 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-12 20:40:55 +00:00
pbrook
d08b2a28e6 MIPS usermode debug exceptions (Dave Denholm).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2209 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-04 16:46:29 +00:00
bellard
597a0559fd update from latest Bochs BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2208 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-01 19:19:17 +00:00
pbrook
188157fe87 Remove FD on close.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2207 c046a42c-6fe2-441c-8c8c-71466251a162
2006-11-01 01:44:16 +00:00
pbrook
58126404f5 Mips IDE support. (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2206 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-29 15:38:28 +00:00
bellard
569f5d668c compilation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2205 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-29 15:10:09 +00:00
bellard
750afe93fd avoid using char when it is not necessary
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2204 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-28 19:27:11 +00:00
bellard
00a67ba19a avoid regression on sparc-user and ppc-user
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2203 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-28 12:19:07 +00:00
bellard
fafffaef4f removed invalid code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2202 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-28 12:09:16 +00:00
pbrook
a94a6abff4 Fix ARM VFP debugging dumps.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2201 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-25 17:43:33 +00:00
bellard
c688a6eb18 wrwim insn fix (Paul Robinson)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2200 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-23 21:37:34 +00:00
bellard
27908725b9 sparc64 syscall fix (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2199 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-23 21:31:01 +00:00
bellard
dd016883fb add support for cvt.s.d and cvt.d.s (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2198 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-23 21:25:11 +00:00
pbrook
d37aca6625 Fix comment typo.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2197 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-22 11:54:30 +00:00
pbrook
e6e5906b6e ColdFire target.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2196 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-22 00:18:54 +00:00
pbrook
223b8a40d1 bFLT 64-bit host fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2195 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-21 23:43:02 +00:00
pbrook
1f9519c92d Fix typo in pixel conversion templates.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2194 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-18 21:16:44 +00:00
bellard
b4511723bd APIC init fix + APIC get_irq fix (Juergen Keil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2193 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-08 18:20:51 +00:00
bellard
d1beab8220 no-reboot option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2192 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-02 19:44:22 +00:00
bellard
e3e97e7c90 do not generate MP table if one CPU (no APIC in QEMU in this case) - added wbinvd (ignored in QEMU but useful on real hardware)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2191 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-02 18:35:39 +00:00
bellard
47d02f6d5c SMI enable bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2190 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-02 18:25:40 +00:00
bellard
93eac243d5 32 bit syscall fix (Juergen Keil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2189 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-02 17:58:33 +00:00
bellard
a7e6f8ba22 synced to Bochs BIOS - use 32 bit pushf/popf in 32 bit PCI bios - moved some useful defines in rombios.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2188 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-01 16:08:15 +00:00
pbrook
326199c270 ARM GIC bug.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2187 c046a42c-6fe2-441c-8c8c-71466251a162
2006-10-01 13:03:52 +00:00
bellard
8d7b0fbb3f 32 bit RSP update fix (aka Open Solaris x86_64 bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2186 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-29 20:01:17 +00:00
pbrook
5e966ce6f4 PCI IRC routing fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2185 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-28 19:52:59 +00:00
bellard
74ce674fa8 fixed user mode emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2184 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-27 21:31:59 +00:00
bellard
8988ae8945 SMM fix for x86_64
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2183 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-27 19:54:02 +00:00
bellard
69c3bcb48f enabled PSE36 for x86_64 (fix for OpenSolaris as guest)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2182 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-27 19:52:41 +00:00
bellard
42fc925ec0 VBE 4 bit bank selection fix (Volker Rupper)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2181 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-25 21:41:20 +00:00
bellard
6f15b608f2 removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2180 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-25 21:34:25 +00:00
bellard
17100159f1 fixed help info strings
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2179 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-25 21:33:49 +00:00
bellard
79266dbd9e updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2178 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 19:36:49 +00:00
bellard
84631fd79c implement i440 instead of i450 ISA memory mappings to be compatible with Bochs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2177 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 19:31:43 +00:00
bellard
4f3baa4b36 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2176 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:49:55 +00:00
bellard
f00fc47c15 moved PCI init to BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2175 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:49:43 +00:00
bellard
ee0ea1d0dd moved PCI init to BIOS - added ISA memory mapping registers and SMM support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2174 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:49:13 +00:00
bellard
02a1602e62 added cpu_smm_update()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2173 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:48:23 +00:00
bellard
a5954d5c34 moved MP table init to BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2172 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:48:00 +00:00
bellard
f537a28c97 moved ACPI table init to BIOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2171 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:45:28 +00:00
bellard
ab1e34add6 moved ACPI table init to BIOS - preliminary SMM support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2170 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:44:17 +00:00
bellard
3b21e03e04 added SMM support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2169 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:41:56 +00:00
bellard
ba86345802 added cpu_get_physical_page_desc()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2168 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:41:10 +00:00
bellard
d4afc623ae moved PCI, MP and ACPI init to bios
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2167 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 18:38:12 +00:00
pbrook
80b3ada7dd Implement sun4u PCI IRQ routing.
Allow multiple PCI busses and PCI-PCI bridges.
Fix bugs in Versatile PCI implementation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2166 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 17:01:44 +00:00
pbrook
d2b5931756 PCI shared IRQ fix (original patch by andrzej zaborowski).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2165 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-24 00:16:34 +00:00
pbrook
e69954b9fc Add ARM RealView Emulation Baseboard.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2164 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-23 17:40:58 +00:00
bellard
37dd208d38 VBE: 8 bit DACs + support for VBE BIOS IDs (Volker Ruppert)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2163 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-21 21:46:53 +00:00
pbrook
05f83f0f95 Update sparc bios image (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2162 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-21 20:34:50 +00:00
bellard
df52b0009b sun4m halt support (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2161 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-20 20:30:57 +00:00
bellard
8f40c388ef update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2160 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-20 20:28:05 +00:00
pbrook
aef445bd7e Merge common ISA access routines.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2159 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-18 01:15:29 +00:00
pbrook
6787f5fae0 SPARC SCSI fixes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2158 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-17 03:20:58 +00:00
bellard
b8174937ed dummy cs4231 audio driver for sun4m (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2157 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-10 19:25:12 +00:00
pbrook
519945dfbe Avoid (repeatedly) trying to read stdin after it has closed.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2156 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-10 14:39:54 +00:00
pbrook
707b3ee068 ARM 64-bit host fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2155 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 23:35:22 +00:00
pbrook
78600320a8 Arm MMU fix (Justin Fletcher).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2154 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 14:36:26 +00:00
bellard
35db099ddb allow host serial port usage (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2153 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 12:17:15 +00:00
bellard
6bcb76c3b6 vvfat fixes (Roger Lathrop)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2152 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 12:03:20 +00:00
bellard
e4a89056df fix serial irq logic (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2151 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 11:38:11 +00:00
bellard
715748fa08 added mouse protocol (Igor Kovalenko)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2150 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 11:35:47 +00:00
bellard
21206a104f more correct display functions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2149 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 11:31:34 +00:00
bellard
094eed6ca5 two stop bits support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2148 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-09 11:10:18 +00:00
bellard
9b94dc325b better PCNET endianness support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2147 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 19:48:17 +00:00
bellard
c6d46c200f typo
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2146 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 17:10:41 +00:00
bellard
e17a36ce41 multi byte nop support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2145 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 17:09:02 +00:00
bellard
03c1847584 endianness fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2144 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 16:40:12 +00:00
bellard
67e999be93 Separate the DMA controllers - Convert ESP to new DMA methods (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2143 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 16:09:07 +00:00
bellard
91cc029598 initial sparc32 lance and pcnet merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2142 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 16:07:02 +00:00
bellard
c03b0f0fd8 allow disabling of serial or parallel devices (Stefan Weil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2141 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 14:10:53 +00:00
pbrook
6192bc374f Flush IO requests before savevm (original patch by Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2140 c046a42c-6fe2-441c-8c8c-71466251a162
2006-09-03 12:08:37 +00:00
pbrook
a917d384ac SCSI TCQ support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2139 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-29 04:52:16 +00:00
bellard
508d92d057 16 bit divider
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2138 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-26 18:00:36 +00:00
bellard
64f5a135a7 signed fixes - VNC console switch (initial patch by Andrzej Zaborowski)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2137 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-24 20:36:44 +00:00
bellard
a817d93656 fixed handling of relative filenames with -snapshot
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2136 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-24 19:53:37 +00:00
bellard
fd44d81821 win32 aio emulation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2135 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-24 18:58:29 +00:00
bellard
f45512feac win32 compilation fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2134 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-23 21:40:13 +00:00
bellard
6b21b973ab fixed error handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2133 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-23 21:14:37 +00:00
bellard
2192c33250 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2132 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-21 20:28:18 +00:00
bellard
f542086dd4 spelling fixes (Stefan Weil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2131 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-21 20:26:44 +00:00
bellard
ee0f47514c removed outdated info
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2130 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 16:56:18 +00:00
bellard
60659e3b44 Japanese keyboard fixes (kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2129 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 14:27:31 +00:00
bellard
f0e4217213 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2128 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 12:38:38 +00:00
bellard
e6cda8e299 win32 tap poll suppression (kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2127 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 12:37:52 +00:00
bellard
b56bdb328a delete block device
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2126 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 11:58:59 +00:00
bellard
a9f277ba8f no need for bdrv_close()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2125 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 11:58:10 +00:00
bellard
19cb37389f better support of host drives
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 11:45:59 +00:00
bellard
66c6ef7678 better support of removable media
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 11:44:21 +00:00
bellard
ea185bbda7 use bdrv_media_changed()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2122 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-19 11:43:22 +00:00
bellard
83acc96b23 fixed VGA resolutions with height > 1024
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2121 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-18 09:32:04 +00:00
bellard
6e1b3e4da4 disable -fomit-frame-pointer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2120 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 17:41:26 +00:00
bellard
87b47350ed -L help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2119 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 17:22:54 +00:00
bellard
243a273ee0 fd leak fix (Igor Kovalenko)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2118 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 16:19:07 +00:00
bellard
c3d78997a3 minimal PCI IDE save/restore
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2117 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:48:35 +00:00
bellard
e6cf6a8c7d save apic timer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2116 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:48:06 +00:00
bellard
1941d19c65 PCI save/restore changes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2115 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:46:34 +00:00
bellard
89b6b50892 vga init changes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2114 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:45:20 +00:00
bellard
d2269f6f64 save VGA PCI state
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2113 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:44:00 +00:00
bellard
dfd92d3a46 reset key modifiers when switching console (aka savevm keyboard bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2112 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 10:42:46 +00:00
bellard
4c279bdf3a win32 compilation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2111 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-17 09:43:50 +00:00
pbrook
3dc1cb3428 ESP DMA fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2110 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-15 22:57:33 +00:00
pbrook
35f1df84b6 scsi empty drive fix (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2109 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-14 15:08:12 +00:00
pbrook
69fba4a51e Remove OpenBIOS ESP patch. Merged upstream.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2108 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-13 14:20:43 +00:00
pbrook
4d611c9a2f SCSI and USB async IO support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2107 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-12 01:04:27 +00:00
pbrook
4ca9c76f36 Add SCSI controller class.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2106 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-10 01:03:35 +00:00
bellard
2a98c1981f removed tabs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2105 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-09 22:38:19 +00:00
bellard
35b961cf8d indent
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2104 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-09 21:55:55 +00:00
bellard
8ccad811e6 use AIO for DMA transfers - enabled DMA for CDROMs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2103 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 21:36:34 +00:00
bellard
e84a4fedf7 mem leak fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2102 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 21:35:12 +00:00
bellard
fb43f4dddc copyright update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2101 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 21:34:46 +00:00
bellard
19d36792c0 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2100 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 21:34:34 +00:00
bellard
90765429aa fixed aio emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2099 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 19:10:16 +00:00
pbrook
ce1a14dc0d Dynamically allocate AIO Completion Blocks.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2098 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-07 02:38:06 +00:00
bellard
51d6bae7a8 removed duplicated line
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2097 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 21:13:56 +00:00
bellard
13a2e80f04 info about VM snapshots
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2096 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 14:50:31 +00:00
bellard
c88676f89c use zlib to compress ram snapshots - correctly save qemu clock
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2095 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 13:36:11 +00:00
bellard
d15a771da1 qcow2 is now used for '-snapshot' - keep BlockDriverState.total_sectors
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2094 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 13:35:09 +00:00
bellard
a946592212 handle read outside the backing file
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2093 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 13:34:04 +00:00
pbrook
1aacf3489b Add missing #define.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2092 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 13:27:39 +00:00
pbrook
51c1ebb1bc Fix SCSI off-by-one device size.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2091 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 11:31:06 +00:00
bellard
6eb5733a3c fixed blocking io emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2090 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-06 09:51:25 +00:00
bellard
15e6690aca fixed disk image creation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2089 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 22:24:28 +00:00
bellard
c47c33b098 block API change
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2088 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:32:10 +00:00
bellard
e70332b376 use QEMUFile API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2087 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:31:46 +00:00
bellard
faea38e786 multiple snapshot support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2086 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:31:00 +00:00
bellard
42ca638823 enable qcow2
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2085 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:29:27 +00:00
bellard
9ab8a34a18 O_LARGEFILE is not needed
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2084 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:27:55 +00:00
bellard
585f8587ad new qcow2 disk image format
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2083 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-05 21:14:20 +00:00
bellard
9e46cfa4c6 sparc64.ld file (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2082 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-04 21:55:15 +00:00
bellard
e2f909bef9 swapped memset args (Charles Coffing)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2081 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-03 20:39:40 +00:00
bellard
7f1a8398ab removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2080 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-03 17:53:19 +00:00
bellard
e7b81015e5 added missing returns
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2079 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-03 17:52:41 +00:00
bellard
436e15b827 win32 fixes (initial patch by kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2078 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-03 09:07:19 +00:00
bellard
550be12730 fixed refresh logic (initial patch by Igor Kovalenko)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2077 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-02 22:19:33 +00:00
bellard
979b67ad86 some compilation fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2076 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-02 22:02:08 +00:00
bellard
83f6409109 async file I/O API
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2075 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-01 16:21:11 +00:00
bellard
7954c73498 commit to specific devices
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2074 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-01 15:52:40 +00:00
bellard
93b6b2a3cd show backing file name
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2073 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-01 15:51:11 +00:00
bellard
d62ca2bb9b removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2072 c046a42c-6fe2-441c-8c8c-71466251a162
2006-08-01 15:50:14 +00:00
pbrook
4615218210 Rewrite Arm host support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2071 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-30 19:16:29 +00:00
pbrook
f3a9676a60 Arm host build fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2070 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-29 19:09:31 +00:00
bellard
47dbd1f32d error display fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2068 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-22 17:06:44 +00:00
pbrook
d07edbfa00 Fix Arm cp15 c13 (Process ID) register writes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2067 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-21 22:39:57 +00:00
bellard
059809e451 usb destroy API change (Lonnie Mendez)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2066 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-19 18:06:15 +00:00
bellard
3b2ccc57c7 Linux compilation fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2065 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-19 17:54:57 +00:00
bellard
74ccb34e6b Sparc64 host support (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2064 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-18 21:23:34 +00:00
bellard
5ef54116ea Sparc64 user emulator fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2063 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-18 21:14:09 +00:00
bellard
725cb90bf7 sparc64 fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2062 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-18 21:12:17 +00:00
bellard
a3c259974e audio capture fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2061 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-18 21:09:59 +00:00
pbrook
69db0ac75a Fix comment typo.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2060 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-17 18:45:34 +00:00
bellard
ec36b695b0 audio capture to wab files (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2059 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-16 18:57:03 +00:00
bellard
6330126439 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2058 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-16 18:56:50 +00:00
pbrook
634fce96eb Defer timer initialization until after commandline processing.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2057 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-15 17:40:09 +00:00
bellard
13224a87fb added mouse event generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2056 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 22:03:35 +00:00
bellard
7ba1260ac1 generate CRLF instead of LF
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2055 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 20:26:42 +00:00
bellard
bd468840d4 fixed LF interpretation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2054 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 20:24:31 +00:00
bellard
3c656346c9 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2053 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 13:13:51 +00:00
bellard
29b9a3456f win32 compilation fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2052 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 09:40:02 +00:00
bellard
a8e5ac33d2 win32 compilation - force process affinity on win32 as a workaround for SMP issues
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2051 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-14 09:36:13 +00:00
bellard
ec607da7c2 avoid recursive tx
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2050 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-13 23:25:11 +00:00
bellard
1dce7c3c22 new clock logic: cpu ticks and virtual clocks are no longer proportional - added timestamps on the stdio console
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2049 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-13 23:20:22 +00:00
bellard
effedbc915 export cpu_get_real_ticks()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2048 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-13 23:00:40 +00:00
bellard
9f909fefd5 use posix timers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2047 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-13 23:00:26 +00:00
bellard
718da2b9b0 fixed for TCP segmentation offloading - removed dependency on slirp.h (Igor Kovalenko)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2046 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-10 21:38:17 +00:00
bellard
0de6bb73fd monitor/mwait workaround
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2045 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-10 19:53:43 +00:00
bellard
3d7374c5da monitor/mwait support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2044 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-10 19:53:04 +00:00
pbrook
4f2092904d Don't include audio.h when building tools.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2043 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-05 14:39:57 +00:00
bellard
d929eba5d4 audio endianness API changes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2042 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 21:47:22 +00:00
bellard
219fb12503 avoid unneeded dependencies
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2041 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 21:42:10 +00:00
bellard
8ead62cfc2 audio fixes + initial audio capture support (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2040 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 16:51:32 +00:00
bellard
feea13e186 sb16 fixes (WfW 3 appears to work with shipped drivers) (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2039 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 16:49:00 +00:00
bellard
6c270db741 rate converter fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2038 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 16:47:58 +00:00
bellard
47378eb1ca update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2037 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 16:33:33 +00:00
bellard
e3c2613f91 pcnet nic support (Antony T Curtis)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2036 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 11:33:00 +00:00
bellard
6cadb320c7 rtl8139 fixes (Igor Kovalenko)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2035 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 10:08:36 +00:00
bellard
856074ec70 fix for IO_MEM_ROMD support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2034 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 09:47:34 +00:00
bellard
99ba31b4fe flash device fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2033 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-04 09:46:31 +00:00
bellard
0510224e89 disable unimplemented C+ mode (aka windows xp 64 fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2032 c046a42c-6fe2-441c-8c8c-71466251a162
2006-07-01 21:41:18 +00:00
bellard
106ec87921 initial MIPS signal handling (initial patch by Raphael Rigo)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2031 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-27 21:08:10 +00:00
bellard
951f13516a telnet protocol and more consistent syntax (Jason Wessel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2030 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-27 21:02:43 +00:00
bellard
1f6e24e73c display device identifier string for user with info usb (Lonnie Mendez)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2029 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 21:00:51 +00:00
bellard
3e382bc84c consistent update of ERL and EXL
(Dirk Behme)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2028 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 20:29:47 +00:00
bellard
beac80cd43 Windows sparse file support (Frediano Ziglio)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2027 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 20:08:57 +00:00
bellard
3587d7e69c fix crash when closing windows (Frediano Ziglio)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2026 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 20:03:44 +00:00
bellard
d796321b6b lwu support - generate exception if unaligned pc (Marius Groeger)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2025 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 20:02:45 +00:00
bellard
567d4107a6 qsub fix (Wolfgang Schildbach)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2024 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 19:55:19 +00:00
bellard
a80dde0837 SPARC FPU optimization (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2023 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-26 19:53:29 +00:00
bellard
29133e9a0f AMD NOR flash device support (initial patch by Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2022 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 22:28:15 +00:00
bellard
9d42037b1d support for dynamic address space changes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2021 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 22:25:22 +00:00
bellard
2a4188a38f low level support for memory mapped flash devices (initial patch by Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2020 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 21:54:59 +00:00
bellard
4f4fbf77ad 64 bit support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2019 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 18:28:12 +00:00
bellard
26a76461f2 C99 64 bit printf
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2018 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 18:15:32 +00:00
bellard
3b42c9794c sse2 comment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2017 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 18:02:38 +00:00
bellard
755d13753b removed warning
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2016 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 18:02:02 +00:00
bellard
26489844dc avoid name conflicts
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2015 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 17:37:36 +00:00
bellard
87ac54273f disable user targets by default for cross compile with mingw32
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2014 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 17:35:56 +00:00
bellard
a18e524af0 multiple wait object support for win32 (kazu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2013 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 17:18:27 +00:00
bellard
e15d737181 send correctly long key sequences on slow terminals - fixes backspace handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2012 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 16:26:29 +00:00
bellard
be995c2764 removed unused code - init timers earlier
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2011 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 16:25:21 +00:00
bellard
6b1575b746 cpu_get_phys_page_debug fix (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2010 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 15:33:53 +00:00
bellard
9d9754a31d sparc fpu fix - allow 64 bit addresses (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2009 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 15:32:37 +00:00
bellard
1579bde84d update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2008 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 14:50:00 +00:00
bellard
0bab00f30f UDP char device (initial patch by Jason Wessel) - TCP char device
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2007 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-25 14:49:44 +00:00
bellard
3532fa7402 mips socket calls (initial patch by Raphael Rigo)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2006 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-24 15:06:03 +00:00
bellard
480c1cdb39 fix for movq2dq, movdq2q and cvttps2dq (thanx to Julian Seward and malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2005 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-24 14:03:10 +00:00
bellard
80e7d52103 added movdq2q and movq2dq
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2004 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-24 14:01:32 +00:00
bellard
13846e700f Sparc64 BPr branch target fix (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2003 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-23 21:01:56 +00:00
bellard
3cb0853ad7 more info about -std-vga
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2002 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-21 21:19:50 +00:00
bellard
1bdb68ea13 fixed sparc64 cpu fp save/restore
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2001 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-21 18:48:01 +00:00
bellard
65ce8c2fb4 soft floats for SPARC (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2000 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-21 18:37:05 +00:00
bellard
ee6c0b51e9 sparc branch fix (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1999 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-21 18:26:15 +00:00
bellard
48dc41eb8b sparc user fixes (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1998 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-21 18:15:50 +00:00
bellard
a891c7a194 fxam fix (Julian Seward)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1997 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-19 22:43:38 +00:00
bellard
b2a8e59224 fxam test
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1996 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-19 22:42:57 +00:00
bellard
447c2cefcb switch_tss eflags restore fix (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1995 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-19 22:06:13 +00:00
pbrook
75956cf032 Sun4u vga+bios tweaks (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1994 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-18 19:41:28 +00:00
pbrook
ded3ab80dd Sparc64 insn fixes (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1993 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-18 19:36:58 +00:00
pbrook
908f52b05c Add big-endian SH4-user target
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1992 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-18 19:16:53 +00:00
pbrook
9c2a9ea1b1 SH bugfixes.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1991 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-18 19:12:54 +00:00
pbrook
397e923f7f Remove debug output.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1990 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-17 20:04:26 +00:00
pbrook
4dbed8972b Enable SH bFLT loader.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1989 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-17 20:01:14 +00:00
pbrook
355fb23d83 SH usermode fault handling.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1988 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-17 19:58:25 +00:00
pbrook
9854bc4662 SH4 rts fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1987 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-17 18:48:31 +00:00
pbrook
978efd6aac Respond to qOffsets gdb packet (for debugging bFLT binaries).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1986 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-17 18:30:42 +00:00
pbrook
e6de1bad46 Arm h/w doc updates.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1985 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-16 21:48:48 +00:00
bellard
30a604f363 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1984 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 18:35:18 +00:00
bellard
856860f5e3 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1983 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 18:18:38 +00:00
bellard
ce05c32384 allow ACPI table build
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1982 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 18:17:46 +00:00
bellard
1ce549abf9 more ACPI definition to keep Solaris Happy (Juergen Kiel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1981 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 18:17:04 +00:00
bellard
a08beb33cd update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1980 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 17:32:56 +00:00
bellard
fdbb46910a Solaris/SPARC host port (Ben Taylor)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1979 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 17:32:25 +00:00
bellard
43057ab127 use constants for TLB handling (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1978 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 17:15:19 +00:00
bellard
c5d6edc3fc mips config fixes (initial patch by Stefan Weil)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1977 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 16:49:24 +00:00
bellard
52ca8d6af0 -no-fd-bootchk option (Lonnie Mendez)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1976 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 16:03:05 +00:00
bellard
5cbfcd00b0 cocoa monitor fix regarding the handling of dead keys (Joachim Henke)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1975 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 15:53:24 +00:00
bellard
ec3757de32 use C99 64 bit printf format to ease win32 porting
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1974 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 15:50:07 +00:00
bellard
e8445331b6 show real allocated disk image size on Windows (Frediano Ziglio)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1973 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 15:32:10 +00:00
bellard
8f447cc753 gdb stub for win32
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1972 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 15:21:14 +00:00
bellard
eda9b09b1d sh4 fmov et al instructions (amatus)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1971 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 15:02:05 +00:00
pbrook
191f9a93f4 ARM postincrememnt addressing fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1970 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 14:36:07 +00:00
bellard
d1e42c5c1e x86_64 mmx/sse fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1969 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 14:29:34 +00:00
bellard
4bb3973f61 typo in get_reloc_expr()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1968 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 13:41:08 +00:00
bellard
bc1ad2decd MIPS FPU support in linux user emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1967 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 13:37:55 +00:00
bellard
83fcb51548 use glibc syscall (David Woodhouse)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1966 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 13:37:16 +00:00
bellard
5b9053a5ea remove proll
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1965 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:57:01 +00:00
bellard
6ea83fedc8 MIPS FPU support (Marius Goeger)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1964 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:56:19 +00:00
bellard
180b700dc7 clock year fix for sparc (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1963 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:41:34 +00:00
bellard
55e4f6644e FPU fix (Joerg Platte)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1962 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:37:58 +00:00
bellard
d8e3326c8e MMU no fault fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1961 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:37:30 +00:00
bellard
0986ac3be2 use OpenBIOS instead of Proll on sparc (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1960 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 12:36:32 +00:00
bellard
9d0869b630 fixed VBE protected mode calls - added VGA and VBE save restore support (not fully tested) - automatic generation of VBE mode table
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1959 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-14 00:58:54 +00:00
bellard
8fa00e0fec more high resolution VESA modes in -std-vga case - changed video memory size to 8 MB
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1958 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 16:54:27 +00:00
bellard
8454df8b1e support for Bochs VBE GETCAPS call so that -std-vga works again with new VGA BIOSes - added support for modes up to 1600x1200x32 in -std-vga case
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1957 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 16:37:40 +00:00
bellard
99589bdcd1 support for higher resolutions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1956 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 16:35:24 +00:00
bellard
74a14f22b8 increase video memory to 8MB
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1955 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 15:57:21 +00:00
bellard
c66b0d4cf4 avoid stopping QEMU when switching desktops with Ctrl-Alt-x
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1954 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 12:03:53 +00:00
bellard
8785a8ddcc 'invisible wall' patch (Anthony Liguori)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1953 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-13 10:49:12 +00:00
pbrook
79737e4a7d Document new arm-user features.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1952 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-11 16:28:41 +00:00
pbrook
e5fe0c5230 bFLT loader (for uClinux binaries).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1951 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-11 13:32:59 +00:00
pbrook
ac62f715c6 Win32 build fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1950 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-08 21:51:27 +00:00
pbrook
7a6cba611d Disk cache flush support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1949 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-04 11:39:07 +00:00
pbrook
17acfe326c More SCSI commands (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1948 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-03 14:23:34 +00:00
pbrook
9f149aa9c1 SATN fixes (Blue Swirl).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1947 c046a42c-6fe2-441c-8c8c-71466251a162
2006-06-03 14:19:19 +00:00
pbrook
7d8406be69 PCI SCSI HBA emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1946 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-30 01:48:12 +00:00
pbrook
0fc5c15a4f SCSI lun probing fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1945 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-26 21:53:41 +00:00
pbrook
cac782d496 Small read fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1944 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-26 18:08:11 +00:00
pbrook
4be9a500e7 Fix partial transfer bug.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1943 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-26 17:15:13 +00:00
pbrook
7c22dd5216 Fix scsi sector size confusion (Blue Swirl).
Fix short TOC read.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1942 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-26 16:46:55 +00:00
pbrook
0aff66b5c8 Update USB documentation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1941 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-26 00:49:52 +00:00
pbrook
2e5d83bbef Rearrange SCSI disk emulation code.
Add USB mass storage device emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1940 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-25 23:58:51 +00:00
pbrook
e6f3e5e016 OHCI large packet fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1939 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-25 23:37:07 +00:00
bellard
159f366388 ARM undefined instruction execution (Jason Wessel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1938 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 23:06:04 +00:00
bellard
ba9a74dae0 fix wrong bitmasks for CP0_Context and CP0_EntryHi (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1937 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 22:14:43 +00:00
bellard
3d9fb9fefe cosmetics (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1936 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 22:13:29 +00:00
bellard
42fe404458 dump all mips insn (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1935 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 22:05:04 +00:00
bellard
9d05095e5f mips cleanup (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1934 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 22:03:52 +00:00
bellard
ea4e754f5a PPC Breakpoints for gdb-stub (Jason Wessel)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1933 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 21:50:20 +00:00
bellard
cae41b10a4 fix missing type declarations (Joachim Henke)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1932 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 21:25:04 +00:00
pbrook
6106487019 Fix USB root hub hotplugging.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1931 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 17:17:06 +00:00
pbrook
6cb7ee859a Only use /dev/shm hack when kqemu is enabled.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1930 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-22 14:10:48 +00:00
pbrook
e4d165c24b Don't clear DMA status register when loading address.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1929 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-21 22:20:03 +00:00
pbrook
0d92ed3022 OHCI USB host emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1928 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-21 16:30:15 +00:00
pbrook
6650ee6d33 Use lookup table for PCI class descriptions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1927 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-21 13:45:09 +00:00
pbrook
db59203d10 ESP DMA fix.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1926 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-21 12:46:31 +00:00
bellard
1c46d7139a clear screen when changing graphic mode in Cirrus VGA BIOS (aka win2k mode change bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1925 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 21:03:52 +00:00
bellard
f815fa45da ne2000 buffer fulness fix (Han Zhu)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1924 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 18:41:52 +00:00
bellard
3512779a88 support for all VNC pixel formats
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1923 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 18:11:49 +00:00
pbrook
5c3ff3a7be Avoid compiler warning.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1922 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 13:44:07 +00:00
pbrook
0cb3fb1e30 Add doc, html, dvi and .PHONY Makefile targets.
Add resulting files to .cvsignore.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1921 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 12:07:53 +00:00
pbrook
c59372208a Teach usermode emulation how to lie about uname -r.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1920 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-14 11:30:38 +00:00
pbrook
00a9bf191b Update ARM board documentation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1919 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-13 16:55:46 +00:00
pbrook
b9dea4fbc6 Move all: target first.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1918 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-13 16:54:03 +00:00
pbrook
214feb514b Add dependency on config.h and config-host.h.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1917 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-13 16:30:17 +00:00
pbrook
502a53952d Rearrange PCI host emulation code.
Add ARM PCI emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1916 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-13 16:11:23 +00:00
pbrook
4aa4253115 Allow parallel make.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1915 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-13 13:55:08 +00:00
bellard
5627148a19 BGR_FORMAT fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1914 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-11 21:54:44 +00:00
bellard
1fc2244d87 mips bios loading fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1913 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-11 21:15:08 +00:00
bellard
d3079cd241 bgr32 pixel format support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1912 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-10 22:17:36 +00:00
bellard
38f3e7c2f5 suppressed unaligned accesses
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1911 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-10 19:21:58 +00:00
bellard
73540ca962 alignment fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1910 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-08 13:38:46 +00:00
pbrook
064aae138b Test if compiler works instead of checking if binary exists.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1909 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-08 00:51:44 +00:00
bellard
699e4642a9 win32 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1908 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-07 18:06:27 +00:00
bellard
64866c3d5c more keycodes - hexa keycodes - keycode completion
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1907 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-07 18:03:31 +00:00
bellard
294e863721 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1906 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-06 14:23:06 +00:00
bellard
67f3656039 patch in bLength for hub descriptor (Lonnie Mendez)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1905 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-05 20:05:35 +00:00
bellard
7ef4da1c3a typo
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1904 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-05 20:03:45 +00:00
bellard
6583391f0d PCI irq mapping fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1903 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-03 23:13:13 +00:00
bellard
6515b20370 ACPI support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1902 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-03 22:02:44 +00:00
bellard
107654552c more correct e820 ranges for ACPI compatibility
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1901 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-03 21:24:55 +00:00
bellard
ceb5caaf18 removed ssize_t for win32 compatibility
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1900 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-03 21:18:59 +00:00
bellard
c904d61f78 UDP broadcast translation error (Mark Jonckheere)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1899 c046a42c-6fe2-441c-8c8c-71466251a162
2006-05-03 20:53:46 +00:00
265 changed files with 50499 additions and 15111 deletions

View File

@@ -1,29 +1,45 @@
arm-user
arm-linux-user
arm-softmmu
armeb-user
armeb-linux-user
config-host.*
dyngen
i386
i386-softmmu
i386-user
i386-darwin-user
i386-linux-user
ppc-softmmu
ppc64-softmmu
ppc-user
ppc-darwin-user
ppc-linux-user
qemu-doc.html
qemu-tech.html
qemu-doc.info
qemu-tech.info
qemu.1
qemu.pod
qemu-img.1
qemu-img.pod
sparc-user
sparc-linux-user
qemu-img
sparc-softmmu
x86_64-softmmu
sparc64-user
sparc64-linux-user
sparc64-softmmu
mips-softmmu
mipsel-softmmu
mips-user
mipsel-user
sh4-user
mips-linux-user
mipsel-linux-user
m68k-linux-user
.gdbinit
sh4-linux-user
sh4-softmmu
*.aux
*.cp
*.dvi
*.fn
*.ky
*.log
*.pg
*.toc
*.tp
*.vr

View File

@@ -1,3 +1,40 @@
version 0.9.0:
- Support for relative paths in backing files for disk images
- Async file I/O API
- New qcow2 disk image format
- Support of multiple VM snapshots
- Linux: specific host CDROM and floppy support
- SMM support
- Moved PCI init, MP table init and ACPI table init to Bochs BIOS
- Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
- MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
- Darwin userspace emulation (Pierre d'Herbemont)
- m68k user support (Paul Brook)
- several x86 and x86_64 emulation fixes
- Mouse relative offset VNC extension (Anthony Liguori)
- PXE boot support (Anthony Liguori)
- '-daemonize' option (Anthony Liguori)
version 0.8.2:
- ACPI support
- PC VGA BIOS fixes
- switch to OpenBios for SPARC targets (Blue Swirl)
- VNC server fixes
- MIPS FPU support (Marius Groeger)
- Solaris/SPARC host support (Ben Taylor)
- PPC breakpoints and single stepping (Jason Wessel)
- USB updates (Paul Brook)
- UDP/TCP/telnet character devices (Jason Wessel)
- Windows sparse file support (Frediano Ziglio)
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
- PCNET NIC support (Antony T Curtis)
- Support for variable frequency host CPUs
- Workaround for win32 SMP hosts
- Support for AMD Flash memories (Jocelyn Mayer)
- Audio capture to WAV files support (malc)
version 0.8.1:
- USB tablet support (Brad Campbell, Anthony Liguori)

15
LICENSE
View File

@@ -1,11 +1,14 @@
The following points clarify the QEMU licenses:
The following points clarify the QEMU license:
1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
system emulator are released under the GNU Lesser General Public
License.
1) QEMU as a whole is released under the GNU General Public License
2) The Linux user mode QEMU emulator is released under the GNU General
Public License.
2) Parts of QEMU have specific licenses which are compatible with the
GNU General Public License. Hence each source file contains its own
licensing information.
In particular, the QEMU virtual CPU core library (libqemu.a) is
released under the GNU Lesser General Public License. Many hardware
device emulation sources are released under the BSD license.
3) QEMU is a trademark of Fabrice Bellard.

View File

@@ -1,15 +1,22 @@
# Makefile for QEMU.
include config-host.mak
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
speed test test2 html dvi info
BASE_CFLAGS=
BASE_LDFLAGS=
BASE_CFLAGS += $(OS_CFLAGS)
ifeq ($(ARCH),sparc)
BASE_CFLAGS += -mcpu=ultrasparc
endif
LDFLAGS=-g
CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TOOLS=qemu-img$(EXESUF)
ifdef CONFIG_STATIC
LDFLAGS+=-static
BASE_LDFLAGS += -static
endif
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
@@ -17,16 +24,26 @@ else
DOCS=
endif
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
LIBS+=-lrt
endif
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 block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
all: $(TOOLS) $(DOCS) recurse-all
subdir-%: dyngen$(EXESUF)
$(MAKE) -C $(subst subdir-,,$@) all
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.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 block-qcow2.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
clean:
# avoid old build problems by removing potentially incorrect old files
@@ -39,6 +56,7 @@ clean:
distclean: clean
rm -f config-host.mak config-host.h $(DOCS)
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
@@ -60,7 +78,8 @@ install: all $(if $(BUILD_DOCS),install-doc)
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
mkdir -p "$(DESTDIR)$(datadir)"
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x proll.elf linux_boot.bin; do \
video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
pxe-rtl8139.bin pxe-pcnet.bin; do \
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
done
ifndef CONFIG_WIN32
@@ -103,7 +122,14 @@ qemu-img.1: qemu-img.texi
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
FILE=qemu-$(shell cat VERSION)
info: qemu-doc.info qemu-tech.info
dvi: qemu-doc.dvi qemu-tech.dvi
html: qemu-doc.html qemu-tech.html
VERSION ?= $(shell cat VERSION)
FILE = qemu-$(VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
@@ -135,8 +161,11 @@ tarbin:
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/proll.elf \
$(datadir)/openbios-sparc32 \
$(datadir)/linux_boot.bin \
$(datadir)/pxe-ne2k_pci.bin \
$(datadir)/pxe-rtl8139.bin \
$(datadir)/pxe-pcnet.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )

View File

@@ -12,14 +12,18 @@ TARGET_BASE_ARCH:=sparc
endif
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_USER_ONLY
VPATH+=:$(SRC_PATH)/linux-user
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
ifdef CONFIG_DARWIN_USER
VPATH+=:$(SRC_PATH)/darwin-user
CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
endif
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
ifdef CONFIG_LINUX_USER
VPATH+=:$(SRC_PATH)/linux-user
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
BASE_CFLAGS=
BASE_LDFLAGS=
#CFLAGS+=-Werror
LDFLAGS=-g
LIBS=
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen$(EXESUF)
@@ -30,6 +34,11 @@ ifeq ($(TARGET_ARCH),arm)
TARGET_ARCH2=armeb
endif
endif
ifeq ($(TARGET_ARCH),sh4)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=sh4eb
endif
endif
ifeq ($(TARGET_ARCH),mips)
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=mipsel
@@ -57,18 +66,20 @@ endif
endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
LDFLAGS+=-static
BASE_LDFLAGS+=-static
endif
# We require -O2 to avoid the stack setup prologue in EXIT_TB
OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
HELPER_CFLAGS+=-fomit-frame-pointer
OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0 -fno-gcse
else
OP_CFLAGS+= -malign-functions=0
endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
@@ -76,69 +87,80 @@ ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
ifdef CONFIG_LINUX_USER
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
BASE_LDFLAGS+=-Wl,-shared
endif
endif
endif
ifeq ($(ARCH),x86_64)
OP_CFLAGS=$(CFLAGS) -falign-functions=0
LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc)
CFLAGS+= -D__powerpc__
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
CPPFLAGS+= -D__powerpc__
ifdef CONFIG_LINUX_USER
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),sparc)
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
ifeq ($(CONFIG_SOLARIS),yes)
BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
BASE_LDFLAGS+=-m32
OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
else
BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
BASE_LDFLAGS+=-m32
OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
endif
endif
ifeq ($(ARCH),sparc64)
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m64
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
BASE_LDFLAGS+=-m64
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -fno-delayed-branch -ffixed-i0
endif
ifeq ($(ARCH),alpha)
# -msmall-data is not used because we want two-instruction relocations
# for the constant constructions
OP_CFLAGS=-Wall -O2 -g
# -msmall-data is not used for OP_CFLAGS because we want two-instruction
# relocations for the constant constructions
# Ensure there's only a single GP
CFLAGS += -msmall-data
LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
BASE_CFLAGS+=-msmall-data
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ia64)
CFLAGS += -mno-sdata
OP_CFLAGS=$(CFLAGS)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
BASE_CFLAGS+=-mno-sdata
OP_CFLAGS+=-mno-sdata
BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),m68k)
OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
LDFLAGS+=-Wl,-T,m68k.ld
OP_CFLAGS+=-fomit-frame-pointer
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),mips)
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(HAVE_GCC3_OPTIONS),yes)
@@ -147,13 +169,19 @@ OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
ifeq ($(CONFIG_DARWIN),yes)
OP_CFLAGS+= -mdynamic-no-pic
LIBS+=-lmx
endif
ifdef CONFIG_DARWIN_USER
# Leave some space for the regular program loading zone
BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
endif
OP_CFLAGS+=$(OS_CFLAGS)
#########################################################
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS+=-lm
ifndef CONFIG_USER_ONLY
LIBS+=-lz
@@ -167,11 +195,17 @@ endif
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
BASE_LDFLAGS+=-p
main.o: BASE_CFLAGS+=-p
endif
ifdef CONFIG_LINUX_USER
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
elfload.o linuxload.o
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
@@ -180,6 +214,15 @@ OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
endif
ifeq ($(TARGET_ARCH), m68k)
OBJS+= m68k-sim.o m68k-semi.o
endif
endif #CONFIG_LINUX_USER
ifdef CONFIG_DARWIN_USER
OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
endif
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
@@ -191,7 +234,7 @@ LIBOBJS+=fpu/softfloat.o
else
LIBOBJS+=fpu/softfloat-native.o
endif
DEFINES+=-I$(SRC_PATH)/fpu
CPPFLAGS+=-I$(SRC_PATH)/fpu
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
@@ -224,6 +267,10 @@ ifeq ($(TARGET_BASE_ARCH), sh4)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), m68k)
LIBOBJS+= helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -264,7 +311,7 @@ endif
all: $(PROGS)
$(QEMU_USER): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
$(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ $(LIBS)
ifeq ($(ARCH),alpha)
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
# the address space (31 bit so sign extending doesn't matter)
@@ -272,8 +319,10 @@ ifeq ($(ARCH),alpha)
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 loader.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
VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o
VL_OBJS+=cutils.o
VL_OBJS+=block.o block-raw.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 block-qcow2.o
ifdef CONFIG_WIN32
VL_OBJS+=tap-win32.o
endif
@@ -299,49 +348,61 @@ LIBS += -lole32 -ldxguid
endif
ifdef CONFIG_FMOD
AUDIODRV += fmodaudio.o
audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
LIBS += $(CONFIG_FMOD_LIB)
endif
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
# USB layer
VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
# PCI network cards
VL_OBJS+= ne2000.o rtl8139.o
VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
DEFINES += -DHAS_AUDIO
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o
VL_OBJS+= usb-uhci.o smbus_eeprom.o
CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o pckbd.o ps2.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 heathrow_pic.o mixeng.o
DEFINES += -DHAS_AUDIO
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o
VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
else
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
VL_OBJS+= cs4231.o
endif
endif
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
VL_OBJS+= versatile_pci.o
VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
VL_OBJS+= arm-semi.o
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
@@ -350,7 +411,7 @@ ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
VL_OBJS+=sdl.o x_keymap.o
endif
VL_OBJS+=vnc.o
ifdef CONFIG_COCOA
@@ -361,7 +422,7 @@ COCOA_LIBS+=-framework CoreAudio
endif
endif
ifdef CONFIG_SLIRP
DEFINES+=-I$(SRC_PATH)/slirp
CPPFLAGS+=-I$(SRC_PATH)/slirp
SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
@@ -379,12 +440,12 @@ endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
VL_LIBS=-lutil
VL_LIBS=-lutil -lrt
endif
endif
endif
ifdef TARGET_GPROF
vl.o: CFLAGS+=-p
vl.o: BASE_CFLAGS+=-p
VL_LDFLAGS+=-p
endif
@@ -392,6 +453,11 @@ ifeq ($(ARCH),ia64)
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifeq ($(ARCH),sparc64)
VL_LDFLAGS+=-m64
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
endif
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
endif
@@ -400,22 +466,22 @@ $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
cocoa.o: cocoa.m
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
sdl.o: sdl.c keymaps.c sdl_keysym.h
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
vldepend: $(VL_OBJS:.o=.c)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
# libqemu
@@ -439,10 +505,26 @@ gen-op.h: op.o $(DYNGEN)
$(DYNGEN) -g -o $@ $<
op.o: op.c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
$(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
# HELPER_CFLAGS is used for all the code compiled with static register
# variables
ifeq ($(TARGET_BASE_ARCH), i386)
# XXX: rename helper.c to op_helper.c
helper.o: helper.c
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
else
op_helper.o: op_helper.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
endif
cpu-exec.o: cpu-exec.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
signal.o: signal.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
ifeq ($(TARGET_BASE_ARCH), i386)
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
@@ -465,7 +547,7 @@ translate.o: translate.c translate_init.c
endif
ifeq ($(TARGET_ARCH), mips)
op.o: op.c op_template.c op_mem.c
op.o: op.c op_template.c fop_template.c op_mem.c
op_helper.o: op_helper_mem.c
endif
@@ -481,11 +563,13 @@ sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
tc58128.o: tc58128.c
endif
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
%.o: %.S
$(CC) $(DEFINES) -c -o $@ $<
$(CC) $(CPPFLAGS) -c -o $@ $<
clean:
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o

View File

@@ -1,16 +0,0 @@
Information about the various packages used to build the current qemu
x86 binary distribution:
* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
was used to get most of the binary packages.
* wine-20020411 tarball
./configure --prefix=/usr/local/wine-i386
All exe and libs were stripped. Some compile time tools and the
includes were deleted.
* ldconfig was launched to build the library links:
qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache

10
TODO
View File

@@ -1,24 +1,20 @@
short term:
----------
- support variable tsc freq
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
- support variable tsc freq
- USB host async
- IDE async
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
@@ -31,12 +27,10 @@ short term:
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- fix arm fpu rounding (at least for float->integer conversions)
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
linux-user specific:

View File

@@ -1 +1 @@
0.8.1
0.9.0

458
arm-semi.c Normal file
View File

@@ -0,0 +1,458 @@
/*
* Arm "Angel" semihosting syscalls
*
* Copyright (c) 2005, 2007 CodeSourcery.
* Written by Paul Brook.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "cpu.h"
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
#else
#include "vl.h"
#endif
#define SYS_OPEN 0x01
#define SYS_CLOSE 0x02
#define SYS_WRITEC 0x03
#define SYS_WRITE0 0x04
#define SYS_WRITE 0x05
#define SYS_READ 0x06
#define SYS_READC 0x07
#define SYS_ISTTY 0x09
#define SYS_SEEK 0x0a
#define SYS_FLEN 0x0c
#define SYS_TMPNAM 0x0d
#define SYS_REMOVE 0x0e
#define SYS_RENAME 0x0f
#define SYS_CLOCK 0x10
#define SYS_TIME 0x11
#define SYS_SYSTEM 0x12
#define SYS_ERRNO 0x13
#define SYS_GET_CMDLINE 0x15
#define SYS_HEAPINFO 0x16
#define SYS_EXIT 0x18
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define GDB_O_RDONLY 0x000
#define GDB_O_WRONLY 0x001
#define GDB_O_RDWR 0x002
#define GDB_O_APPEND 0x008
#define GDB_O_CREAT 0x200
#define GDB_O_TRUNC 0x400
#define GDB_O_BINARY 0
static int gdb_open_modeflags[12] = {
GDB_O_RDONLY,
GDB_O_RDONLY | GDB_O_BINARY,
GDB_O_RDWR,
GDB_O_RDWR | GDB_O_BINARY,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
};
static int open_modeflags[12] = {
O_RDONLY,
O_RDONLY | O_BINARY,
O_RDWR,
O_RDWR | O_BINARY,
O_WRONLY | O_CREAT | O_TRUNC,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
O_RDWR | O_CREAT | O_TRUNC,
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
O_WRONLY | O_CREAT | O_APPEND,
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
O_RDWR | O_CREAT | O_APPEND,
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
#ifdef CONFIG_USER_ONLY
static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
{
if (code == (uint32_t)-1)
ts->swi_errno = errno;
return code;
}
#else
static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
{
return code;
}
static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
{
uint32_t val;
cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
return tswap32(val);
}
static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
{
uint8_t val;
cpu_memory_rw_debug(env, addr, &val, 1, 0);
return val;
}
#define tget32(p) softmmu_tget32(env, p)
#define tget8(p) softmmu_tget8(env, p)
static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
int copy)
{
char *p;
/* TODO: Make this something that isn't fixed size. */
p = malloc(len);
if (copy)
cpu_memory_rw_debug(env, addr, p, len, 0);
return p;
}
#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
{
char *p;
char *s;
uint8_t c;
/* TODO: Make this something that isn't fixed size. */
s = p = malloc(1024);
do {
cpu_memory_rw_debug(env, addr, &c, 1, 0);
addr++;
*(p++) = c;
} while (c);
return s;
}
#define lock_user_string(p) softmmu_lock_user_string(env, p)
static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
target_ulong len)
{
if (len)
cpu_memory_rw_debug(env, addr, p, len, 1);
free(p);
}
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
#endif
static target_ulong arm_semi_syscall_len;
static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
{
#ifdef CONFIG_USER_ONLY
TaskState *ts = env->opaque;
#endif
if (ret == (target_ulong)-1) {
#ifdef CONFIG_USER_ONLY
ts->swi_errno = err;
#endif
env->regs[0] = ret;
} else {
/* Fixup syscalls that use nonstardard return conventions. */
switch (env->regs[0]) {
case SYS_WRITE:
case SYS_READ:
env->regs[0] = arm_semi_syscall_len - ret;
break;
case SYS_SEEK:
env->regs[0] = 0;
break;
default:
env->regs[0] = ret;
break;
}
}
}
#define ARG(n) tget32(args + (n) * 4)
#define SET_ARG(n, val) tput32(args + (n) * 4,val)
uint32_t do_arm_semihosting(CPUState *env)
{
target_ulong args;
char * s;
int nr;
uint32_t ret;
uint32_t len;
#ifdef CONFIG_USER_ONLY
TaskState *ts = env->opaque;
#else
CPUState *ts = env;
#endif
nr = env->regs[0];
args = env->regs[1];
switch (nr) {
case SYS_OPEN:
s = lock_user_string(ARG(0));
if (ARG(1) >= 12)
return (uint32_t)-1;
if (strcmp(s, ":tt") == 0) {
if (ARG(1) < 4)
return STDIN_FILENO;
else
return STDOUT_FILENO;
}
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2),
gdb_open_modeflags[ARG(1)]);
return env->regs[0];
} else {
ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
}
unlock_user(s, ARG(0), 0);
return ret;
case SYS_CLOSE:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
return env->regs[0];
} else {
return set_swi_errno(ts, close(ARG(0)));
}
case SYS_WRITEC:
{
char c = tget8(args);
/* Write to debug console. stderr is near enough. */
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
return env->regs[0];
} else {
return write(STDERR_FILENO, &c, 1);
}
}
case SYS_WRITE0:
s = lock_user_string(args);
len = strlen(s);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
ret = env->regs[0];
} else {
ret = write(STDERR_FILENO, s, len);
}
unlock_user(s, args, 0);
return ret;
case SYS_WRITE:
len = ARG(2);
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
return env->regs[0];
} else {
s = lock_user(ARG(1), len, 1);
ret = set_swi_errno(ts, write(ARG(0), s, len));
unlock_user(s, ARG(1), 0);
if (ret == (uint32_t)-1)
return -1;
return len - ret;
}
case SYS_READ:
len = ARG(2);
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
return env->regs[0];
} else {
s = lock_user(ARG(1), len, 0);
do
ret = set_swi_errno(ts, read(ARG(0), s, len));
while (ret == -1 && errno == EINTR);
unlock_user(s, ARG(1), len);
if (ret == (uint32_t)-1)
return -1;
return len - ret;
}
case SYS_READC:
/* XXX: Read from debug cosole. Not implemented. */
return 0;
case SYS_ISTTY:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
return env->regs[0];
} else {
return isatty(ARG(0));
}
case SYS_SEEK:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1));
return env->regs[0];
} else {
ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
if (ret == (uint32_t)-1)
return -1;
return 0;
}
case SYS_FLEN:
if (use_gdb_syscalls()) {
/* TODO: Use stat syscall. */
return -1;
} else {
struct stat buf;
ret = set_swi_errno(ts, fstat(ARG(0), &buf));
if (ret == (uint32_t)-1)
return -1;
return buf.st_size;
}
case SYS_TMPNAM:
/* XXX: Not implemented. */
return -1;
case SYS_REMOVE:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1));
ret = env->regs[0];
} else {
s = lock_user_string(ARG(0));
ret = set_swi_errno(ts, remove(s));
unlock_user(s, ARG(0), 0);
}
return ret;
case SYS_RENAME:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
return env->regs[0];
} else {
char *s2;
s = lock_user_string(ARG(0));
s2 = lock_user_string(ARG(2));
ret = set_swi_errno(ts, rename(s, s2));
unlock_user(s2, ARG(2), 0);
unlock_user(s, ARG(0), 0);
return ret;
}
case SYS_CLOCK:
return clock() / (CLOCKS_PER_SEC / 100);
case SYS_TIME:
return set_swi_errno(ts, time(NULL));
case SYS_SYSTEM:
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1));
return env->regs[0];
} else {
s = lock_user_string(ARG(0));
ret = set_swi_errno(ts, system(s));
unlock_user(s, ARG(0), 0);
}
case SYS_ERRNO:
#ifdef CONFIG_USER_ONLY
return ts->swi_errno;
#else
return 0;
#endif
case SYS_GET_CMDLINE:
#ifdef CONFIG_USER_ONLY
/* Build a commandline from the original argv. */
{
char **arg = ts->info->host_argv;
int len = ARG(1);
/* lock the buffer on the ARM side */
char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
s = cmdline_buffer;
while (*arg && len > 2) {
int n = strlen(*arg);
if (s != cmdline_buffer) {
*(s++) = ' ';
len--;
}
if (n >= len)
n = len - 1;
memcpy(s, *arg, n);
s += n;
len -= n;
arg++;
}
/* Null terminate the string. */
*s = 0;
len = s - cmdline_buffer;
/* Unlock the buffer on the ARM side. */
unlock_user(cmdline_buffer, ARG(0), len);
/* Adjust the commandline length argument. */
SET_ARG(1, len);
/* Return success if commandline fit into buffer. */
return *arg ? -1 : 0;
}
#else
return -1;
#endif
case SYS_HEAPINFO:
{
uint32_t *ptr;
uint32_t limit;
#ifdef CONFIG_USER_ONLY
/* Some C libraries assume the heap immediately follows .bss, so
allocate it using sbrk. */
if (!ts->heap_limit) {
long ret;
ts->heap_base = do_brk(0);
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
/* Try a big heap, and reduce the size if that fails. */
for (;;) {
ret = do_brk(limit);
if (ret != -1)
break;
limit = (ts->heap_base >> 1) + (limit >> 1);
}
ts->heap_limit = limit;
}
ptr = lock_user(ARG(0), 16, 0);
ptr[0] = tswap32(ts->heap_base);
ptr[1] = tswap32(ts->heap_limit);
ptr[2] = tswap32(ts->stack_base);
ptr[3] = tswap32(0); /* Stack limit. */
unlock_user(ptr, ARG(0), 16);
#else
limit = ram_size;
ptr = lock_user(ARG(0), 16, 0);
/* TODO: Make this use the limit of the loaded application. */
ptr[0] = tswap32(limit / 2);
ptr[1] = tswap32(limit);
ptr[2] = tswap32(limit); /* Stack base */
ptr[3] = tswap32(0); /* Stack limit. */
unlock_user(ptr, ARG(0), 16);
#endif
return 0;
}
case SYS_EXIT:
exit(0);
default:
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
cpu_dump_state(env, stderr, fprintf, 0);
abort();
}
}

25
arm.ld
View File

@@ -53,6 +53,10 @@ SECTIONS
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
__exidx_end = .;
.reginfo : { *(.reginfo) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
@@ -63,7 +67,28 @@ SECTIONS
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.data1 : { *(.data1) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
*(.ctors)

View File

@@ -61,8 +61,8 @@ static struct {
.size_in_usec_in = 1,
.size_in_usec_out = 1,
#endif
.pcm_name_out = "hw:0,0",
.pcm_name_in = "hw:0,0",
.pcm_name_out = "default",
.pcm_name_in = "default",
#ifdef HIGH_LATENCY
.buffer_size_in = 400000,
.period_size_in = 400000 / 4,
@@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw)
}
}
mixeng_clear (src, written);
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
@@ -663,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
@@ -752,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);

View File

@@ -29,6 +29,7 @@
/* #define DEBUG_PLIVE */
/* #define DEBUG_LIVE */
/* #define DEBUG_OUT */
/* #define DEBUG_CAPTURE */
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
@@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int cond)
if (cond) {
static int shown;
AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
if (!shown) {
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
@@ -509,14 +510,28 @@ static void audio_print_settings (audsettings_t *as)
AUD_log (NULL, "invalid(%d)", as->fmt);
break;
}
AUD_log (NULL, " endianness=");
switch (as->endianness) {
case 0:
AUD_log (NULL, "little");
break;
case 1:
AUD_log (NULL, "big");
break;
default:
AUD_log (NULL, "invalid");
break;
}
AUD_log (NULL, "\n");
}
static int audio_validate_settigs (audsettings_t *as)
static int audio_validate_settings (audsettings_t *as)
{
int invalid;
invalid = as->nchannels != 1 && as->nchannels != 2;
invalid |= as->endianness != 0 && as->endianness != 1;
switch (as->fmt) {
case AUD_FMT_S8:
@@ -530,11 +545,7 @@ static int audio_validate_settigs (audsettings_t *as)
}
invalid |= as->freq <= 0;
if (invalid) {
return -1;
}
return 0;
return invalid ? -1 : 0;
}
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
@@ -556,14 +567,11 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
return info->freq == as->freq
&& info->nchannels == as->nchannels
&& info->sign == sign
&& info->bits == bits;
&& info->bits == bits
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_init_info (
struct audio_pcm_info *info,
audsettings_t *as,
int swap_endian
)
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
{
int bits = 8, sign = 0;
@@ -587,7 +595,7 @@ void audio_pcm_init_info (
info->shift = (as->nchannels == 2) + (bits == 16);
info->align = (1 << info->shift) - 1;
info->bytes_per_second = info->freq << info->shift;
info->swap_endian = swap_endian;
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
@@ -597,11 +605,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
}
if (info->sign) {
memset (buf, len << info->shift, 0x00);
memset (buf, 0x00, len << info->shift);
}
else {
if (info->bits == 8) {
memset (buf, len << info->shift, 0x80);
memset (buf, 0x80, len << info->shift);
}
else {
int i;
@@ -609,7 +617,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
int shift = info->nchannels - 1;
short s = INT16_MAX;
if (info->swap_endian) {
if (info->swap_endianness) {
s = bswap16 (s);
}
@@ -620,6 +628,143 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
}
}
/*
* Capture
*/
static void noop_conv (st_sample_t *dst, const void *src,
int samples, volume_t *vol)
{
(void) src;
(void) dst;
(void) samples;
(void) vol;
}
static CaptureVoiceOut *audio_pcm_capture_find_specific (
AudioState *s,
audsettings_t *as
)
{
CaptureVoiceOut *cap;
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
if (audio_pcm_info_eq (&cap->hw.info, as)) {
return cap;
}
}
return NULL;
}
static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
{
struct capture_callback *cb;
#ifdef DEBUG_CAPTURE
dolog ("notification %d sent\n", cmd);
#endif
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.notify (cb->opaque, cmd);
}
}
static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
{
if (cap->hw.enabled != enabled) {
audcnotification_e cmd;
cap->hw.enabled = enabled;
cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
audio_notify_capture (cap, cmd);
}
}
static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
{
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
int enabled = 0;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (sw->active) {
enabled = 1;
break;
}
}
audio_capture_maybe_changed (cap, enabled);
}
static void audio_detach_capture (HWVoiceOut *hw)
{
SWVoiceCap *sc = hw->cap_head.lh_first;
while (sc) {
SWVoiceCap *sc1 = sc->entries.le_next;
SWVoiceOut *sw = &sc->sw;
CaptureVoiceOut *cap = sc->cap;
int was_active = sw->active;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
if (was_active) {
/* We have removed soft voice from the capture:
this might have changed the overall status of the capture
since this might have been the only active voice */
audio_recalc_and_notify_capture (cap);
}
sc = sc1;
}
}
static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
{
CaptureVoiceOut *cap;
audio_detach_capture (hw);
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
SWVoiceCap *sc;
SWVoiceOut *sw;
HWVoiceOut *hw_cap = &cap->hw;
sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
if (!sc) {
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
sizeof (*sc));
return -1;
}
sc->cap = cap;
sw = &sc->sw;
sw->hw = hw_cap;
sw->info = hw->info;
sw->empty = 1;
sw->active = hw->enabled;
sw->conv = noop_conv;
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
if (!sw->rate) {
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
qemu_free (sw);
return -1;
}
LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
#ifdef DEBUG_CAPTURE
asprintf (&sw->name, "for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("Added %s active = %d\n", sw->name, sw->active);
#endif
if (sw->active) {
audio_capture_maybe_changed (cap, 1);
}
}
return 0;
}
/*
* Hard voice (capture)
*/
@@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
}
if (live == hwsamples) {
#ifdef DEBUG_OUT
dolog ("%s is full %d\n", sw->name, live);
#endif
return 0;
}
@@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw = sw->hw;
if (sw->active != on) {
SWVoiceOut *temp_sw;
SWVoiceCap *sc;
if (on) {
int total;
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
}
if (sw->empty) {
total = 0;
}
}
else {
if (hw->enabled) {
@@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw->pending_disable = nb_active == 1;
}
}
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = hw->enabled;
if (hw->enabled) {
audio_capture_maybe_changed (sc->cap, 1);
}
}
sw->active = on;
}
}
@@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *sw)
}
ldebug (
"%s: get_avail live %d ret %lld\n",
"%s: get_avail live %d ret %" PRId64 "\n",
SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
);
@@ -1023,7 +1173,7 @@ static int audio_get_free (SWVoiceOut *sw)
dead = sw->hw->samples - live;
#ifdef DEBUG_OUT
dolog ("%s: get_free live %d dead %d ret %lld\n",
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
SW_NAME (sw),
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
#endif
@@ -1031,6 +1181,43 @@ static int audio_get_free (SWVoiceOut *sw)
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
}
static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
{
int n;
if (hw->enabled) {
SWVoiceCap *sc;
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
SWVoiceOut *sw = &sc->sw;
int rpos2 = rpos;
n = samples;
while (n) {
int till_end_of_hw = hw->samples - rpos2;
int to_write = audio_MIN (till_end_of_hw, n);
int bytes = to_write << hw->info.shift;
int written;
sw->buf = hw->mix_buf + rpos2;
written = audio_pcm_sw_write (sw, NULL, bytes);
if (written - bytes) {
dolog ("Could not mix %d bytes into a capture "
"buffer, mixed %d\n",
bytes, written);
break;
}
n -= to_write;
rpos2 = (rpos2 + to_write) % hw->samples;
}
}
}
n = audio_MIN (samples, hw->samples - rpos);
mixeng_clear (hw->mix_buf + rpos, n);
mixeng_clear (hw->mix_buf, samples - n);
}
static void audio_run_out (AudioState *s)
{
HWVoiceOut *hw = NULL;
@@ -1038,7 +1225,7 @@ static void audio_run_out (AudioState *s)
while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
int played;
int live, free, nb_live, cleanup_required;
int live, free, nb_live, cleanup_required, prev_rpos;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!nb_live) {
@@ -1051,12 +1238,17 @@ static void audio_run_out (AudioState *s)
}
if (hw->pending_disable && !nb_live) {
SWVoiceCap *sc;
#ifdef DEBUG_OUT
dolog ("Disabling voice\n");
#endif
hw->enabled = 0;
hw->pending_disable = 0;
hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = 0;
audio_recalc_and_notify_capture (sc->cap);
}
continue;
}
@@ -1072,6 +1264,7 @@ static void audio_run_out (AudioState *s)
continue;
}
prev_rpos = hw->rpos;
played = hw->pcm_ops->run_out (hw);
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
@@ -1085,6 +1278,7 @@ static void audio_run_out (AudioState *s)
if (played) {
hw->ts_helper += played;
audio_capture_mix_and_clear (hw, prev_rpos, played);
}
cleanup_required = 0;
@@ -1115,15 +1309,18 @@ static void audio_run_out (AudioState *s)
}
if (cleanup_required) {
restart:
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
SWVoiceOut *sw1;
sw = hw->sw_head.lh_first;
while (sw) {
sw1 = sw->entries.le_next;
if (!sw->active && !sw->callback.fn) {
#ifdef DEBUG_PLIVE
dolog ("Finishing with old voice\n");
#endif
audio_close_out (s, sw);
goto restart; /* play it safe */
}
sw = sw1;
}
}
}
@@ -1158,12 +1355,60 @@ static void audio_run_in (AudioState *s)
}
}
static void audio_run_capture (AudioState *s)
{
CaptureVoiceOut *cap;
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
int live, rpos, captured;
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
captured = live = audio_pcm_hw_get_live_out (hw);
rpos = hw->rpos;
while (live) {
int left = hw->samples - rpos;
int to_capture = audio_MIN (live, left);
st_sample_t *src;
struct capture_callback *cb;
src = hw->mix_buf + rpos;
hw->clip (cap->buf, src, to_capture);
mixeng_clear (src, to_capture);
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.capture (cb->opaque, cap->buf,
to_capture << hw->info.shift);
}
rpos = (rpos + to_capture) % hw->samples;
live -= to_capture;
}
hw->rpos = rpos;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (!sw->active && sw->empty) {
continue;
}
if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
captured, sw->total_hw_samples_mixed);
captured = sw->total_hw_samples_mixed;
}
sw->total_hw_samples_mixed -= captured;
sw->empty = sw->total_hw_samples_mixed == 0;
}
}
}
static void audio_timer (void *opaque)
{
AudioState *s = opaque;
audio_run_out (s);
audio_run_in (s);
audio_run_capture (s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
@@ -1327,8 +1572,19 @@ static void audio_atexit (void)
HWVoiceIn *hwi = NULL;
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
SWVoiceCap *sc;
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
hwo->pcm_ops->fini_out (hwo);
for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
CaptureVoiceOut *cap = sc->cap;
struct capture_callback *cb;
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.destroy (cb->opaque);
}
}
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
@@ -1383,6 +1639,7 @@ AudioState *AUD_init (void)
LIST_INIT (&s->hw_head_out);
LIST_INIT (&s->hw_head_in);
LIST_INIT (&s->cap_head);
atexit (audio_atexit);
s->ts = qemu_new_timer (vm_clock, audio_timer, s);
@@ -1479,3 +1736,136 @@ AudioState *AUD_init (void)
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
return s;
}
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *cb_opaque
)
{
CaptureVoiceOut *cap;
struct capture_callback *cb;
if (!s) {
/* XXX suppress */
s = &glob_audio_state;
}
if (audio_validate_settings (as)) {
dolog ("Invalid settings were passed when trying to add capture\n");
audio_print_settings (as);
goto err0;
}
cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
if (!cb) {
dolog ("Could not allocate capture callback information, size %zu\n",
sizeof (*cb));
goto err0;
}
cb->ops = *ops;
cb->opaque = cb_opaque;
cap = audio_pcm_capture_find_specific (s, as);
if (cap) {
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
return cap;
}
else {
HWVoiceOut *hw;
CaptureVoiceOut *cap;
cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
if (!cap) {
dolog ("Could not allocate capture voice, size %zu\n",
sizeof (*cap));
goto err1;
}
hw = &cap->hw;
LIST_INIT (&hw->sw_head);
LIST_INIT (&cap->cb_head);
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
sizeof (st_sample_t));
if (!hw->mix_buf) {
dolog ("Could not allocate capture mix buffer (%d samples)\n",
hw->samples);
goto err2;
}
audio_pcm_init_info (&hw->info, as);
cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!cap->buf) {
dolog ("Could not allocate capture buffer "
"(%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
goto err3;
}
hw->clip = mixeng_clip
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
[hw->info.bits == 16];
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
hw = NULL;
while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
audio_attach_capture (s, hw);
}
return cap;
err3:
qemu_free (cap->hw.mix_buf);
err2:
qemu_free (cap);
err1:
qemu_free (cb);
err0:
return NULL;
}
}
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
{
struct capture_callback *cb;
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
if (cb->opaque == cb_opaque) {
cb->ops.destroy (cb_opaque);
LIST_REMOVE (cb, entries);
qemu_free (cb);
if (!cap->cb_head.lh_first) {
SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
while (sw) {
SWVoiceCap *sc = (SWVoiceCap *) sw;
#ifdef DEBUG_CAPTURE
dolog ("freeing %s\n", sw->name);
#endif
sw1 = sw->entries.le_next;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
sw = sw1;
}
LIST_REMOVE (cap, entries);
qemu_free (cap);
}
return;
}
}
}

View File

@@ -24,6 +24,7 @@
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "config.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
@@ -35,14 +36,44 @@ typedef enum {
AUD_FMT_S16
} audfmt_e;
#ifdef WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif
typedef struct {
int freq;
int nchannels;
audfmt_e fmt;
int endianness;
} audsettings_t;
typedef enum {
AUD_CNOTIFY_ENABLE,
AUD_CNOTIFY_DISABLE
} audcnotification_e;
struct audio_capture_ops {
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*destroy) (void *opaque);
};
struct capture_ops {
void (*info) (void *opaque);
void (*destroy) (void *opaque);
};
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
@@ -66,6 +97,13 @@ AudioState *AUD_init (void);
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *opaque
);
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
@@ -73,8 +111,7 @@ SWVoiceOut *AUD_open_out (
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings,
int sw_endian
audsettings_t *settings
);
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
@@ -92,8 +129,7 @@ SWVoiceIn *AUD_open_in (
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings,
int sw_endian
audsettings_t *settings
);
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
@@ -111,7 +147,7 @@ static inline void *advance (void *p, int incr)
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \

View File

@@ -61,13 +61,14 @@ struct audio_pcm_info {
int align;
int shift;
int bytes_per_second;
int swap_endian;
int swap_endianness;
};
typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
int enabled;
int pending_disable;
int valid;
struct audio_pcm_info info;
f_sample *clip;
@@ -79,6 +80,7 @@ typedef struct HWVoiceOut {
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
@@ -160,14 +162,34 @@ struct audio_pcm_ops {
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
LIST_ENTRY (capture_callback) entries;
};
struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
LIST_ENTRY (SWVoiceCap) entries;
};
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
QEMUTimer *ts;
LIST_HEAD (card_head, QEMUSoundCard) card_head;
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
int nb_hw_voices_out;
int nb_hw_voices_in;
};
@@ -182,8 +204,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
int swap_endian);
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
@@ -204,15 +225,6 @@ static inline int audio_ring_dist (int dst, int src, int len)
return (dst >= src) ? (dst - src) : (len - src + dst);
}
static inline int audio_need_to_swap_endian (int endianness)
{
#ifdef WORDS_BIGENDIAN
return endianness != 1;
#else
return endianness != 0;
#endif
}
#if defined __GNUC__
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
#define INIT_FIELD(f) . f

View File

@@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYPE) (
SW *sw,
HW *hw,
const char *name,
audsettings_t *as,
int endian
audsettings_t *as
)
{
int err;
audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
audio_pcm_init_info (&sw->info, as);
sw->hw = hw;
sw->active = 0;
#ifdef DAC
@@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
#endif
[sw->info.nchannels == 2]
[sw->info.sign]
[sw->info.swap_endian]
[sw->info.swap_endianness]
[sw->info.bits == 16];
sw->name = qemu_strdup (name);
@@ -200,6 +199,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
HW *hw = *hwp;
if (!hw->sw_head.lh_first) {
#ifdef DAC
audio_detach_capture (hw);
#endif
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
@@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
@@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endian]
[hw->info.swap_endianness]
[hw->info.bits == 16];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
@@ -292,6 +296,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
#ifdef DAC
audio_attach_capture (s, hw);
#endif
return hw;
err1:
@@ -328,8 +335,7 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
AudioState *s,
const char *sw_name,
audsettings_t *as,
int sw_endian
audsettings_t *as
)
{
SW *sw;
@@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
goto err3;
}
@@ -399,8 +405,7 @@ SW *glue (AUD_open_, TYPE) (
const char *name,
void *callback_opaque ,
audio_callback_fn_t callback_fn,
audsettings_t *as,
int sw_endian
audsettings_t *as
)
{
AudioState *s;
@@ -421,7 +426,7 @@ SW *glue (AUD_open_, TYPE) (
s = card->audio;
if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
@@ -473,12 +478,12 @@ SW *glue (AUD_open_, TYPE) (
}
glue (audio_pcm_sw_fini_, TYPE) (sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
}
else {
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian);
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
return NULL;

View File

@@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc(
#endif
}
/* cleanup */
mixeng_clear (src, frameCount);
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
@@ -297,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
UInt32 propertySize;
int err;
int bits = 8;
int endianess = 0;
const char *typ = "playback";
AudioValueRange frameRange;
@@ -310,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
bits = 16;
endianess = 1;
}
audio_pcm_init_info (
&hw->info,
as,
/* Following is irrelevant actually since we do not use
mixengs clipping routines */
audio_need_to_swap_endian (endianess)
);
audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);

View File

@@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) (
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
DWORD flag;
#ifdef DSBTYPE_IN
flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
@@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) (
&blen1,
&p2,
&blen2,
(entire
#ifdef DSBTYPE_IN
? DSCBLOCK_ENTIREBUFFER
#else
? DSBLOCK_ENTIREBUFFER
#endif
: 0)
flag
);
if (FAILED (hr)) {
@@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
}
ds->first_time = 1;
audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) {
dolog (

View File

@@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
@@ -987,6 +985,12 @@ static void *dsound_audio_init (void)
hr = IDirectSound_Initialize (s->dsound, NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize DirectSound\n");
hr = IDirectSound_Release (s->dsound);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release DirectSound\n");
}
s->dsound = NULL;
return NULL;
}

View File

@@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
@@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
{
int bits16, mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
audsettings_t obt_as = *as;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
@@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
@@ -420,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
{
int bits16, mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
audsettings_t obt_as = *as;
if (conf.broken_adc) {
return -1;
@@ -442,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
}
/* FMOD always operates on little endian frames? */
audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;

View File

@@ -40,22 +40,21 @@ static int no_run_out (HWVoiceOut *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
}
else {
samples = bytes >> hw->info.shift;
}
int64_t now;
int64_t ticks;
int64_t bytes;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
no->old_ticks = now;
decr = audio_MIN (live, samples);
hw->rpos = (hw->rpos + decr) % hw->samples;
@@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as, 0);
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
@@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as, 0);
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
@@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw)
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples;
int samples = 0;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
no->old_ticks = now;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
}
return samples;
}

View File

@@ -55,12 +55,14 @@ static struct {
int fragsize;
const char *devpath_out;
const char *devpath_in;
int debug;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp"
.devpath_in = "/dev/dsp",
.debug = 0
};
struct oss_params {
@@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw)
return 0;
}
if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to malc@pulsesoft.com\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
}
if (abinfo.bytes < 0) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
}
return 0;
}
@@ -369,15 +382,12 @@ static int oss_run_out (HWVoiceOut *hw)
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
mixeng_clear (src, wsamples);
decr -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
@@ -443,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
@@ -587,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianness)
);
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
@@ -730,6 +734,8 @@ static struct audio_option oss_options[] = {
"Path to DAC device", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
"Path to ADC device", NULL, 0},
{"DEBUG", AUD_OPT_BOOL, &conf.debug,
"Turn on some debugging messages", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};

View File

@@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
if (rate->opos_inc == (1ULL + UINT_MAX)) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
OP (obuf[i].l, ibuf[i].r);
OP (obuf[i].l, ibuf[i].l);
OP (obuf[i].r, ibuf[i].r);
}
*isamp = n;

View File

@@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
mixeng_clear (src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
@@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
audio_pcm_init_info (
&hw->info,
&obt_as,
audio_need_to_swap_endian (endianess)
);
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
s->initialized = 1;

View File

@@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw)
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
@@ -136,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
hdr[34] = bits16 ? 0x10 : 0x08;
audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
wav_as.endianness = 0;
audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
@@ -151,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
wav->f = fopen (conf.wav_path, "wb");
wav->f = qemu_fopen (conf.wav_path, "wb");
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
@@ -185,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw)
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
qemu_fclose (wav->f);
wav->f = NULL;
qemu_free (wav->pcm_buf);

163
audio/wavcapture.c Normal file
View File

@@ -0,0 +1,163 @@
#include "vl.h"
typedef struct {
QEMUFile *f;
int bytes;
char *path;
int freq;
int bits;
int nchannels;
CaptureVoiceOut *cap;
} WAVState;
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static void wav_notify (void *opaque, audcnotification_e cmd)
{
(void) opaque;
(void) cmd;
}
static void wav_destroy (void *opaque)
{
WAVState *wav = opaque;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
if (wav->f) {
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
qemu_fclose (wav->f);
}
qemu_free (wav->path);
}
static void wav_capture (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
qemu_put_buffer (wav->f, buf, size);
wav->bytes += size;
}
static void wav_capture_destroy (void *opaque)
{
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
}
static void wav_capture_info (void *opaque)
{
WAVState *wav = opaque;
char *path = wav->path;
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
wav->freq, wav->bits, wav->nchannels,
path ? path : "<not available>", wav->bytes);
}
static struct capture_ops wav_capture_ops = {
.destroy = wav_capture_destroy,
.info = wav_capture_info
};
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels)
{
WAVState *wav;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
audsettings_t as;
struct audio_capture_ops ops;
int stereo, bits16, shift;
CaptureVoiceOut *cap;
if (bits != 8 && bits != 16) {
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
return -1;
}
if (nchannels != 1 && nchannels != 2) {
term_printf ("incorrect channel count %d, must be 1 or 2\n",
nchannels);
return -1;
}
stereo = nchannels == 2;
bits16 = bits == 16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
ops.notify = wav_notify;
ops.capture = wav_capture;
ops.destroy = wav_destroy;
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
sizeof (*wav));
return -1;
}
shift = bits16 + stereo;
hdr[34] = bits16 ? 0x10 : 0x08;
le_store (hdr + 22, as.nchannels, 2);
le_store (hdr + 24, freq, 4);
le_store (hdr + 28, freq << shift, 4);
le_store (hdr + 32, 1 << shift, 2);
wav->f = qemu_fopen (path, "wb");
if (!wav->f) {
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return -1;
}
wav->path = qemu_strdup (path);
wav->bits = bits;
wav->nchannels = nchannels;
wav->freq = freq;
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
cap = AUD_add_capture (NULL, &as, &ops, wav);
if (!cap) {
term_printf ("Failed to add audio capture\n");
qemu_free (wav->path);
qemu_fclose (wav->f);
qemu_free (wav);
return -1;
}
wav->cap = cap;
s->opaque = wav;
s->ops = wav_capture_ops;
return 0;
}

View File

@@ -28,7 +28,8 @@
/**************************************************************/
#define HEADER_MAGIC "Bochs Virtual HD Image"
#define HEADER_VERSION 0x00010000
#define HEADER_VERSION 0x00020000
#define HEADER_V1 0x00010000
#define HEADER_SIZE 512
#define REDOLOG_TYPE "Redolog"
@@ -36,6 +37,26 @@
// not allocated: 0xffffffff
// always little-endian
struct bochs_header_v1 {
char magic[32]; // "Bochs Virtual HD Image"
char type[16]; // "Redolog"
char subtype[16]; // "Undoable" / "Volatile" / "Growing"
uint32_t version;
uint32_t header; // size of header
union {
struct {
uint32_t catalog; // num of entries
uint32_t bitmap; // bitmap size
uint32_t extent; // extent size
uint64_t disk; // disk size
char padding[HEADER_SIZE - 64 - 8 - 20];
} redolog;
char padding[HEADER_SIZE - 64 - 8];
} extra;
};
// always little-endian
struct bochs_header {
char magic[32]; // "Bochs Virtual HD Image"
@@ -49,8 +70,9 @@ struct bochs_header {
uint32_t catalog; // num of entries
uint32_t bitmap; // bitmap size
uint32_t extent; // extent size
uint32_t reserved; // for ???
uint64_t disk; // disk size
char padding[HEADER_SIZE - 64 - 8 - 20];
char padding[HEADER_SIZE - 64 - 8 - 24];
} redolog;
char padding[HEADER_SIZE - 64 - 8];
} extra;
@@ -79,21 +101,23 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
!strcmp(bochs->type, REDOLOG_TYPE) &&
!strcmp(bochs->subtype, GROWING_TYPE) &&
(le32_to_cpu(bochs->version) == HEADER_VERSION))
((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
(le32_to_cpu(bochs->version) == HEADER_V1)))
return 100;
return 0;
}
static int bochs_open(BlockDriverState *bs, const char *filename)
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVBochsState *s = bs->opaque;
int fd, i;
struct bochs_header bochs;
struct bochs_header_v1 header_v1;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
}
@@ -109,11 +133,17 @@ static int bochs_open(BlockDriverState *bs, const char *filename)
if (strcmp(bochs.magic, HEADER_MAGIC) ||
strcmp(bochs.type, REDOLOG_TYPE) ||
strcmp(bochs.subtype, GROWING_TYPE) ||
(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
(le32_to_cpu(bochs.version) != HEADER_V1))) {
goto fail;
}
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
if (le32_to_cpu(bochs.version) == HEADER_V1) {
memcpy(&header_v1, &bochs, sizeof(bochs));
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
} else {
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
}
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);

View File

@@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, const char *filename)
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
s->fd = open(filename, O_RDONLY | O_BINARY);
if (s->fd < 0)
return -1;
return -errno;
bs->read_only = 1;
/* read header */

View File

@@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename)
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCowState *s = bs->opaque;
int fd;
@@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs, const char *filename)
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
#if 0
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
#endif
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
@@ -179,8 +163,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
if (ret != n * 512)
return -1;
} else {
if (bs->backing_hd) {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, n * 512);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
@@ -220,7 +211,7 @@ static int cow_create(const char *filename, int64_t image_sectors,
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (cow_fd < 0)
return -1;
@@ -228,18 +219,23 @@ static int cow_create(const char *filename, int64_t image_sectors,
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
/* Note: if no file, we put a dummy mtime */
cow_header.mtime = cpu_to_be32(0);
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
return -1;
goto mtime_fail;
}
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
goto mtime_fail;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
mtime_fail:
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
image_filename);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
@@ -250,6 +246,12 @@ static int cow_create(const char *filename, int64_t image_sectors,
return 0;
}
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
@@ -259,6 +261,7 @@ BlockDriver bdrv_cow = {
cow_write,
cow_close,
cow_create,
cow_flush,
cow_is_allocated,
};
#endif

View File

@@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
return be32_to_cpu(buffer);
}
static int dmg_open(BlockDriverState *bs, const char *filename)
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
s->fd = open(filename, O_RDONLY | O_BINARY);
if (s->fd < 0)
return -1;
return -errno;
bs->read_only = 1;
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
@@ -93,7 +93,7 @@ dmg_close:
close(s->fd);
/* open raw instead */
bs->drv=&bdrv_raw;
return bs->drv->bdrv_open(bs,filename);
return bs->drv->bdrv_open(bs, filename, flags);
}
info_begin=read_off(s->fd);
if(info_begin==0)

View File

@@ -1,7 +1,7 @@
/*
* Block driver for the QCOW format
*
* Copyright (c) 2004 Fabrice Bellard
* Copyright (c) 2004-2006 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
@@ -53,7 +53,7 @@ typedef struct QCowHeader {
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
int fd;
BlockDriverState *hd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
@@ -89,20 +89,16 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int qcow_open(BlockDriverState *bs, const char *filename)
static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVQcowState *s = bs->opaque;
int fd, len, i, shift;
int len, i, shift, ret;
QCowHeader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
s->fd = fd;
if (read(fd, &header, sizeof(header)) != sizeof(header))
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0)
return ret;
if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
goto fail;
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
@@ -138,8 +134,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
if (!s->l1_table)
goto fail;
lseek(fd, s->l1_table_offset, SEEK_SET);
if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
@@ -162,8 +157,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
len = header.backing_file_size;
if (len > 1023)
len = 1023;
lseek(fd, header.backing_file_offset, SEEK_SET);
if (read(fd, bs->backing_file, len) != len)
if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
}
@@ -174,7 +168,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename)
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(fd);
bdrv_delete(s->hd);
return -1;
}
@@ -276,14 +270,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
if (!allocate)
return 0;
/* allocate a new l2 entry */
l2_offset = lseek(s->fd, 0, SEEK_END);
l2_offset = bdrv_getlength(s->hd);
/* round to cluster size */
l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
&tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
new_l2_table = 1;
}
@@ -309,14 +303,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
lseek(s->fd, l2_offset, SEEK_SET);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
} else {
if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return 0;
}
@@ -337,36 +330,35 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
overwritten */
if (decompress_cluster(s, cluster_offset) < 0)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = bdrv_getlength(s->hd);
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
/* write the cluster content */
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, s->cluster_cache, s->cluster_size) !=
if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
s->cluster_size)
return -1;
} else {
cluster_offset = lseek(s->fd, 0, SEEK_END);
cluster_offset = bdrv_getlength(s->hd);
if (allocate == 1) {
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
ftruncate(s->fd, cluster_offset + s->cluster_size);
bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (s->crypt_method &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0xaa, 512);
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
if (write(s->fd, s->cluster_data, 512) != 512)
if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
s->cluster_data, 512) != 512)
return -1;
}
}
@@ -379,8 +371,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite(s->hd,
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
return cluster_offset;
@@ -438,8 +430,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
lseek(s->fd, coffset, SEEK_SET);
ret = read(s->fd, s->cluster_data, csize);
ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
if (ret != csize)
return -1;
if (decompress_buffer(s->cluster_cache, s->cluster_size,
@@ -451,6 +442,8 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
return 0;
}
#if 0
static int qcow_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
@@ -465,14 +458,20 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
if (bs->backing_hd) {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, 512 * n);
}
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
if (decompress_cluster(s, cluster_offset) < 0)
return -1;
memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
if (ret != n * 512)
return -1;
if (s->crypt_method) {
@@ -486,6 +485,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num,
}
return 0;
}
#endif
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
@@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
index_in_cluster + n);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
if (s->crypt_method) {
encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
&s->aes_encrypt_key);
ret = write(s->fd, s->cluster_data, n * 512);
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
s->cluster_data, n * 512);
} else {
ret = write(s->fd, buf, n * 512);
ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
}
if (ret != n * 512)
return -1;
@@ -522,6 +522,209 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num,
return 0;
}
typedef struct QCowAIOCB {
BlockDriverAIOCB common;
int64_t sector_num;
uint8_t *buf;
int nb_sectors;
int n;
uint64_t cluster_offset;
uint8_t *cluster_data;
BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB;
static void qcow_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
acb->hd_aiocb = NULL;
if (ret < 0) {
fail:
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
return;
}
redo:
/* post process the read buffer */
if (!acb->cluster_offset) {
/* nothing to do */
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* nothing to do */
} else {
if (s->crypt_method) {
encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
acb->n, 0,
&s->aes_decrypt_key);
}
}
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
if (acb->nb_sectors == 0) {
/* request completed */
acb->common.cb(acb->common.opaque, 0);
qemu_aio_release(acb);
return;
}
/* prepare next AIO request */
acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
0, 0, 0, 0);
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
acb->n = s->cluster_sectors - index_in_cluster;
if (acb->n > acb->nb_sectors)
acb->n = acb->nb_sectors;
if (!acb->cluster_offset) {
if (bs->backing_hd) {
/* read from the base image */
acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
goto fail;
} else {
/* Note: in this case, no need to wait */
memset(acb->buf, 0, 512 * acb->n);
goto redo;
}
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
if (decompress_cluster(s, acb->cluster_offset) < 0)
goto fail;
memcpy(acb->buf,
s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
goto redo;
} else {
if ((acb->cluster_offset & 511) != 0) {
ret = -EIO;
goto fail;
}
acb->hd_aiocb = bdrv_aio_read(s->hd,
(acb->cluster_offset >> 9) + index_in_cluster,
acb->buf, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
goto fail;
}
}
static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
QCowAIOCB *acb;
acb = qemu_aio_get(bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->buf = buf;
acb->nb_sectors = nb_sectors;
acb->n = 0;
acb->cluster_offset = 0;
qcow_aio_read_cb(acb, 0);
return &acb->common;
}
static void qcow_aio_write_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVQcowState *s = bs->opaque;
int index_in_cluster;
uint64_t cluster_offset;
const uint8_t *src_buf;
acb->hd_aiocb = NULL;
if (ret < 0) {
fail:
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
return;
}
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
if (acb->nb_sectors == 0) {
/* request completed */
acb->common.cb(acb->common.opaque, 0);
qemu_aio_release(acb);
return;
}
index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
acb->n = s->cluster_sectors - index_in_cluster;
if (acb->n > acb->nb_sectors)
acb->n = acb->nb_sectors;
cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
index_in_cluster,
index_in_cluster + acb->n);
if (!cluster_offset || (cluster_offset & 511) != 0) {
ret = -EIO;
goto fail;
}
if (s->crypt_method) {
if (!acb->cluster_data) {
acb->cluster_data = qemu_mallocz(s->cluster_size);
if (!acb->cluster_data) {
ret = -ENOMEM;
goto fail;
}
}
encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
acb->n, 1, &s->aes_encrypt_key);
src_buf = acb->cluster_data;
} else {
src_buf = acb->buf;
}
acb->hd_aiocb = bdrv_aio_write(s->hd,
(cluster_offset >> 9) + index_in_cluster,
src_buf, acb->n,
qcow_aio_write_cb, acb);
if (acb->hd_aiocb == NULL)
goto fail;
}
static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
int64_t sector_num, const uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
s->cluster_cache_offset = -1; /* disable compressed cache */
acb = qemu_aio_get(bs, cb, opaque);
if (!acb)
return NULL;
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->buf = (uint8_t *)buf;
acb->nb_sectors = nb_sectors;
acb->n = 0;
qcow_aio_write_cb(acb, 0);
return &acb->common;
}
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
{
QCowAIOCB *acb = (QCowAIOCB *)blockacb;
if (acb->hd_aiocb)
bdrv_aio_cancel(acb->hd_aiocb);
qemu_aio_release(acb);
}
static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
@@ -529,7 +732,7 @@ static void qcow_close(BlockDriverState *bs)
qemu_free(s->l2_cache);
qemu_free(s->cluster_cache);
qemu_free(s->cluster_data);
close(s->fd);
bdrv_delete(s->hd);
}
static int qcow_create(const char *filename, int64_t total_size,
@@ -537,12 +740,9 @@ static int qcow_create(const char *filename, int64_t total_size,
{
int fd, header_size, backing_filename_len, l1_size, i, shift;
QCowHeader header;
char backing_filename[1024];
uint64_t tmp;
struct stat st;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
if (fd < 0)
return -1;
memset(&header, 0, sizeof(header));
@@ -552,28 +752,11 @@ static int qcow_create(const char *filename, int64_t total_size,
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
if (strcmp(backing_file, "fat:")) {
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.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_filename);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
} else
backing_file = NULL;
header.mtime = cpu_to_be32(st.st_mtime);
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_file);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
header.mtime = cpu_to_be32(0);
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
unmodifyed sectors */
header.l2_bits = 12; /* 32 KB L2 tables */
@@ -595,7 +778,7 @@ static int qcow_create(const char *filename, int64_t total_size,
/* write all the data */
write(fd, &header, sizeof(header));
if (backing_file) {
write(fd, backing_filename, backing_filename_len);
write(fd, backing_file, backing_filename_len);
}
lseek(fd, header_size, SEEK_SET);
tmp = 0;
@@ -606,16 +789,18 @@ static int qcow_create(const char *filename, int64_t total_size,
return 0;
}
int qcow_make_empty(BlockDriverState *bs)
static int qcow_make_empty(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
int ret;
memset(s->l1_table, 0, l1_length);
lseek(s->fd, s->l1_table_offset, SEEK_SET);
if (write(s->fd, s->l1_table, l1_length) < 0)
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
return -1;
ftruncate(s->fd, s->l1_table_offset + l1_length);
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
if (ret < 0)
return ret;
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
@@ -624,18 +809,10 @@ int qcow_make_empty(BlockDriverState *bs)
return 0;
}
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
if (bs->drv != &bdrv_qcow)
return -1;
return s->cluster_size;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf)
static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
z_stream strm;
@@ -643,8 +820,8 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
uint8_t *out_buf;
uint64_t cluster_offset;
if (bs->drv != &bdrv_qcow)
return -1;
if (nb_sectors != s->cluster_sectors)
return -EINVAL;
out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
@@ -682,8 +859,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
cluster_offset &= s->cluster_offset_mask;
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
qemu_free(out_buf);
return -1;
}
@@ -693,18 +869,37 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
return 0;
}
static void qcow_flush(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
bdrv_flush(s->hd);
}
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVQcowState *s = bs->opaque;
bdi->cluster_size = s->cluster_size;
return 0;
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_probe,
qcow_open,
qcow_read,
qcow_write,
NULL,
NULL,
qcow_close,
qcow_create,
qcow_flush,
qcow_is_allocated,
qcow_set_key,
qcow_make_empty
qcow_make_empty,
.bdrv_aio_read = qcow_aio_read,
.bdrv_aio_write = qcow_aio_write,
.bdrv_aio_cancel = qcow_aio_cancel,
.aiocb_size = sizeof(QCowAIOCB),
.bdrv_write_compressed = qcow_write_compressed,
.bdrv_get_info = qcow_get_info,
};

2246
block-qcow2.c Normal file

File diff suppressed because it is too large Load Diff

1352
block-raw.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "block_int.h"
@@ -59,7 +60,7 @@ typedef struct {
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
int fd;
BlockDriverState *hd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
@@ -73,6 +74,7 @@ typedef struct BDRVVmdkState {
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
uint32_t parent_cid;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
@@ -89,27 +91,278 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
#define CHECK_CID 1
#define SECTOR_SIZE 512
#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each
#define HEADER_SIZE 512 // first sector of 512 bytes
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
uint32_t magic;
int l1_size;
char desc[DESC_SIZE];
uint32_t cid;
char *p_name, *cid_str;
size_t cid_str_size;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
bs->read_only = 1;
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return 0;
if (parent) {
cid_str = "parentCID";
cid_str_size = sizeof("parentCID");
} else {
cid_str = "CID";
cid_str_size = sizeof("CID");
}
if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
if ((p_name = strstr(desc,cid_str)) != 0) {
p_name += cid_str_size;
sscanf(p_name,"%x",&cid);
}
return cid;
}
static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
{
BDRVVmdkState *s = bs->opaque;
char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
char *p_name, *tmp_str;
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
tmp_str = strstr(desc,"parentCID");
strcpy(tmp_desc, tmp_str);
if ((p_name = strstr(desc,"CID")) != 0) {
p_name += sizeof("CID");
sprintf(p_name,"%x\n",cid);
strcat(desc,tmp_desc);
}
if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
return 0;
}
static int vmdk_is_cid_valid(BlockDriverState *bs)
{
#ifdef CHECK_CID
BDRVVmdkState *s = bs->opaque;
BlockDriverState *p_bs = s->hd->backing_hd;
uint32_t cur_pcid;
if (p_bs) {
cur_pcid = vmdk_read_cid(p_bs,0);
if (s->parent_cid != cur_pcid)
// CID not valid
return 0;
}
#endif
// CID valid
return 1;
}
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
{
int snp_fd, p_fd;
uint32_t p_cid;
char *p_name, *gd_buf, *rgd_buf;
const char *real_filename, *temp_str;
VMDK4Header header;
uint32_t gde_entries, gd_size;
int64_t gd_offset, rgd_offset, capacity, gt_size;
char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
char *desc_template =
"# Disk DescriptorFile\n"
"version=1\n"
"CID=%x\n"
"parentCID=%x\n"
"createType=\"monolithicSparse\"\n"
"parentFileNameHint=\"%s\"\n"
"\n"
"# Extent description\n"
"RW %lu SPARSE \"%s\"\n"
"\n"
"# The Disk Data Base \n"
"#DDB\n"
"\n";
snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
if (snp_fd < 0)
return -1;
p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
if (p_fd < 0) {
close(snp_fd);
return -1;
}
/* read the header */
if (lseek(p_fd, 0x0, SEEK_SET) == -1)
goto fail;
if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
goto fail;
/* write the header */
if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
goto fail;
if (write(snp_fd, hdr, HEADER_SIZE) == -1)
goto fail;
memset(&header, 0, sizeof(header));
memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
ftruncate(snp_fd, header.grain_offset << 9);
/* the descriptor offset = 0x200 */
if (lseek(p_fd, 0x200, SEEK_SET) == -1)
goto fail;
if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
goto fail;
if ((p_name = strstr(p_desc,"CID")) != 0) {
p_name += sizeof("CID");
sscanf(p_name,"%x",&p_cid);
}
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(s_desc, desc_template, p_cid, p_cid, backing_file
, (uint32_t)header.capacity, real_filename);
/* write the descriptor */
if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
goto fail;
if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
goto fail;
gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table
rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table
capacity = header.capacity * SECTOR_SIZE; // Extent size
/*
* Each GDE span 32M disk, means:
* 512 GTE per GT, each GTE points to grain
*/
gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
if (!gt_size)
goto fail;
gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde
gd_size = gde_entries * sizeof(uint32_t);
/* write RGD */
rgd_buf = qemu_malloc(gd_size);
if (!rgd_buf)
goto fail;
if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
goto fail_rgd;
if (read(p_fd, rgd_buf, gd_size) != gd_size)
goto fail_rgd;
if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
goto fail_rgd;
if (write(snp_fd, rgd_buf, gd_size) == -1)
goto fail_rgd;
qemu_free(rgd_buf);
/* write GD */
gd_buf = qemu_malloc(gd_size);
if (!gd_buf)
goto fail_rgd;
if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
goto fail_gd;
if (read(p_fd, gd_buf, gd_size) != gd_size)
goto fail_gd;
if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
goto fail_gd;
if (write(snp_fd, gd_buf, gd_size) == -1)
goto fail_gd;
qemu_free(gd_buf);
close(p_fd);
close(snp_fd);
return 0;
fail_gd:
qemu_free(gd_buf);
fail_rgd:
qemu_free(rgd_buf);
fail:
close(p_fd);
close(snp_fd);
return -1;
}
static void vmdk_parent_close(BlockDriverState *bs)
{
if (bs->backing_hd)
bdrv_close(bs->backing_hd);
}
static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
{
BDRVVmdkState *s = bs->opaque;
char *p_name;
char desc[DESC_SIZE];
char parent_img_name[1024];
/* the descriptor offset = 0x200 */
if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
return -1;
if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
char *end_name;
struct stat file_buf;
p_name += sizeof("parentFileNameHint") + 1;
if ((end_name = strchr(p_name,'\"')) == 0)
return -1;
strncpy(s->hd->backing_file, p_name, end_name - p_name);
if (stat(s->hd->backing_file, &file_buf) != 0) {
path_combine(parent_img_name, sizeof(parent_img_name),
filename, s->hd->backing_file);
} else {
strcpy(parent_img_name, s->hd->backing_file);
}
s->hd->backing_hd = bdrv_new("");
if (!s->hd->backing_hd) {
failure:
bdrv_close(s->hd);
return -1;
}
if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
goto failure;
}
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVmdkState *s = bs->opaque;
uint32_t magic;
int l1_size, i, ret;
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0)
return ret;
if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
if (read(fd, &header, sizeof(header)) !=
sizeof(header))
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
@@ -120,8 +373,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
if (read(fd, &header, sizeof(header)) != sizeof(header))
if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le64_to_cpu(header.capacity);
s->cluster_sectors = le64_to_cpu(header.granularity);
@@ -133,17 +386,22 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
// try to open parent images, if exist
if (vmdk_parent_open(bs, filename) != 0)
goto fail;
// write the CID once after the image creation
s->parent_cid = vmdk_read_cid(bs,1);
} else {
goto fail;
}
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_table, l1_size) != l1_size)
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
@@ -153,9 +411,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
s->l1_backup_table = qemu_malloc(l1_size);
if (!s->l1_backup_table)
goto fail;
if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
goto fail;
if (read(fd, s->l1_backup_table, l1_size) != l1_size)
if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
@@ -165,16 +421,43 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
s->fd = fd;
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(fd);
bdrv_delete(s->hd);
return -1;
}
static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate);
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
uint64_t offset, int allocate)
{
uint64_t parent_cluster_offset;
BDRVVmdkState *s = bs->opaque;
uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
// we will be here if it's first write on non-exist grain(cluster).
// try to read from parent image, if exist
if (s->hd->backing_hd) {
BDRVVmdkState *ps = s->hd->backing_hd->opaque;
if (!vmdk_is_cid_valid(bs))
return -1;
parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate);
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) !=
ps->cluster_sectors*512)
return -1;
if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) !=
sizeof(whole_grain))
return -1;
}
return 0;
}
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate)
{
@@ -212,34 +495,41 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
s->l2_size * sizeof(uint32_t))
return 0;
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (!cluster_offset) {
struct stat file_buf;
if (!allocate)
return 0;
cluster_offset = lseek(s->fd, 0, SEEK_END);
ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
stat(s->hd->filename, &file_buf);
cluster_offset = file_buf.st_size;
bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
cluster_offset >>= 9;
/* update L2 table */
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
&tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
l2_offset = s->l1_backup_table[l1_index];
lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
&tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
return 0;
}
cluster_offset <<= 9;
return cluster_offset;
@@ -265,9 +555,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
int index_in_cluster, n, ret;
uint64_t cluster_offset;
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
@@ -275,11 +565,18 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
memset(buf, 0, 512 * n);
// try to read from parent image, if exist
if (s->hd->backing_hd) {
if (!vmdk_is_cid_valid(bs))
return -1;
ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, 512 * n);
}
} else {
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = read(s->fd, buf, n * 512);
if (ret != n * 512)
if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
}
nb_sectors -= n;
@@ -293,8 +590,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
int ret, index_in_cluster, n;
int index_in_cluster, n;
uint64_t cluster_offset;
static int cid_update = 0;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -304,13 +602,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
ret = write(s->fd, buf, n * 512);
if (ret != n * 512)
if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
// update CID on the first write every time the virtual disk is opened
if (!cid_update) {
vmdk_write_cid(bs, time(NULL));
cid_update++;
}
}
return 0;
}
@@ -334,7 +636,7 @@ static int vmdk_create(const char *filename, int64_t total_size,
"# The Disk Data Base \n"
"#DDB\n"
"\n"
"ddb.virtualHWVersion = \"3\"\n"
"ddb.virtualHWVersion = \"4\"\n"
"ddb.geometry.cylinders = \"%lu\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
@@ -343,6 +645,9 @@ static int vmdk_create(const char *filename, int64_t total_size,
const char *real_filename, *temp_str;
/* XXX: add support for backing file */
if (backing_file) {
return vmdk_snapshot_create(filename, backing_file);
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
@@ -421,9 +726,18 @@ static int vmdk_create(const char *filename, int64_t total_size,
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
close(s->fd);
bdrv_delete(s->hd);
// try to close parent image, if exist
vmdk_parent_close(s->hd);
}
static void vmdk_flush(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
bdrv_flush(s->hd);
}
BlockDriver bdrv_vmdk = {
@@ -435,5 +749,6 @@ BlockDriver bdrv_vmdk = {
vmdk_write,
vmdk_close,
vmdk_create,
vmdk_flush,
vmdk_is_allocated,
};

View File

@@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename)
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVPCState *s = bs->opaque;
int fd, i;
struct vpc_subheader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
bs->read_only = 1; // no write support yet
s->fd = fd;
@@ -163,7 +160,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);

View File

@@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) {
exit(-5);
}
#undef assert
#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
#endif
#else
@@ -351,13 +351,6 @@ typedef struct BDRVVVFATState {
} BDRVVVFATState;
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (strstart(filename, "fat:", NULL))
return 100;
return 0;
}
static void init_mbr(BDRVVVFATState* s)
{
/* TODO: if the files mbr.img and bootsect.img exist, use them */
@@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATState* s,
return 0;
}
#ifdef DEBUG
static BDRVVVFATState *vvv = NULL;
#endif
static int enable_write_target(BDRVVVFATState *s);
static int is_consistent(BDRVVVFATState *s);
static int vvfat_open(BlockDriverState *bs, const char* dirname)
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
{
BDRVVVFATState *s = bs->opaque;
int floppy = 0;
int i;
#ifdef DEBUG
vvv = s;
#endif
DLOG(if (stderr == NULL) {
stderr = fopen("vvfat.log", "a");
@@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) {
bs->heads = bs->cyls = bs->secs = 0;
// assert(is_consistent(s));
return 0;
}
@@ -2178,7 +2174,7 @@ static int commit_one_file(BDRVVVFATState* s,
for (i = s->cluster_size; i < offset; i += s->cluster_size)
c = modified_fat_get(s, c);
fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
if (fd < 0) {
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
strerror(errno), errno);
@@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFATState *s)
array_init(&(s->commits), sizeof(commit_t));
s->qcow_filename = malloc(1024);
strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
get_tmp_filename(s->qcow_filename, 1024);
if (bdrv_create(&bdrv_qcow,
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
return -1;
@@ -2767,13 +2762,15 @@ static void vvfat_close(BlockDriverState *bs)
BlockDriver bdrv_vvfat = {
"vvfat",
sizeof(BDRVVVFATState),
vvfat_probe,
NULL, /* no probe for protocols */
vvfat_open,
vvfat_read,
vvfat_write,
vvfat_close,
NULL, /* ??? Not sure if we can do any meaningful flushing. */
NULL,
vvfat_is_allocated
vvfat_is_allocated,
.protocol_name = "fat",
};
#ifdef DEBUG

1245
block.c

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
@@ -36,17 +36,54 @@ struct BlockDriver {
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
void (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
/* aio */
BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
int64_t sector_num, const uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
int aiocb_size;
const char *protocol_name;
int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count);
int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count);
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int (*bdrv_snapshot_create)(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info);
int (*bdrv_snapshot_goto)(BlockDriverState *bs,
const char *snapshot_id);
int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
int (*bdrv_snapshot_list)(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
/* removable device specific */
int (*bdrv_is_inserted)(BlockDriverState *bs);
int (*bdrv_media_changed)(BlockDriverState *bs);
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
BlockDriverAIOCB *free_aiocb;
struct BlockDriver *next;
};
struct BlockDriverState {
int64_t total_sectors;
int64_t total_sectors; /* if we are reading a disk image, give its
size in sectors */
int read_only; /* if true, the media is read only */
int inserted; /* if true, the media is present */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
@@ -54,7 +91,7 @@ struct BlockDriverState {
void (*change_cb)(void *opaque);
void *change_opaque;
BlockDriver *drv;
BlockDriver *drv; /* NULL means no media */
void *opaque;
int boot_sector_enabled;
@@ -64,8 +101,12 @@ struct BlockDriverState {
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
int is_temporary;
int media_changed;
BlockDriverState *backing_hd;
/* async read/write emulation */
void *sync_aiocb;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
@@ -75,6 +116,17 @@ struct BlockDriverState {
BlockDriverState *next;
};
struct BlockDriverAIOCB {
BlockDriverState *bs;
BlockDriverCompletionFunc *cb;
void *opaque;
BlockDriverAIOCB *next;
};
void get_tmp_filename(char *filename, int size);
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
void *opaque);
void qemu_aio_release(void *p);
#endif /* BLOCK_INT_H */

47
check_ops.sh Executable file
View File

@@ -0,0 +1,47 @@
#! /bin/sh
# Script to check for duplicate function prologues in op.o
# Typically this indicates missing FORCE_RET();
# This script does not detect other errors that may be present.
# Usage: check_ops.sh [-m machine] [op.o]
# machine and op.o are guessed if not specified.
if [ "x$1" = "x-m" ]; then
machine=$2
shift 2
else
machine=`uname -m`
fi
if [ -z "$1" ]; then
for f in `find . -name op.o`; do
/bin/sh "$0" -m $machine $f
done
exit 0
fi
case $machine in
i?86)
ret='\tret'
;;
x86_64)
ret='\tretq'
;;
arm)
ret='\tldm.*pc'
;;
ppc* | powerpc*)
ret='\tblr'
;;
mips*)
ret='\tjr.*ra'
;;
*)
echo "Unknown machine `uname -m`"
;;
esac
echo $1
# op_exit_tb causes false positives on some hosts.
${CROSS}objdump -dr $1 | \
sed -e '/>:$\|'"$ret"'/!d' -e 's/.*<\(.*\)>:/~\1:/' -e 's/.*'"$ret"'.*/!/' | \
sed -e ':1;N;s/\n//;t1' | sed -e 's/~/\n/g' | grep -v '^op_exit_tb' | \
grep '^op_.*!!'

56
cocoa.m
View File

@@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *ds)
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
/* handle monitor key events */
} else {
int keysym = 0;
switch([event keyCode]) {
case 123:
kbd_put_keysym(QEMU_KEY_LEFT);
break;
case 124:
kbd_put_keysym(QEMU_KEY_RIGHT);
break;
case 125:
kbd_put_keysym(QEMU_KEY_DOWN);
break;
case 126:
kbd_put_keysym(QEMU_KEY_UP);
break;
default:
kbd_put_keysym([[event characters] characterAtIndex:0]);
break;
case 115:
keysym = QEMU_KEY_HOME;
break;
case 117:
keysym = QEMU_KEY_DELETE;
break;
case 119:
keysym = QEMU_KEY_END;
break;
case 123:
keysym = QEMU_KEY_LEFT;
break;
case 124:
keysym = QEMU_KEY_RIGHT;
break;
case 125:
keysym = QEMU_KEY_DOWN;
break;
case 126:
keysym = QEMU_KEY_UP;
break;
default:
{
NSString *ks = [event characters];
if ([ks length] > 0)
keysym = [ks characterAtIndex:0];
}
}
if (keysym)
kbd_put_keysym(keysym);
}
}
}
@@ -867,10 +884,9 @@ static void setupWindowMenu(void)
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
static void CustomApplicationMain (argc, argv)
static void CustomApplicationMain(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QemuCocoaGUIController *gui_controller;
@@ -904,8 +920,8 @@ int main(int argc, char **argv)
{
gArgc = argc;
gArgv = argv;
CustomApplicationMain (argc, argv);
CustomApplicationMain();
return 0;
}

205
configure vendored
View File

@@ -22,6 +22,8 @@ interp_prefix="/usr/gnemul/qemu-%M"
static="no"
cross_prefix=""
cc="gcc"
gcc3_search="yes"
gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
host_cc="gcc"
ar="ar"
make="make"
@@ -88,20 +90,21 @@ bsd="no"
linux="no"
kqemu="no"
profiler="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
check_gcc="yes"
softmmu="yes"
user="no"
linux_user="no"
darwin_user="no"
build_docs="no"
uname_release=""
# OS specific
targetos=`uname -s`
case $targetos in
CYGWIN*)
mingw32="yes"
CFLAGS="-O2 -mno-cygwin"
OS_CFLAGS="-mno-cygwin"
;;
MINGW32*)
mingw32="yes"
@@ -124,6 +127,10 @@ oss="yes"
Darwin)
bsd="yes"
darwin="yes"
darwin_user="yes"
cocoa="yes"
coreaudio="yes"
OS_CFLAGS="-mdynamic-no-pic"
;;
SunOS)
solaris="yes"
@@ -131,7 +138,7 @@ solaris="yes"
*)
oss="yes"
linux="yes"
user="yes"
linux_user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
@@ -148,6 +155,11 @@ if [ "$solaris" = "yes" ] ; then
make="gmake"
install="ginstall"
solarisrev=`uname -r | cut -f2 -d.`
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
if test "$solarisrev" -gt 10 ; then
kqemu="yes"
fi
fi
fi
# find source path
@@ -178,6 +190,7 @@ for opt do
--cross-prefix=*) cross_prefix="$optarg"
;;
--cc=*) cc="$optarg"
gcc3_search="no"
;;
--host-cc=*) host_cc="$optarg"
;;
@@ -211,7 +224,7 @@ for opt do
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
;;
--disable-slirp) slirp="no"
;;
@@ -221,8 +234,6 @@ for opt do
;;
--enable-profiler) profiler="yes"
;;
--kernel-path=*) kernel_path="$optarg"
;;
--enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
@@ -233,17 +244,22 @@ for opt do
;;
--enable-system) softmmu="yes"
;;
--disable-user) user="no"
--disable-linux-user) linux_user="no"
;;
--enable-user) user="yes"
--enable-linux-user) linux_user="yes"
;;
--disable-darwin-user) darwin_user="no"
;;
--enable-darwin-user) darwin_user="yes"
;;
--enable-uname-release=*) uname_release="$optarg"
;;
esac
done
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-O2"
fi
# default flags for all hosts
CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
LDFLAGS="$LDFLAGS -g"
if test x"$show_help" = x"yes" ; then
cat << EOF
@@ -261,7 +277,6 @@ echo " --target-list=LIST set target list [$target_list]"
echo ""
echo "kqemu kernel acceleration support:"
echo " --disable-kqemu disable kqemu support"
echo " --kernel-path=PATH set the kernel path (configure probes it)"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
@@ -280,12 +295,15 @@ echo " --enable-fmod enable FMOD audio driver"
echo " --enabled-dsound enable DirectSound audio driver"
echo " --enable-system enable all system emulation targets"
echo " --disable-system disable all system emulation targets"
echo " --enable-user enable all linux usermode emulation targets"
echo " --disable-user disable all linux usermode emulation targets"
echo " --enable-linux-user enable all linux usermode emulation targets"
echo " --disable-linux-user disable all linux usermode emulation targets"
echo " --enable-darwin-user enable all darwin usermode emulation targets"
echo " --disable-darwin-user disable all darwin usermode emulation targets"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
fi
@@ -293,21 +311,66 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if [ ! -x "`which $cc`" ] ; then
echo "Compiler $cc could not be found"
exit
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) {}
EOF
if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
: C compiler works ok
else
echo "ERROR: \"$cc\" either does not exist or does not work"
exit 1
fi
if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
fi
# Check for gcc4, error if pre-gcc4
if test "$check_gcc" = "yes" ; then
cat > $TMPC <<EOF
#if __GNUC__ < 4
#error gcc3
#endif
int main(){return 0;}
EOF
check_cc() {
which "$1" >&/dev/null
return $?
}
if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
echo "WARNING: \"$cc\" looks like gcc 4.x"
found_compat_cc="no"
if test "$gcc3_search" = "yes" ; then
echo "Looking for gcc 3.x"
for compat_cc in $gcc3_list ; do
if check_cc "$compat_cc" ; then
echo "Found \"$compat_cc\""
cc="$compat_cc"
found_compat_cc="yes"
break
fi
done
if test "$found_compat_cc" = "no" ; then
echo "gcc 3.x not found!"
fi
fi
if test "$found_compat_cc" = "no" ; then
echo "QEMU is known to have problems when compiled with gcc 4.x"
echo "It is recommended that you use gcc 3.x to build QEMU"
echo "To use this compiler anyway, configure with --disable-gcc-check"
exit 1;
fi
fi
fi
#
# Solaris specific configure tool chain decisions
#
@@ -355,8 +418,12 @@ if test -z "$target_list" ; then
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
fi
# the following are Linux specific
if [ "$user" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
if [ "$linux_user" = "yes" ] ; then
target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list"
fi
# the following are Darwin specific
if [ "$darwin_user" = "yes" ] ; then
target_list="i386-darwin-user ppc-darwin-user $target_list"
fi
else
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
@@ -410,23 +477,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
have_gcc3_options="yes"
fi
# Check for gcc4, error if pre-gcc4
if test "$check_gcc" = "yes" ; then
cat > $TMPC <<EOF
#if __GNUC__ < 4
#error gcc3
#endif
int main(){return 0;}
EOF
if $cc -o $TMPO $TMPC 2>/dev/null ; then
echo "ERROR: \"$cc\" looks like gcc 4.x"
echo "QEMU is known to have problems when compiled with gcc 4.x"
echo "It is recommended that you use gcc 3.x to build QEMU"
echo "To use this compiler anyway, configure with --disable-gcc-check"
exit 1;
fi
fi
##########################################
# SDL probe
@@ -455,7 +505,9 @@ _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
if test "$_sdlversion" -lt 121 ; then
sdl_too_old=yes
else
sdl=yes
if test "$cocoa" = "no" ; then
sdl=yes
fi
fi
# static link with sdl ?
@@ -476,8 +528,34 @@ fi # static link
fi # sdl compile test
fi # cross compilation
else
# Make sure to disable cocoa if sdl was set
if test "$sdl" = "yes" ; then
cocoa="no"
coreaudio="no"
fi
fi # -z $sdl
##########################################
# alsa sound support libraries
if test "$alsa" = "yes" ; then
cat > $TMPC << EOF
#include <alsa/asoundlib.h>
int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
EOF
if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then
:
else
echo
echo "Error: Could not find alsa"
echo "Make sure to have the alsa libs and headers installed."
echo
exit 1
fi
fi
# Check if tools are available to build documentation.
if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
build_docs="yes"
@@ -546,6 +624,8 @@ fi
echo "FMOD support $fmod $fmod_support"
echo "kqemu support $kqemu"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -577,6 +657,7 @@ fi
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
echo "LDFLAGS=$LDFLAGS" >> $config_mak
echo "EXESUF=$EXESUF" >> $config_mak
@@ -704,6 +785,8 @@ if [ "$bsd" = "yes" ] ; then
echo "#define _BSD 1" >> $config_h
fi
echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
@@ -716,6 +799,8 @@ target_bigendian="no"
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
[ "$target_cpu" = "m68k" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -725,6 +810,16 @@ if expr $target : '.*-user' > /dev/null ; then
target_user_only="yes"
fi
target_linux_user="no"
if expr $target : '.*-linux-user' > /dev/null ; then
target_linux_user="yes"
fi
target_darwin_user="no"
if expr $target : '.*-darwin-user' > /dev/null ; then
target_darwin_user="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"
@@ -737,7 +832,7 @@ fi
mkdir -p $target_dir
mkdir -p $target_dir/fpu
if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
mkdir -p $target_dir/nwfpe
fi
if test "$target_user_only" = "no" ; then
@@ -758,6 +853,7 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
bflt="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
@@ -772,6 +868,7 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
bflt="yes"
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -802,10 +899,18 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
elif test "$target_cpu" = "sh4" ; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
echo "TARGET_ARCH=sh4" >> $config_mak
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
echo "#define TARGET_SH4 1" >> $config_h
bflt="yes"
elif test "$target_cpu" = "m68k" ; then
echo "TARGET_ARCH=m68k" >> $config_mak
echo "#define TARGET_ARCH \"m68k\"" >> $config_h
echo "#define TARGET_M68K 1" >> $config_h
bflt="yes"
else
echo "Unsupported target CPU"
exit 1
@@ -822,11 +927,23 @@ if test "$target_user_only" = "yes" ; then
echo "CONFIG_USER_ONLY=yes" >> $config_mak
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
if test "$target_linux_user" = "yes" ; then
echo "CONFIG_LINUX_USER=yes" >> $config_mak
echo "#define CONFIG_LINUX_USER 1" >> $config_h
fi
if test "$target_darwin_user" = "yes" ; then
echo "CONFIG_DARWIN_USER=yes" >> $config_mak
echo "#define CONFIG_DARWIN_USER 1" >> $config_h
fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=yes" >> $config_mak
echo "#define TARGET_HAS_BFLT 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then

370
console.c
View File

@@ -27,8 +27,8 @@
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
typedef struct TextAttributes {
uint8_t fgcol:4;
@@ -53,6 +53,57 @@ enum TTYState {
TTY_STATE_CSI,
};
typedef struct QEMUFIFO {
uint8_t *buf;
int buf_size;
int count, wptr, rptr;
} QEMUFIFO;
int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
{
int l, len;
l = f->buf_size - f->count;
if (len1 > l)
len1 = l;
len = len1;
while (len > 0) {
l = f->buf_size - f->wptr;
if (l > len)
l = len;
memcpy(f->buf + f->wptr, buf, l);
f->wptr += l;
if (f->wptr >= f->buf_size)
f->wptr = 0;
buf += l;
len -= l;
}
f->count += len1;
return len1;
}
int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
{
int l, len;
if (len1 > f->count)
len1 = f->count;
len = len1;
while (len > 0) {
l = f->buf_size - f->rptr;
if (l > len)
l = len;
memcpy(buf, f->buf + f->rptr, l);
f->rptr += l;
if (f->rptr >= f->buf_size)
f->rptr = 0;
buf += l;
len -= l;
}
f->count -= len1;
return len1;
}
/* ??? This is mis-named.
It is used for both text and graphical consoles. */
struct TextConsole {
@@ -70,6 +121,7 @@ struct TextConsole {
int total_height;
int backscroll_height;
int x, y;
int x_saved, y_saved;
int y_displayed;
int y_base;
TextAttributes t_attrib_default; /* default text attributes */
@@ -80,9 +132,11 @@ struct TextConsole {
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
/* kbd read handler */
IOReadHandler *fd_read;
void *fd_opaque;
CharDriverState *chr;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
QEMUTimer *kbd_timer;
};
static TextConsole *active_console;
@@ -91,7 +145,7 @@ static int nb_consoles = 0;
void vga_hw_update(void)
{
if (active_console->hw_update)
if (active_console && active_console->hw_update)
active_console->hw_update(active_console->hw);
}
@@ -274,24 +328,24 @@ enum color_names {
static const uint32_t color_table_rgb[2][8] = {
{ /* dark */
RGB(0x00, 0x00, 0x00), /* black */
RGB(0xaa, 0x00, 0x00), /* red */
RGB(0x00, 0xaa, 0x00), /* green */
RGB(0xaa, 0xaa, 0x00), /* yellow */
RGB(0x00, 0x00, 0xaa), /* blue */
RGB(0xaa, 0x00, 0xaa), /* magenta */
RGB(0x00, 0xaa, 0xaa), /* cyan */
RGB(0xaa, 0xaa, 0xaa), /* white */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xaa, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xaa, 0x00), /* green */
QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
},
{ /* bright */
RGB(0x00, 0x00, 0x00), /* black */
RGB(0xff, 0x00, 0x00), /* red */
RGB(0x00, 0xff, 0x00), /* green */
RGB(0xff, 0xff, 0x00), /* yellow */
RGB(0x00, 0x00, 0xff), /* blue */
RGB(0xff, 0x00, 0xff), /* magenta */
RGB(0x00, 0xff, 0xff), /* cyan */
RGB(0xff, 0xff, 0xff), /* white */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xff, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xff, 0x00), /* green */
QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xff), /* blue */
QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
};
@@ -563,7 +617,6 @@ static void console_put_lf(TextConsole *s)
TextCell *c;
int x, y1;
s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
@@ -604,10 +657,6 @@ static void console_handle_escape(TextConsole *s)
{
int i;
if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
s->t_attrib = s->t_attrib_default;
return;
}
for (i=0; i<s->nb_esc_params; i++) {
switch (s->esc_params[i]) {
case 0: /* reset all console attributes to default */
@@ -697,10 +746,21 @@ static void console_handle_escape(TextConsole *s)
}
}
static void console_clear_xy(TextConsole *s, int x, int y)
{
int y1 = (s->y_base + y) % s->total_height;
TextCell *c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c++;
update_xy(s, x, y);
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
int y1, i, x;
int y1, i;
int x, y;
switch(s->state) {
case TTY_STATE_NORM:
@@ -712,15 +772,12 @@ static void console_putchar(TextConsole *s, int ch)
console_put_lf(s);
break;
case '\b': /* backspace */
if(s->x > 0) s->x--;
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ' ';
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
if (s->x > 0)
s->x--;
break;
case '\t': /* tabspace */
if (s->x + (8 - (s->x % 8)) > s->width) {
s->x = 0;
console_put_lf(s);
} else {
s->x = s->x + (8 - (s->x % 8));
@@ -729,18 +786,31 @@ static void console_putchar(TextConsole *s, int ch)
case '\a': /* alert aka. bell */
/* TODO: has to be implemented */
break;
case 14:
/* SI (shift in), character set 0 (ignored) */
break;
case 15:
/* SO (shift out), character set 1 (ignored) */
break;
case 27: /* esc (introducing an escape sequence) */
s->state = TTY_STATE_ESC;
break;
default:
if (s->x >= s->width - 1) {
break;
}
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ch;
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width)
#if 0 /* line wrap disabled */
if (s->x >= s->width) {
s->x = 0;
console_put_lf(s);
}
#endif
break;
}
break;
@@ -764,32 +834,150 @@ static void console_putchar(TextConsole *s, int ch)
s->nb_esc_params++;
if (ch == ';')
break;
#ifdef DEBUG_CONSOLE
fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
#endif
s->state = TTY_STATE_NORM;
switch(ch) {
case 'D':
if (s->x > 0)
s->x--;
break;
case 'C':
if (s->x < (s->width - 1))
s->x++;
break;
case 'K':
/* clear to eol */
y1 = (s->y_base + s->y) % s->total_height;
for(x = s->x; x < s->width; x++) {
c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c++;
update_xy(s, x, s->y);
case 'A':
/* move cursor up */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
s->y -= s->esc_params[0];
if (s->y < 0) {
s->y = 0;
}
break;
default:
case 'B':
/* move cursor down */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
s->y += s->esc_params[0];
if (s->y >= s->height) {
s->y = s->height - 1;
}
break;
case 'C':
/* move cursor right */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
s->x += s->esc_params[0];
if (s->x >= s->width) {
s->x = s->width - 1;
}
break;
case 'D':
/* move cursor left */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
s->x -= s->esc_params[0];
if (s->x < 0) {
s->x = 0;
}
break;
case 'G':
/* move cursor to column */
s->x = s->esc_params[0] - 1;
if (s->x < 0) {
s->x = 0;
}
break;
case 'f':
case 'H':
/* move cursor to row, column */
s->x = s->esc_params[1] - 1;
if (s->x < 0) {
s->x = 0;
}
s->y = s->esc_params[0] - 1;
if (s->y < 0) {
s->y = 0;
}
break;
case 'J':
switch (s->esc_params[0]) {
case 0:
/* clear to end of screen */
for (y = s->y; y < s->height; y++) {
for (x = 0; x < s->width; x++) {
if (y == s->y && x < s->x) {
continue;
}
console_clear_xy(s, x, y);
}
}
break;
case 1:
/* clear from beginning of screen */
for (y = 0; y <= s->y; y++) {
for (x = 0; x < s->width; x++) {
if (y == s->y && x > s->x) {
break;
}
console_clear_xy(s, x, y);
}
}
break;
case 2:
/* clear entire screen */
for (y = 0; y <= s->height; y++) {
for (x = 0; x < s->width; x++) {
console_clear_xy(s, x, y);
}
}
break;
}
case 'K':
switch (s->esc_params[0]) {
case 0:
/* clear to eol */
for(x = s->x; x < s->width; x++) {
console_clear_xy(s, x, s->y);
}
break;
case 1:
/* clear from beginning of line */
for (x = 0; x <= s->x; x++) {
console_clear_xy(s, x, s->y);
}
break;
case 2:
/* clear entire line */
for(x = 0; x < s->width; x++) {
console_clear_xy(s, x, s->y);
}
break;
}
break;
case 'm':
console_handle_escape(s);
break;
case 'n':
/* report cursor position */
/* TODO: send ESC[row;colR */
break;
case 's':
/* save cursor position */
s->x_saved = s->x;
s->y_saved = s->y;
break;
case 'u':
/* restore cursor position */
s->x = s->x_saved;
s->y = s->y_saved;
break;
default:
#ifdef DEBUG_CONSOLE
fprintf(stderr, "unhandled escape character '%c'\n", ch);
#endif
break;
}
break;
}
}
}
@@ -830,15 +1018,6 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
return len;
}
static void console_chr_add_read_handler(CharDriverState *chr,
IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
static void console_send_event(CharDriverState *chr, int event)
{
TextConsole *s = chr->opaque;
@@ -854,6 +1033,28 @@ static void console_send_event(CharDriverState *chr, int event)
}
}
static void kbd_send_chars(void *opaque)
{
TextConsole *s = opaque;
int len;
uint8_t buf[16];
len = qemu_chr_can_read(s->chr);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
if (len > 0) {
if (len > sizeof(buf))
len = sizeof(buf);
qemu_fifo_read(&s->out_fifo, buf, len);
qemu_chr_read(s->chr, buf, len);
}
/* characters are pending: we send them a bit later (XXX:
horrible, should change char device API) */
if (s->out_fifo.count > 0) {
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
@@ -879,25 +1080,26 @@ void kbd_put_keysym(int keysym)
console_scroll(10);
break;
default:
if (s->fd_read) {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
*q++ = keysym;
}
s->fd_read(s->fd_opaque, buf, q - buf);
}
if (s->chr->chr_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
}
break;
}
@@ -971,9 +1173,13 @@ CharDriverState *text_console_init(DisplayState *ds)
}
chr->opaque = s;
chr->chr_write = console_puts;
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
s->chr = chr;
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
if (!color_inited) {
color_inited = 1;
for(j = 0; j < 2; j++) {
@@ -1004,5 +1210,7 @@ CharDriverState *text_console_init(DisplayState *ds)
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
qemu_chr_reset(chr);
return chr;
}

120
cpu-all.h
View File

@@ -725,6 +725,13 @@ void page_unprotect_range(target_ulong data, target_ulong data_size);
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_signal_handler cpu_ppc_signal_handler
#elif defined(TARGET_M68K)
#define CPUState CPUM68KState
#define cpu_init cpu_m68k_init
#define cpu_exec cpu_m68k_exec
#define cpu_gen_code cpu_m68k_gen_code
#define cpu_signal_handler cpu_m68k_signal_handler
#elif defined(TARGET_MIPS)
#define CPUState CPUMIPSState
#define cpu_init cpu_mips_init
@@ -762,6 +769,7 @@ extern int code_copy_enabled;
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */
void cpu_interrupt(CPUState *s, int mask);
void cpu_reset_interrupt(CPUState *env, int mask);
@@ -828,6 +836,10 @@ extern uint8_t *phys_ram_dirty;
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
/* acts like a ROM when read and like a device when written. As an
exception, the write memory callback gets the ram offset instead of
the physical address */
#define IO_MEM_ROMD (1)
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
@@ -835,6 +847,7 @@ typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset);
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
@@ -896,15 +909,116 @@ void cpu_tlb_update_dirty(CPUState *env);
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
/* profiling */
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
/*******************************************/
/* host CPU ticks (if available) */
#if defined(__powerpc__)
static inline uint32_t get_tbl(void)
{
uint32_t tbl;
asm volatile("mftb %0" : "=r" (tbl));
return tbl;
}
static inline uint32_t get_tbu(void)
{
uint32_t tbl;
asm volatile("mftbu %0" : "=r" (tbl));
return tbl;
}
static inline int64_t cpu_get_real_ticks(void)
{
uint32_t l, h, h1;
/* NOTE: we test if wrapping has occurred */
do {
h = get_tbu();
l = get_tbl();
h1 = get_tbu();
} while (h != h1);
return ((int64_t)h << 32) | l;
}
#elif defined(__i386__)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("rdtsc" : "=A" (val));
return val;
}
#elif defined(__x86_64__)
static inline int64_t cpu_get_real_ticks(void)
{
uint32_t low,high;
int64_t val;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
val = high;
val <<= 32;
val |= low;
return val;
}
#elif defined(__ia64)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
return val;
}
#elif defined(__s390__)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
return val;
}
#elif defined(__sparc_v9__)
static inline int64_t cpu_get_real_ticks (void)
{
#if defined(_LP64)
uint64_t rval;
asm volatile("rd %%tick,%0" : "=r"(rval));
return rval;
#else
union {
uint64_t i64;
struct {
uint32_t high;
uint32_t low;
} i32;
} rval;
asm volatile("rd %%tick,%1; srlx %1,32,%0"
: "=r"(rval.i32.high), "=r"(rval.i32.low));
return rval.i64;
#endif
}
#else
/* The host CPU doesn't have an easily accessible cycle counter.
Just return a monotonically increasing vlue. This will be totally wrong,
but hopefully better than nothing. */
static inline int64_t cpu_get_real_ticks (void)
{
static int64_t ticks = 0;
return ticks++;
}
#endif
/* profiling */
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
{
return cpu_get_real_ticks();
}
extern int64_t kqemu_time, kqemu_time_start;
extern int64_t qemu_time, qemu_time_start;
extern int64_t tlb_flush_time;

View File

@@ -47,7 +47,7 @@ typedef uint32_t target_ulong;
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016llx"
#define TARGET_FMT_lx "%016" PRIx64
#else
#error TARGET_LONG_SIZE undefined
#endif
@@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t;
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
addresses on the same page. The top bits are the same. This allows
TLB invalidation to quickly clear a subset of the hash table. */
#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
#define CPU_TLB_BITS 8
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)

View File

@@ -40,14 +40,14 @@ int tb_invalidated_flag;
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
#endif
#ifndef TARGET_SPARC
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
#define reg_T2
#endif
@@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_fast(void)
pc = env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
// Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
| (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
#else
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
// FPU enable . MMU enabled . MMU no-fault . Supervisor
flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
| env->psrs;
#endif
cs_base = env->npc;
pc = env->pc;
@@ -190,6 +194,10 @@ static inline TranslationBlock *tb_find_fast(void)
flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
cs_base = 0;
pc = env->PC;
#elif defined(TARGET_M68K)
flags = env->fpcr & M68K_FPCR_PREC;
cs_base = 0;
pc = env->pc;
#elif defined(TARGET_SH4)
flags = env->sr & (SR_MD | SR_RB);
cs_base = 0; /* XXXXX */
@@ -218,43 +226,16 @@ static inline TranslationBlock *tb_find_fast(void)
int cpu_exec(CPUState *env1)
{
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
#ifdef reg_ECX
int saved_ECX;
#endif
#ifdef reg_EDX
int saved_EDX;
#endif
#ifdef reg_EBX
int saved_EBX;
#endif
#ifdef reg_ESP
int saved_ESP;
#endif
#ifdef reg_EBP
int saved_EBP;
#endif
#ifdef reg_ESI
int saved_ESI;
#endif
#ifdef reg_EDI
int saved_EDI;
#endif
#elif defined(TARGET_SPARC)
#define DECLARE_HOST_REGS 1
#include "hostregs_helper.h"
#if defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
uint32_t *saved_regwptr;
#endif
#endif
#ifdef __sparc__
int saved_i7, tmp_T0;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
int saved_i7;
target_ulong tmp_T0;
#endif
int ret, interrupt_request;
void (*gen_func)(void);
@@ -316,44 +297,15 @@ int cpu_exec(CPUState *env1)
cpu_single_env = env1;
/* first we save global registers */
saved_env = env;
#define SAVE_HOST_REGS 1
#include "hostregs_helper.h"
env = env1;
saved_T0 = T0;
saved_T1 = T1;
#if defined(reg_T2)
saved_T2 = T2;
#endif
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif
#if defined(TARGET_I386)
#ifdef reg_EAX
saved_EAX = EAX;
#endif
#ifdef reg_ECX
saved_ECX = ECX;
#endif
#ifdef reg_EDX
saved_EDX = EDX;
#endif
#ifdef reg_EBX
saved_EBX = EBX;
#endif
#ifdef reg_ESP
saved_ESP = ESP;
#endif
#ifdef reg_EBP
saved_EBP = EBP;
#endif
#ifdef reg_ESI
saved_ESI = ESI;
#endif
#ifdef reg_EDI
saved_EDI = EDI;
#endif
env_to_regs();
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
@@ -366,6 +318,10 @@ int cpu_exec(CPUState *env1)
saved_regwptr = REGWPTR;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_M68K)
env->cc_op = CC_OP_FLAGS;
env->cc_dest = env->sr & 0xf;
env->cc_x = (env->sr >> 4) & 1;
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
@@ -386,7 +342,7 @@ int cpu_exec(CPUState *env1)
break;
} else if (env->user_mode_only) {
/* if user mode only, we simulate a fake exception
which will be hanlded outside the cpu execution
which will be handled outside the cpu execution
loop */
#if defined(TARGET_I386)
do_interrupt_user(env->exception_index,
@@ -447,15 +403,23 @@ int cpu_exec(CPUState *env1)
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
interrupt_request = env->interrupt_request;
if (__builtin_expect(interrupt_request, 0)) {
#if defined(TARGET_I386)
/* if hardware interrupt pending, we execute it */
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
!(env->hflags & HF_SMM_MASK)) {
env->interrupt_request &= ~CPU_INTERRUPT_SMI;
do_smm_enter();
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
int intno;
@@ -467,7 +431,7 @@ int cpu_exec(CPUState *env1)
do_interrupt(intno, 0, 0, 0, 1);
/* ensure that no TB jump will be modified as
the program flow was changed */
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -486,7 +450,7 @@ int cpu_exec(CPUState *env1)
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -497,7 +461,7 @@ int cpu_exec(CPUState *env1)
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -515,8 +479,7 @@ int cpu_exec(CPUState *env1)
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -534,7 +497,7 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
do_interrupt(env->interrupt_index);
env->interrupt_index = 0;
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -544,8 +507,10 @@ int cpu_exec(CPUState *env1)
//do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
env1->halted = 1;
return EXCP_HALTED;
env->interrupt_request &= ~CPU_INTERRUPT_HALT;
env->halted = 1;
env->exception_index = EXCP_HLT;
cpu_loop_exit();
}
#elif defined(TARGET_ARM)
if (interrupt_request & CPU_INTERRUPT_FIQ
@@ -561,11 +526,13 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_SH4)
/* XXXXX */
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
@@ -616,6 +583,12 @@ int cpu_exec(CPUState *env1)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_PPC)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_M68K)
cpu_m68k_flush_flags(env, env->cc_op);
env->cc_op = CC_OP_FLAGS;
env->sr = (env->sr & 0xffe0)
| env->cc_dest | (env->cc_x << 4);
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_MIPS)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_SH4)
@@ -633,7 +606,7 @@ int cpu_exec(CPUState *env1)
lookup_symbol(tb->pc));
}
#endif
#ifdef __sparc__
#if defined(__sparc__) && !defined(HOST_SOLARIS)
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. When the TB
@@ -669,7 +642,9 @@ int cpu_exec(CPUState *env1)
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
: "i0", "i1", "i2", "i3", "i4", "i5",
"l0", "l1", "l2", "l3", "l4", "l5",
"l6", "l7");
#elif defined(__arm__)
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
@@ -795,32 +770,6 @@ int cpu_exec(CPUState *env1)
#endif
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
EAX = saved_EAX;
#endif
#ifdef reg_ECX
ECX = saved_ECX;
#endif
#ifdef reg_EDX
EDX = saved_EDX;
#endif
#ifdef reg_EBX
EBX = saved_EBX;
#endif
#ifdef reg_ESP
ESP = saved_ESP;
#endif
#ifdef reg_EBP
EBP = saved_EBP;
#endif
#ifdef reg_ESI
ESI = saved_ESI;
#endif
#ifdef reg_EDI
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_SPARC)
@@ -828,21 +777,24 @@ int cpu_exec(CPUState *env1)
REGWPTR = saved_regwptr;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_M68K)
cpu_m68k_flush_flags(env, env->cc_op);
env->cc_op = CC_OP_FLAGS;
env->sr = (env->sr & 0xffe0)
| env->cc_dest | (env->cc_x << 4);
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
#else
#error unsupported target CPU
#endif
#ifdef __sparc__
/* restore global registers */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
T0 = saved_T0;
T1 = saved_T1;
#if defined(reg_T2)
T2 = saved_T2;
#endif
env = saved_env;
#include "hostregs_helper.h"
/* fail safe : never use cpu_single_env outside cpu_exec() */
cpu_single_env = NULL;
return ret;
@@ -1085,6 +1037,45 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
return 1;
}
#elif defined(TARGET_M68K)
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_m68k_handle_mmu_fault(env, address, is_write, 1, 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);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* 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,
@@ -1168,19 +1159,14 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
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);
}
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
@@ -1190,6 +1176,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
#if defined(__i386__)
#if defined(__APPLE__)
# include <sys/ucontext.h>
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
#else
# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
#endif
#if defined(USE_CODE_COPY)
static void cpu_send_trap(unsigned long pc, int trap,
struct ucontext *uc)
@@ -1210,9 +1208,10 @@ static void cpu_send_trap(unsigned long pc, int trap,
}
#endif
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int trapno;
@@ -1223,8 +1222,8 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
pc = EIP_sig(uc);
trapno = TRAP_sig(uc);
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
if (trapno == 0x00 || trapno == 0x05) {
/* send division by zero or bound exception */
@@ -1234,15 +1233,16 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
trapno == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
(ERROR_sig(uc) >> 1) & 1 : 0,
&uc->uc_sigmask, puc);
}
#elif defined(__x86_64__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
@@ -1304,9 +1304,10 @@ typedef struct ucontext SIGCONTEXT;
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
#endif /* __APPLE__ */
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
@@ -1327,9 +1328,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#elif defined(__alpha__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
uint32_t *pc = uc->uc_mcontext.sc_pc;
uint32_t insn = *pc;
@@ -1356,9 +1358,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
}
#elif defined(__sparc__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
uint32_t *regs = (uint32_t *)(info + 1);
void *sigmask = (regs + 20);
unsigned long pc;
@@ -1389,9 +1392,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#elif defined(__arm__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
@@ -1401,14 +1405,15 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
&uc->uc_sigmask, puc);
}
#elif defined(__mc68000)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
@@ -1428,8 +1433,9 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
# define __ISR_VALID 1
#endif
int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long ip;
int is_write = 0;
@@ -1456,9 +1462,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
#elif defined(__s390__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int is_write;

83
cutils.c Normal file
View File

@@ -0,0 +1,83 @@
/*
* Simple C functions to supplement the C library
*
* Copyright (c) 2006 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"
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
/* strcat and truncate. */
char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
}
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
int stristart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (toupper(*p) != toupper(*q))
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}

358
darwin-user/commpage.c Normal file
View File

@@ -0,0 +1,358 @@
/*
* Commpage syscalls
*
* Copyright (c) 2006 Pierre d'Herbemont
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <mach/message.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <libkern/OSAtomic.h>
#include "qemu.h"
//#define DEBUG_COMMPAGE
#ifdef DEBUG_COMMPAGE
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
#else
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
#endif
/********************************************************************
* Commpage definitions
*/
#ifdef TARGET_I386
/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
#elif defined(TARGET_PPC)
/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
# define COMMPAGE_START (-8*4096)
# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
#endif
void do_compare_and_swap32(void *cpu_env, int num);
void do_compare_and_swap64(void *cpu_env, int num);
void do_add_atomic_word32(void *cpu_env, int num);
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
void do_nanotime(void *cpu_env, int num);
void unimpl_commpage(void *cpu_env, int num);
typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
uint32_t arg8);
typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
uint32_t arg6, uint32_t arg7, uint32_t arg8);
#define HAS_PTR 0x10
#define NO_PTR 0x20
#define CALL_DIRECT 0x1
#define CALL_INDIRECT 0x2
#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
{ #name, offset, nargs, options, (commpage_8args_function_t)func }
struct commpage_entry {
char * name;
int offset;
int nargs;
char options;
commpage_8args_function_t function;
};
static inline int commpage_code_num(struct commpage_entry *entry)
{
if((entry->options & HAS_PTR))
return entry->offset + 4;
else
return entry->offset;
}
static inline int commpage_is_indirect(struct commpage_entry *entry)
{
return !(entry->options & CALL_DIRECT);
}
/********************************************************************
* Commpage entry
*/
static struct commpage_entry commpage_entries[] =
{
COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR),
COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT),
COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT),
COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(gettimeofday, 1, 0x2e0, do_cgettimeofday, CALL_INDIRECT),
COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x4e0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(pthread_self, 0, 0x580, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT),
#ifdef TARGET_I386
COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT),
#endif
COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT),
COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT),
COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT),
#ifdef TARGET_I386
COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT),
COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT),
#elif TARGET_PPC
COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT),
COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT),
#endif
};
/********************************************************************
* Commpage backdoor
*/
static inline void print_commpage_entry(struct commpage_entry entry)
{
printf("@0x%x %s\n", entry.offset, entry.name);
}
static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
{
#ifdef TARGET_I386
char * commpage = (char*)(COMMPAGE_START+entry.offset);
int c = 0;
if(entry.options & HAS_PTR)
{
commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
}
commpage[c++] = 0xcd;
commpage[c++] = 0x79; /* int 0x79 */
commpage[c++] = 0xc3; /* ret */
#else
qerror("can't install the commpage on this arch\n");
#endif
}
/********************************************************************
* Commpage initialization
*/
void commpage_init(void)
{
#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC))
int i;
void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if((int)commpage != COMMPAGE_START)
qerror("can't allocate the commpage\n");
bzero(commpage, COMMPAGE_SIZE);
/* XXX: commpage data not handled */
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
install_commpage_backdoor_for_entry(commpage_entries[i]);
#else
/* simply map our pages so they can be executed
XXX: we don't really want to do that since in the ppc on ppc situation we may
not able to run commpages host optimized instructions (like G5's on a G5),
hence this is sometimes a broken fix. */
page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
#endif
}
/********************************************************************
* Commpage implementation
*/
void do_compare_and_swap32(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
if(value && old == tswap32(*value))
{
uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
*value = tswap32(new);
/* set zf flag */
((CPUX86State*)cpu_env)->eflags |= 0x40;
}
else
{
((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
/* unset zf flag */
((CPUX86State*)cpu_env)->eflags &= ~0x40;
}
#else
qerror("do_compare_and_swap32 unimplemented");
#endif
}
void do_compare_and_swap64(void *cpu_env, int num)
{
#ifdef TARGET_I386
/* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
uint64_t old, new, swapped_val;
uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
swapped_val = tswap64(*value);
if(old == swapped_val)
{
new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
*value = tswap64(new);
/* set zf flag */
((CPUX86State*)cpu_env)->eflags |= 0x40;
}
else
{
((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
/* unset zf flag */
((CPUX86State*)cpu_env)->eflags &= ~0x40;
}
#else
qerror("do_compare_and_swap64 unimplemented");
#endif
}
void do_add_atomic_word32(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
uint32_t swapped_value = tswap32(*value);
DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
/* old value in EAX */
((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
*value = tswap32(swapped_value + amt);
#else
qerror("do_add_atomic_word32 unimplemented");
#endif
}
void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
{
#ifdef TARGET_I386
extern int __commpage_gettimeofday(struct timeval *);
DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
struct timeval *time = (struct timeval *)arg1;
int ret = __commpage_gettimeofday(time);
tswap32s((uint32_t*)&time->tv_sec);
tswap32s((uint32_t*)&time->tv_usec);
((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
#else
qerror("do_gettimeofday unimplemented");
#endif
}
void do_nanotime(void *cpu_env, int num)
{
#ifdef TARGET_I386
uint64_t t = mach_absolute_time();
((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
#else
qerror("do_nanotime unimplemented");
#endif
}
void unimpl_commpage(void *cpu_env, int num)
{
qerror("qemu: commpage function 0x%x not implemented\n", num);
}
/********************************************************************
* do_commpage - called by the main cpu loop
*/
void
do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
uint32_t arg8)
{
int i, found = 0;
arg1 = tswap32(arg1);
arg2 = tswap32(arg2);
arg3 = tswap32(arg3);
arg4 = tswap32(arg4);
arg5 = tswap32(arg5);
arg6 = tswap32(arg6);
arg7 = tswap32(arg7);
arg8 = tswap32(arg8);
num = num-COMMPAGE_START-2;
for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
if( num == commpage_code_num(&commpage_entries[i]) )
{
DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
found = 1;
if(commpage_is_indirect(&commpage_entries[i]))
{
commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
function(cpu_env, num, arg1, arg2, arg3,
arg4, arg5, arg6, arg7, arg8);
}
else
{
commpage_entries[i].function(arg1, arg2, arg3,
arg4, arg5, arg6, arg7, arg8);
}
break;
}
}
if(!found)
{
gemu_log("qemu: commpage function 0x%x not defined\n", num);
gdb_handlesig (cpu_env, SIGTRAP);
exit(-1);
}
}

4
darwin-user/ioctls.h Normal file
View File

@@ -0,0 +1,4 @@
/* emulated ioctl list */
IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))

View File

@@ -0,0 +1 @@
STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)

903
darwin-user/machload.c Normal file
View File

@@ -0,0 +1,903 @@
/*
* Mach-O object file loading
*
* Copyright (c) 2006 Pierre d'Herbemont
*
* 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 <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include "qemu.h"
#include "disas.h"
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/ppc/reloc.h>
//#define DEBUG_MACHLOAD
#ifdef DEBUG_MACHLOAD
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
#else
# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
#endif
# define check_mach_header(x) (x.magic == MH_CIGAM)
extern const char *interp_prefix;
/* we don't have a good implementation for this */
#define DONT_USE_DYLD_SHARED_MAP
/* Pass extra arg to DYLD for debug */
//#define ACTIVATE_DYLD_TRACE
//#define OVERRIDE_DYLINKER
#ifdef OVERRIDE_DYLINKER
# ifdef TARGET_I386
# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld"
# else
# define DYLINKER_NAME "/usr/lib/dyld"
# endif
#endif
/* XXX: in an include */
struct nlist_extended
{
union {
char *n_name;
long n_strx;
} n_un;
unsigned char n_type;
unsigned char n_sect;
short st_desc;
unsigned long st_value;
unsigned long st_size;
};
/* Print symbols in gdb */
void *macho_text_sect = 0;
int macho_offset = 0;
int load_object(const char *filename, struct target_pt_regs * regs, void ** mh);
void qerror(const char *format, ...);
#ifdef TARGET_I386
typedef struct mach_i386_thread_state {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int edi;
unsigned int esi;
unsigned int ebp;
unsigned int esp;
unsigned int ss;
unsigned int eflags;
unsigned int eip;
unsigned int cs;
unsigned int ds;
unsigned int es;
unsigned int fs;
unsigned int gs;
} mach_i386_thread_state_t;
void bswap_i386_thread_state(struct mach_i386_thread_state *ts)
{
bswap32s((uint32_t*)&ts->eax);
bswap32s((uint32_t*)&ts->ebx);
bswap32s((uint32_t*)&ts->ecx);
bswap32s((uint32_t*)&ts->edx);
bswap32s((uint32_t*)&ts->edi);
bswap32s((uint32_t*)&ts->esi);
bswap32s((uint32_t*)&ts->ebp);
bswap32s((uint32_t*)&ts->esp);
bswap32s((uint32_t*)&ts->ss);
bswap32s((uint32_t*)&ts->eflags);
bswap32s((uint32_t*)&ts->eip);
bswap32s((uint32_t*)&ts->cs);
bswap32s((uint32_t*)&ts->ds);
bswap32s((uint32_t*)&ts->es);
bswap32s((uint32_t*)&ts->fs);
bswap32s((uint32_t*)&ts->gs);
}
#define target_thread_state mach_i386_thread_state
#define TARGET_CPU_TYPE CPU_TYPE_I386
#define TARGET_CPU_NAME "i386"
#endif
#ifdef TARGET_PPC
struct mach_ppc_thread_state {
unsigned int srr0; /* Instruction address register (PC) */
unsigned int srr1; /* Machine state register (supervisor) */
unsigned int r0;
unsigned int r1;
unsigned int r2;
unsigned int r3;
unsigned int r4;
unsigned int r5;
unsigned int r6;
unsigned int r7;
unsigned int r8;
unsigned int r9;
unsigned int r10;
unsigned int r11;
unsigned int r12;
unsigned int r13;
unsigned int r14;
unsigned int r15;
unsigned int r16;
unsigned int r17;
unsigned int r18;
unsigned int r19;
unsigned int r20;
unsigned int r21;
unsigned int r22;
unsigned int r23;
unsigned int r24;
unsigned int r25;
unsigned int r26;
unsigned int r27;
unsigned int r28;
unsigned int r29;
unsigned int r30;
unsigned int r31;
unsigned int cr; /* Condition register */
unsigned int xer; /* User's integer exception register */
unsigned int lr; /* Link register */
unsigned int ctr; /* Count register */
unsigned int mq; /* MQ register (601 only) */
unsigned int vrsave; /* Vector Save Register */
};
void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts)
{
bswap32s((uint32_t*)&ts->srr0);
bswap32s((uint32_t*)&ts->srr1);
bswap32s((uint32_t*)&ts->r0);
bswap32s((uint32_t*)&ts->r1);
bswap32s((uint32_t*)&ts->r2);
bswap32s((uint32_t*)&ts->r3);
bswap32s((uint32_t*)&ts->r4);
bswap32s((uint32_t*)&ts->r5);
bswap32s((uint32_t*)&ts->r6);
bswap32s((uint32_t*)&ts->r7);
bswap32s((uint32_t*)&ts->r8);
bswap32s((uint32_t*)&ts->r9);
bswap32s((uint32_t*)&ts->r10);
bswap32s((uint32_t*)&ts->r11);
bswap32s((uint32_t*)&ts->r12);
bswap32s((uint32_t*)&ts->r13);
bswap32s((uint32_t*)&ts->r14);
bswap32s((uint32_t*)&ts->r15);
bswap32s((uint32_t*)&ts->r16);
bswap32s((uint32_t*)&ts->r17);
bswap32s((uint32_t*)&ts->r18);
bswap32s((uint32_t*)&ts->r19);
bswap32s((uint32_t*)&ts->r20);
bswap32s((uint32_t*)&ts->r21);
bswap32s((uint32_t*)&ts->r22);
bswap32s((uint32_t*)&ts->r23);
bswap32s((uint32_t*)&ts->r24);
bswap32s((uint32_t*)&ts->r25);
bswap32s((uint32_t*)&ts->r26);
bswap32s((uint32_t*)&ts->r27);
bswap32s((uint32_t*)&ts->r28);
bswap32s((uint32_t*)&ts->r29);
bswap32s((uint32_t*)&ts->r30);
bswap32s((uint32_t*)&ts->r31);
bswap32s((uint32_t*)&ts->cr);
bswap32s((uint32_t*)&ts->xer);
bswap32s((uint32_t*)&ts->lr);
bswap32s((uint32_t*)&ts->ctr);
bswap32s((uint32_t*)&ts->mq);
bswap32s((uint32_t*)&ts->vrsave);
}
#define target_thread_state mach_ppc_thread_state
#define TARGET_CPU_TYPE CPU_TYPE_POWERPC
#define TARGET_CPU_NAME "PowerPC"
#endif
struct target_thread_command {
unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */
unsigned long cmdsize; /* total size of this command */
unsigned long flavor; /* flavor of thread state */
unsigned long count; /* count of longs in thread state */
struct target_thread_state state; /* thread state for this flavor */
};
void bswap_tc(struct target_thread_command *tc)
{
bswap32s((uint32_t*)(&tc->flavor));
bswap32s((uint32_t*)&tc->count);
#if defined(TARGET_I386)
bswap_i386_thread_state(&tc->state);
#elif defined(TARGET_PPC)
bswap_ppc_thread_state(&tc->state);
#else
# error unknown TARGET_CPU_TYPE
#endif
}
void bswap_mh(struct mach_header *mh)
{
bswap32s((uint32_t*)(&mh->magic));
bswap32s((uint32_t*)&mh->cputype);
bswap32s((uint32_t*)&mh->cpusubtype);
bswap32s((uint32_t*)&mh->filetype);
bswap32s((uint32_t*)&mh->ncmds);
bswap32s((uint32_t*)&mh->sizeofcmds);
bswap32s((uint32_t*)&mh->flags);
}
void bswap_lc(struct load_command *lc)
{
bswap32s((uint32_t*)&lc->cmd);
bswap32s((uint32_t*)&lc->cmdsize);
}
void bswap_fh(struct fat_header *fh)
{
bswap32s((uint32_t*)&fh->magic);
bswap32s((uint32_t*)&fh->nfat_arch);
}
void bswap_fa(struct fat_arch *fa)
{
bswap32s((uint32_t*)&fa->cputype);
bswap32s((uint32_t*)&fa->cpusubtype);
bswap32s((uint32_t*)&fa->offset);
bswap32s((uint32_t*)&fa->size);
bswap32s((uint32_t*)&fa->align);
}
void bswap_segcmd(struct segment_command *sc)
{
bswap32s((uint32_t*)&sc->vmaddr);
bswap32s((uint32_t*)&sc->vmsize);
bswap32s((uint32_t*)&sc->fileoff);
bswap32s((uint32_t*)&sc->filesize);
bswap32s((uint32_t*)&sc->maxprot);
bswap32s((uint32_t*)&sc->initprot);
bswap32s((uint32_t*)&sc->nsects);
bswap32s((uint32_t*)&sc->flags);
}
void bswap_symtabcmd(struct symtab_command *stc)
{
bswap32s((uint32_t*)&stc->cmd);
bswap32s((uint32_t*)&stc->cmdsize);
bswap32s((uint32_t*)&stc->symoff);
bswap32s((uint32_t*)&stc->nsyms);
bswap32s((uint32_t*)&stc->stroff);
bswap32s((uint32_t*)&stc->strsize);
}
void bswap_sym(struct nlist *n)
{
bswap32s((uint32_t*)&n->n_un.n_strx);
bswap16s((uint16_t*)&n->n_desc);
bswap32s((uint32_t*)&n->n_value);
}
int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap)
{
int entry;
if(need_bswap)
bswap_tc(tc);
#if defined(TARGET_I386)
entry = tc->state.eip;
DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n",
tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp,
tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es,
tc->state.fs, tc->state.gs );
#define reg_copy(reg) regs->reg = tc->state.reg
if(regs)
{
reg_copy(eax);
reg_copy(ebx);
reg_copy(ecx);
reg_copy(edx);
reg_copy(edi);
reg_copy(esi);
reg_copy(ebp);
reg_copy(esp);
reg_copy(eflags);
reg_copy(eip);
/*
reg_copy(ss);
reg_copy(cs);
reg_copy(ds);
reg_copy(es);
reg_copy(fs);
reg_copy(gs);*/
}
#undef reg_copy
#elif defined(TARGET_PPC)
entry = tc->state.srr0;
#endif
DPRINTF("load_thread: entry 0x%x\n", entry);
return entry;
}
int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap)
{
int size;
char * dylinker_name;
size = dc->cmdsize - sizeof(struct dylinker_command);
if(need_bswap)
dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc);
else
dylinker_name = (char*)((dc->name.offset)+(int)dc);
#ifdef OVERRIDE_DYLINKER
dylinker_name = DYLINKER_NAME;
#else
if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1)
qerror("can't allocate the new dylinker name\n");
#endif
DPRINTF("dylinker_name %s\n", dylinker_name);
return load_object(dylinker_name, NULL, NULL);
}
int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide)
{
unsigned long addr = sc->vmaddr;
unsigned long size = sc->filesize;
unsigned long error = 0;
if(need_bswap)
bswap_segcmd(sc);
if(sc->vmaddr == 0)
{
DPRINTF("load_segment: sc->vmaddr == 0 returning\n");
return -1;
}
if (strcmp(sc->segname, "__PAGEZERO") == 0)
{
DPRINTF("load_segment: __PAGEZERO returning\n");
return -1;
}
/* Right now mmap memory */
/* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */
DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide);
if(sc->filesize > 0)
{
int opt = 0;
if(fixed)
opt |= MAP_FIXED;
DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide);
addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff);
if(addr==-1)
qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
error = addr-sc->vmaddr;
}
else
{
addr = sc->vmaddr+slide;
error = slide;
}
if(sc->vmsize > sc->filesize)
{
addr += sc->filesize;
size = sc->vmsize-sc->filesize;
addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if(addr==-1)
qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
}
return error;
}
void *load_data(int fd, long offset, unsigned int size)
{
char *data;
data = malloc(size);
if (!data)
return NULL;
lseek(fd, offset, SEEK_SET);
if (read(fd, data, size) != size) {
free(data);
return NULL;
}
return data;
}
/* load a mach-o object file */
int load_object(const char *filename, struct target_pt_regs * regs, void ** mh)
{
int need_bswap = 0;
int entry_point = 0;
int dyld_entry_point = 0;
int slide, mmapfixed;
int fd;
struct load_command *lcmds, *lc;
int is_fat = 0;
unsigned int i, magic;
int mach_hdr_pos = 0;
struct mach_header mach_hdr;
/* for symbol lookup whith -d flag. */
struct symtab_command * symtabcmd = 0;
struct nlist_extended *symtab, *sym;
struct nlist *symtab_std, *syment;
char *strtab;
fd = open(filename, O_RDONLY);
if (fd < 0)
qerror("can't open file '%s'", filename);
/* Read magic header. */
if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
qerror("unable to read Magic of '%s'", filename);
/* Check Mach identification. */
if(magic == MH_MAGIC)
{
is_fat = 0;
need_bswap = 0;
} else if (magic == MH_CIGAM)
{
is_fat = 0;
need_bswap = 1;
} else if (magic == FAT_MAGIC)
{
is_fat = 1;
need_bswap = 0;
} else if (magic == FAT_CIGAM)
{
is_fat = 1;
need_bswap = 1;
}
else
qerror("Not a Mach-O file.", filename);
DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]");
if(is_fat)
{
int found = 0;
struct fat_header fh;
struct fat_arch *fa;
lseek(fd, 0, SEEK_SET);
/* Read Fat header. */
if (read(fd, &fh, sizeof (fh)) != sizeof (fh))
qerror("unable to read file header");
if(need_bswap)
bswap_fh(&fh);
/* Read Fat Arch. */
fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch);
if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch)
qerror("unable to read file header");
for( i = 0; i < fh.nfat_arch; i++, fa++)
{
if(need_bswap)
bswap_fa(fa);
if(fa->cputype == TARGET_CPU_TYPE)
{
mach_hdr_pos = fa->offset;
lseek(fd, mach_hdr_pos, SEEK_SET);
/* Read Mach header. */
if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header))
qerror("unable to read file header");
if(mach_hdr.magic == MH_MAGIC)
need_bswap = 0;
else if (mach_hdr.magic == MH_CIGAM)
need_bswap = 1;
else
qerror("Invalid mach header in Fat Mach-O File");
found = 1;
break;
}
}
if(!found)
qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME);
}
else
{
lseek(fd, 0, SEEK_SET);
/* Read Mach header */
if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
qerror("%s: unable to read file header", filename);
}
if(need_bswap)
bswap_mh(&mach_hdr);
if ((mach_hdr.cputype) != TARGET_CPU_TYPE)
qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME);
switch(mach_hdr.filetype)
{
case MH_EXECUTE: break;
case MH_FVMLIB:
case MH_DYLIB:
case MH_DYLINKER: break;
default:
qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype);
}
/* read segment headers */
lcmds = malloc(mach_hdr.sizeofcmds);
if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds)
qerror("%s: unable to read load_command", filename);
slide = 0;
mmapfixed = 0;
for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++)
{
if(need_bswap)
bswap_lc(lc);
switch(lc->cmd)
{
case LC_SEGMENT:
/* The main_exe can't be relocated */
if(mach_hdr.filetype == MH_EXECUTE)
mmapfixed = 1;
slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide);
/* other segment must be mapped according to slide exactly, if load_segment did something */
if(slide != -1)
mmapfixed = 1;
else
slide = 0; /* load_segment didn't map the segment */
if(mach_hdr.filetype == MH_EXECUTE && slide != 0)
qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide);
if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0)
{
/* Text section */
if(mach_hdr.filetype == MH_EXECUTE)
{
/* return the mach_header */
*mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
}
else
{
/* it is dyld save the section for gdb, we will be interested in dyld symbol
while debuging */
macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
macho_offset = slide;
}
}
break;
case LC_LOAD_DYLINKER:
dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap );
break;
case LC_LOAD_DYLIB:
/* dyld will do that for us */
break;
case LC_THREAD:
case LC_UNIXTHREAD:
{
struct target_pt_regs * _regs;
if(mach_hdr.filetype == MH_DYLINKER)
_regs = regs;
else
_regs = 0;
entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap );
}
break;
case LC_SYMTAB:
/* Save the symtab and strtab */
symtabcmd = (struct symtab_command *)lc;
break;
case LC_ID_DYLINKER:
case LC_ID_DYLIB:
case LC_UUID:
case LC_DYSYMTAB:
case LC_TWOLEVEL_HINTS:
case LC_PREBIND_CKSUM:
case LC_SUB_LIBRARY:
break;
default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename);
}
lc = (struct load_command*)((int)(lc)+(lc->cmdsize));
}
if(symtabcmd)
{
if(need_bswap)
bswap_symtabcmd(symtabcmd);
symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist));
strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize);
symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms);
if(need_bswap)
{
for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++)
bswap_sym(syment);
}
for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++)
{
struct nlist *sym_follow, *sym_next = 0;
unsigned int j;
memset(sym, 0, sizeof(*sym));
sym->n_type = syment->n_type;
if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
continue;
memcpy(sym, syment, sizeof(*syment));
/* Find the following symbol in order to get the current symbol size */
for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) {
if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
continue;
if(!sym_next) {
sym_next = sym_follow;
continue;
}
if(!(sym_next->n_value > sym_follow->n_value))
continue;
sym_next = sym_follow;
}
if(sym_next)
sym->st_size = sym_next->n_value - sym->st_value;
else
sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */
sym->st_value += slide;
}
free((void*)symtab_std);
{
DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms);
struct syminfo *s;
s = malloc(sizeof(*s));
s->disas_symtab = symtab;
s->disas_strtab = strtab;
s->disas_num_syms = symtabcmd->nsyms;
s->next = syminfos;
syminfos = s;
}
}
close(fd);
if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point)
return dyld_entry_point;
else
return entry_point+slide;
}
extern unsigned long stack_size;
unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
{
unsigned long stack_base, error, size;
int i;
int * stack;
int argc, envc;
/* Create enough stack to hold everything. If we don't use
* it for args, we'll use it for something else...
*/
size = stack_size;
error = target_mmap(0,
size + qemu_host_page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (error == -1)
qerror("stk mmap");
/* we reserve one extra page at the top of the stack as guard */
target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
stack_base = error + size;
stack = (void*)stack_base;
/*
* | STRING AREA |
* +-------------+
* | 0 |
* +-------------+
* | apple[n] |
* +-------------+
* :
* +-------------+
* | apple[0] |
* +-------------+
* | 0 |
* +-------------+
* | env[n] |
* +-------------+
* :
* :
* +-------------+
* | env[0] |
* +-------------+
* | 0 |
* +-------------+
* | arg[argc-1] |
* +-------------+
* :
* :
* +-------------+
* | arg[0] |
* +-------------+
* | argc |
* +-------------+
* sp-> | mh | address of where the a.out's file offset 0 is in memory
* +-------------+
*/
/* Construct the stack Stack grows down */
stack--;
/* XXX: string should go up there */
*stack = 0;
stack--;
/* Push the absolute path of our executable */
DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]);
stl(stack, (int) argv[0]);
stack--;
stl(stack, 0);
stack--;
/* Get envc */
for(envc = 0; env[envc]; envc++);
for(i = envc-1; i >= 0; i--)
{
DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]);
stl(stack, (int)env[i]);
stack--;
/* XXX: remove that when string will be on top of the stack */
page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID);
}
/* Add on the stack the interp_prefix choosen if so */
if(interp_prefix[0])
{
char *dyld_root;
asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix);
page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID);
stl(stack, (int)dyld_root);
stack--;
}
#ifdef DONT_USE_DYLD_SHARED_MAP
{
char *shared_map_mode;
asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid");
page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID);
stl(stack, (int)shared_map_mode);
stack--;
}
#endif
#ifdef ACTIVATE_DYLD_TRACE
char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes",
"DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes",
"DYLD_PRINT_INITIALIZERS=yes",
"DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" };
char ** extra_env = malloc(sizeof(extra_env_static));
bcopy(extra_env_static, extra_env, sizeof(extra_env_static));
page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID);
for(i = 0; i<9; i++)
{
DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]);
stl(stack, (int) extra_env[i]);
stack--;
}
#endif
stl(stack, 0);
stack--;
/* Get argc */
for(argc = 0; argv[argc]; argc++);
for(i = argc-1; i >= 0; i--)
{
DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]);
stl(stack, (int) argv[i]);
stack--;
/* XXX: remove that when string will be on top of the stack */
page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
}
DPRINTF("pushing argc %d \n", argc);
stl(stack, argc);
stack--;
DPRINTF("pushing mh 0x%x \n", (int)mh);
stl(stack, (int) mh);
/* Stack points on the mh */
return (unsigned long)stack;
}
int mach_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs)
{
int entrypoint, stack;
void * mh; /* the Mach Header that will be used by dyld */
DPRINTF("mach_exec at 0x%x\n", (int)mach_exec);
entrypoint = load_object(filename, regs, &mh);
stack = setup_arg_pages(mh, argv, envp);
#if defined(TARGET_I386)
regs->eip = entrypoint;
regs->esp = stack;
#elif defined(TARGET_PPC)
regs->nip = entrypoint;
regs->gpr[1] = stack;
#endif
DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh);
if(!entrypoint)
qerror("%s: no entry point!\n", filename);
return 0;
}

918
darwin-user/main.c Normal file
View File

@@ -0,0 +1,918 @@
/*
* qemu user main
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2006 Pierre d'Herbemont
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include "qemu.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
#ifdef __APPLE__
#include <crt_externs.h>
# define environ (*_NSGetEnviron())
#endif
#include <mach/mach_init.h>
#include <mach/vm_map.h>
const char *interp_prefix = "";
asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
unsigned long stack_size = 512 * 1024;
void qerror(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
void gemu_log(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
void cpu_outb(CPUState *env, int addr, int val)
{
fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
}
void cpu_outw(CPUState *env, int addr, int val)
{
fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
}
void cpu_outl(CPUState *env, int addr, int val)
{
fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
}
int cpu_inb(CPUState *env, int addr)
{
fprintf(stderr, "inb: port=0x%04x\n", addr);
return 0;
}
int cpu_inw(CPUState *env, int addr)
{
fprintf(stderr, "inw: port=0x%04x\n", addr);
return 0;
}
int cpu_inl(CPUState *env, int addr)
{
fprintf(stderr, "inl: port=0x%04x\n", addr);
return 0;
}
int cpu_get_pic_interrupt(CPUState *env)
{
return -1;
}
#ifdef TARGET_PPC
static inline uint64_t cpu_ppc_get_tb (CPUState *env)
{
/* TO FIX */
return 0;
}
uint32_t cpu_ppc_load_tbl (CPUState *env)
{
return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
}
uint32_t cpu_ppc_load_tbu (CPUState *env)
{
return cpu_ppc_get_tb(env) >> 32;
}
static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
{
/* TO FIX */
}
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
{
cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
}
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
{
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
}
uint32_t cpu_ppc_load_decr (CPUState *env)
{
/* TO FIX */
return -1;
}
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
{
/* TO FIX */
}
void cpu_loop(CPUPPCState *env)
{
int trapnr;
uint32_t ret;
target_siginfo_t info;
for(;;) {
trapnr = cpu_ppc_exec(env);
if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
trapnr != EXCP_TRACE) {
if (loglevel > 0) {
cpu_dump_state(env, logfile, fprintf, 0);
}
}
switch(trapnr) {
case EXCP_NONE:
break;
case EXCP_SYSCALL_USER:
/* system call */
if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], env->gpr[9], env->gpr[10]*/);
else if(((int)env->gpr[0])<0)
ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], env->gpr[9], env->gpr[10]);
else
ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], env->gpr[9], env->gpr[10]);
/* Unix syscall error signaling */
if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
{
if( (int)ret < 0 )
env->nip += 0;
else
env->nip += 4;
}
/* Return value */
env->gpr[3] = ret;
break;
case EXCP_RESET:
/* Should not happen ! */
fprintf(stderr, "RESET asked... Stop emulation\n");
if (loglevel)
fprintf(logfile, "RESET asked... Stop emulation\n");
abort();
case EXCP_MACHINE_CHECK:
fprintf(stderr, "Machine check exeption... Stop emulation\n");
if (loglevel)
fprintf(logfile, "RESET asked... Stop emulation\n");
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_OBJERR;
info.si_addr = (void*)(env->nip - 4);
queue_signal(info.si_signo, &info);
case EXCP_DSI:
#ifndef DAR
/* To deal with multiple qemu header version as host for the darwin-user code */
# define DAR SPR_DAR
#endif
fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
if (loglevel) {
fprintf(logfile, "Invalid data memory access: 0x%08x\n",
env->spr[DAR]);
}
/* Handle this via the gdb */
gdb_handlesig (env, SIGSEGV);
info.si_addr = (void*)env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_ISI:
fprintf(stderr, "Invalid instruction fetch\n");
if (loglevel)
fprintf(logfile, "Invalid instruction fetch\n");
/* Handle this via the gdb */
gdb_handlesig (env, SIGSEGV);
info.si_addr = (void*)(env->nip - 4);
queue_signal(info.si_signo, &info);
break;
case EXCP_EXTERNAL:
/* Should not happen ! */
fprintf(stderr, "External interruption... Stop emulation\n");
if (loglevel)
fprintf(logfile, "External interruption... Stop emulation\n");
abort();
case EXCP_ALIGN:
fprintf(stderr, "Invalid unaligned memory access\n");
if (loglevel)
fprintf(logfile, "Invalid unaligned memory access\n");
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
info.si_addr = (void*)(env->nip - 4);
queue_signal(info.si_signo, &info);
break;
case EXCP_PROGRAM:
switch (env->error_code & ~0xF) {
case EXCP_FP:
fprintf(stderr, "Program exception\n");
if (loglevel)
fprintf(logfile, "Program exception\n");
/* Set FX */
env->fpscr[7] |= 0x8;
/* Finally, update FEX */
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
env->fpscr[7] |= 0x4;
info.si_signo = SIGFPE;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_FP_OX:
info.si_code = FPE_FLTOVF;
break;
case EXCP_FP_UX:
info.si_code = FPE_FLTUND;
break;
case EXCP_FP_ZX:
case EXCP_FP_VXZDZ:
info.si_code = FPE_FLTDIV;
break;
case EXCP_FP_XX:
info.si_code = FPE_FLTRES;
break;
case EXCP_FP_VXSOFT:
info.si_code = FPE_FLTINV;
break;
case EXCP_FP_VXNAN:
case EXCP_FP_VXISI:
case EXCP_FP_VXIDI:
case EXCP_FP_VXIMZ:
case EXCP_FP_VXVC:
case EXCP_FP_VXSQRT:
case EXCP_FP_VXCVI:
info.si_code = FPE_FLTSUB;
break;
default:
fprintf(stderr, "Unknown floating point exception "
"(%02x)\n", env->error_code);
if (loglevel) {
fprintf(logfile, "Unknown floating point exception "
"(%02x)\n", env->error_code & 0xF);
}
}
break;
case EXCP_INVAL:
fprintf(stderr, "Invalid instruction\n");
if (loglevel)
fprintf(logfile, "Invalid instruction\n");
info.si_signo = SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_INVAL_INVAL:
info.si_code = ILL_ILLOPC;
break;
case EXCP_INVAL_LSWX:
info.si_code = ILL_ILLOPN;
break;
case EXCP_INVAL_SPR:
info.si_code = ILL_PRVREG;
break;
case EXCP_INVAL_FP:
info.si_code = ILL_COPROC;
break;
default:
fprintf(stderr, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF);
if (loglevel) {
fprintf(logfile, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF);
}
info.si_code = ILL_ILLADR;
break;
}
/* Handle this via the gdb */
gdb_handlesig (env, SIGSEGV);
break;
case EXCP_PRIV:
fprintf(stderr, "Privilege violation\n");
if (loglevel)
fprintf(logfile, "Privilege violation\n");
info.si_signo = SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) {
case EXCP_PRIV_OPC:
info.si_code = ILL_PRVOPC;
break;
case EXCP_PRIV_REG:
info.si_code = ILL_PRVREG;
break;
default:
fprintf(stderr, "Unknown privilege violation (%02x)\n",
env->error_code & 0xF);
info.si_code = ILL_PRVOPC;
break;
}
break;
case EXCP_TRAP:
fprintf(stderr, "Tried to call a TRAP\n");
if (loglevel)
fprintf(logfile, "Tried to call a TRAP\n");
abort();
default:
/* Should not happen ! */
fprintf(stderr, "Unknown program exception (%02x)\n",
env->error_code);
if (loglevel) {
fprintf(logfile, "Unknwon program exception (%02x)\n",
env->error_code);
}
abort();
}
info.si_addr = (void*)(env->nip - 4);
queue_signal(info.si_signo, &info);
break;
case EXCP_NO_FP:
fprintf(stderr, "No floating point allowed\n");
if (loglevel)
fprintf(logfile, "No floating point allowed\n");
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_COPROC;
info.si_addr = (void*)(env->nip - 4);
queue_signal(info.si_signo, &info);
break;
case EXCP_DECR:
/* Should not happen ! */
fprintf(stderr, "Decrementer exception\n");
if (loglevel)
fprintf(logfile, "Decrementer exception\n");
abort();
case EXCP_TRACE:
/* Pass to gdb: we use this to trace execution */
gdb_handlesig (env, SIGTRAP);
break;
case EXCP_FP_ASSIST:
/* Should not happen ! */
fprintf(stderr, "Floating point assist exception\n");
if (loglevel)
fprintf(logfile, "Floating point assist exception\n");
abort();
case EXCP_MTMSR:
/* We reloaded the msr, just go on */
if (msr_pr == 0) {
fprintf(stderr, "Tried to go into supervisor mode !\n");
if (loglevel)
fprintf(logfile, "Tried to go into supervisor mode !\n");
abort();
}
break;
case EXCP_BRANCH:
/* We stopped because of a jump... */
break;
case EXCP_INTERRUPT:
/* Don't know why this should ever happen... */
fprintf(stderr, "EXCP_INTERRUPT\n");
break;
case EXCP_DEBUG:
gdb_handlesig (env, SIGTRAP);
break;
default:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
if (loglevel) {
fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
"0x%02x - aborting\n", trapnr, env->error_code);
}
abort();
}
process_pending_signals(env);
}
}
#endif
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
uint64_t cpu_get_tsc(CPUX86State *env)
{
return cpu_get_real_ticks();
}
void
write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
unsigned int e1, e2;
e1 = (addr << 16) | (limit & 0xffff);
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
e2 |= flags;
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
unsigned long addr, unsigned int sel)
{
unsigned int e1, e2;
e1 = (addr & 0xffff) | (sel << 16);
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
stl((uint8_t *)ptr, e1);
stl((uint8_t *)ptr + 4, e2);
}
#define GDT_TABLE_SIZE 14
#define LDT_TABLE_SIZE 15
#define IDT_TABLE_SIZE 256
#define TSS_SIZE 104
uint64_t gdt_table[GDT_TABLE_SIZE];
uint64_t ldt_table[LDT_TABLE_SIZE];
uint64_t idt_table[IDT_TABLE_SIZE];
uint32_t tss[TSS_SIZE];
/* only dpl matters as we do only user space emulation */
static void set_idt(int n, unsigned int dpl)
{
set_gate(idt_table + n, 0, dpl, 0, 0);
}
/* ABI convention: after a syscall if there was an error the CF flag is set */
static inline void set_error(CPUX86State *env, int ret)
{
if(ret<0)
env->eflags = env->eflags | 0x1;
else
env->eflags &= ~0x1;
env->regs[R_EAX] = ret;
}
void cpu_loop(CPUX86State *env)
{
int trapnr;
int ret;
uint8_t *pc;
target_siginfo_t info;
for(;;) {
trapnr = cpu_x86_exec(env);
uint32_t *params = (uint32_t *)env->regs[R_ESP];
switch(trapnr) {
case 0x79: /* Our commpage hack back door exit is here */
do_commpage(env, env->eip, *(params + 1), *(params + 2),
*(params + 3), *(params + 4),
*(params + 5), *(params + 6),
*(params + 7), *(params + 8));
break;
case 0x81: /* mach syscall */
{
ret = do_mach_syscall(env, env->regs[R_EAX],
*(params + 1), *(params + 2),
*(params + 3), *(params + 4),
*(params + 5), *(params + 6),
*(params + 7), *(params + 8));
set_error(env, ret);
break;
}
case 0x90: /* unix backdoor */
{
/* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
int saved_stack = env->regs[R_ESP];
env->regs[R_ESP] = env->regs[R_ECX];
ret = do_unix_syscall(env, env->regs[R_EAX]);
env->regs[R_ECX] = env->regs[R_ESP];
env->regs[R_ESP] = saved_stack;
set_error(env, ret);
break;
}
case 0x80: /* unix syscall */
{
ret = do_unix_syscall(env, env->regs[R_EAX]/*,
*(params + 1), *(params + 2),
*(params + 3), *(params + 4),
*(params + 5), *(params + 6),
*(params + 7), *(params + 8)*/);
set_error(env, ret);
break;
}
case 0x82: /* thread syscall */
{
ret = do_thread_syscall(env, env->regs[R_EAX],
*(params + 1), *(params + 2),
*(params + 3), *(params + 4),
*(params + 5), *(params + 6),
*(params + 7), *(params + 8));
set_error(env, ret);
break;
}
case EXCP0B_NOSEG:
case EXCP0C_STACK:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_NOOP;
info.si_addr = 0;
gdb_handlesig (env, SIGBUS);
queue_signal(info.si_signo, &info);
break;
case EXCP0D_GPF:
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_NOOP;
info.si_addr = 0;
gdb_handlesig (env, SIGSEGV);
queue_signal(info.si_signo, &info);
break;
case EXCP0E_PAGE:
info.si_signo = SIGSEGV;
info.si_errno = 0;
if (!(env->error_code & 1))
info.si_code = SEGV_MAPERR;
else
info.si_code = SEGV_ACCERR;
info.si_addr = (void*)env->cr[2];
gdb_handlesig (env, SIGSEGV);
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
/* division by zero */
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = FPE_INTDIV;
info.si_addr = (void*)env->eip;
gdb_handlesig (env, SIGFPE);
queue_signal(info.si_signo, &info);
break;
case EXCP01_SSTP:
case EXCP03_INT3:
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_addr = (void*)env->eip;
gdb_handlesig (env, SIGTRAP);
queue_signal(info.si_signo, &info);
break;
case EXCP04_INTO:
case EXCP05_BOUND:
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_NOOP;
info.si_addr = 0;
gdb_handlesig (env, SIGSEGV);
queue_signal(info.si_signo, &info);
break;
case EXCP06_ILLOP:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPN;
info.si_addr = (void*)env->eip;
gdb_handlesig (env, SIGILL);
queue_signal(info.si_signo, &info);
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
{
int sig;
sig = gdb_handlesig (env, SIGTRAP);
if (sig)
{
info.si_signo = sig;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
queue_signal(info.si_signo, &info);
}
}
break;
default:
pc = (void*)(env->segs[R_CS].base + env->eip);
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
}
process_pending_signals(env);
}
}
#endif
void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
"Darwin CPU emulator (compiled for %s emulation)\n"
"\n"
"-h print this help\n"
"-L path set the %s library path (default='%s')\n"
"-s size set the stack size in bytes (default=%ld)\n"
"\n"
"debug options:\n"
#ifdef USE_CODE_COPY
"-no-code-copy disable code copy acceleration\n"
#endif
"-d options activate log (logfile='%s')\n"
"-g wait for gdb on port 1234\n"
"-p pagesize set the host page size to 'pagesize'\n",
TARGET_ARCH,
TARGET_ARCH,
interp_prefix,
stack_size,
DEBUG_LOGFILE);
_exit(1);
}
/* XXX: currently only used for async signals (see signal.c) */
CPUState *global_env;
/* used only if single thread */
CPUState *cpu_single_env = NULL;
/* used to free thread contexts */
TaskState *first_task_state;
int main(int argc, char **argv)
{
const char *filename;
struct target_pt_regs regs1, *regs = &regs1;
TaskState ts1, *ts = &ts1;
CPUState *env;
int optind;
short use_gdbstub = 0;
const char *r;
if (argc <= 1)
usage();
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
optind = 1;
for(;;) {
if (optind >= argc)
break;
r = argv[optind];
if (r[0] != '-')
break;
optind++;
r++;
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
int mask;
CPULogItem *item;
if (optind >= argc)
break;
r = argv[optind++];
mask = cpu_str_to_log_mask(r);
if (!mask) {
printf("Log items (comma separated):\n");
for(item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
} else if (!strcmp(r, "s")) {
r = argv[optind++];
stack_size = strtol(r, (char **)&r, 0);
if (stack_size <= 0)
usage();
if (*r == 'M')
stack_size *= 1024 * 1024;
else if (*r == 'k' || *r == 'K')
stack_size *= 1024;
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
qemu_host_page_size = atoi(argv[optind++]);
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
exit(1);
}
} else
if (!strcmp(r, "g")) {
use_gdbstub = 1;
} else
#ifdef USE_CODE_COPY
if (!strcmp(r, "no-code-copy")) {
code_copy_enabled = 0;
} else
#endif
{
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init();
printf("Starting %s with qemu\n----------------\n", filename);
commpage_init();
if (mach_exec(filename, argv+optind, environ, regs) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
}
syscall_init();
signal_init();
global_env = env;
/* build Task State */
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
env->user_mode_only = 1;
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->cpuid_features & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags |= IF_MASK;
/* darwin register setup */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
env->regs[R_ECX] = regs->ecx;
env->regs[R_EDX] = regs->edx;
env->regs[R_ESI] = regs->esi;
env->regs[R_EDI] = regs->edi;
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
/* Darwin LDT setup */
/* 2 - User code segment
3 - User data segment
4 - User cthread */
bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
env->ldt.base = (uint32_t) ldt_table;
env->ldt.limit = sizeof(ldt_table) - 1;
write_dt(ldt_table + 2, 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
write_dt(ldt_table + 3, 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
write_dt(ldt_table + 4, 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
/* Darwin GDT setup.
* has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
bzero(gdt_table, sizeof(gdt_table));
env->gdt.base = (uint32_t)gdt_table;
env->gdt.limit = sizeof(gdt_table) - 1;
/* Set up a back door to handle sysenter syscalls (unix) */
char * syscallbackdoor = malloc(64);
page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
int i = 0;
syscallbackdoor[i++] = 0xcd;
syscallbackdoor[i++] = 0x90; /* int 0x90 */
syscallbackdoor[i++] = 0x0F;
syscallbackdoor[i++] = 0x35; /* sysexit */
/* Darwin sysenter/sysexit setup */
env->sysenter_cs = 0x1; //XXX
env->sysenter_eip = (int)syscallbackdoor;
env->sysenter_esp = (int)malloc(64);
/* Darwin TSS setup
This must match up with GDT[4] */
env->tr.base = (uint32_t) tss;
env->tr.limit = sizeof(tss) - 1;
env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment
/* Darwin interrupt setup */
bzero(idt_table, sizeof(idt_table));
env->idt.base = (uint32_t) idt_table;
env->idt.limit = sizeof(idt_table) - 1;
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
set_idt(3, 3);
set_idt(4, 3);
set_idt(5, 3);
set_idt(6, 0);
set_idt(7, 0);
set_idt(8, 0);
set_idt(9, 0);
set_idt(10, 0);
set_idt(11, 0);
set_idt(12, 0);
set_idt(13, 0);
set_idt(14, 0);
set_idt(15, 0);
set_idt(16, 0);
set_idt(17, 0);
set_idt(18, 0);
set_idt(19, 0);
/* Syscalls are done via
int 0x80 (unix) (rarely used)
int 0x81 (mach)
int 0x82 (thread)
int 0x83 (diag) (not handled here)
sysenter/sysexit (unix) -> we redirect that to int 0x90 */
set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
set_idt(0x80, 3); /* Unix Syscall */
set_idt(0x81, 3); /* Mach Syscalls */
set_idt(0x82, 3); /* thread Syscalls */
set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */
cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
#elif defined(TARGET_PPC)
{
int i;
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
}
}
#else
#error unsupported target CPU
#endif
if (use_gdbstub) {
printf("Waiting for gdb Connection on port 1234...\n");
gdbserver_start (1234);
gdb_handlesig(env, 0);
}
cpu_loop(env);
/* never exits */
return 0;
}

411
darwin-user/mmap.c Normal file
View File

@@ -0,0 +1,411 @@
/*
* mmap support for qemu
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include "qemu.h"
//#define DEBUG_MMAP
/* NOTE: all the constants are the HOST ones */
int target_mprotect(unsigned long start, unsigned long len, int prot)
{
unsigned long end, host_start, host_end, addr;
int prot1, ret;
#ifdef DEBUG_MMAP
printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
#endif
if ((start & ~TARGET_PAGE_MASK) != 0)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return -EINVAL;
if (len == 0)
return 0;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot1 = prot;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
if (host_end == host_start + qemu_host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
end = host_end;
}
ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot1 = prot;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot1 |= page_get_flags(addr);
}
ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
prot1 & PAGE_BITS);
if (ret != 0)
return ret;
host_end -= qemu_host_page_size;
}
/* handle the pages in the middle */
if (host_start < host_end) {
ret = mprotect((void *)host_start, host_end - host_start, prot);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, prot | PAGE_VALID);
return 0;
}
/* map an incomplete host page */
int mmap_frag(unsigned long host_start,
unsigned long start, unsigned long end,
int prot, int flags, int fd, unsigned long offset)
{
unsigned long host_end, ret, addr;
int prot1, prot_new;
host_end = host_start + qemu_host_page_size;
/* get the protection of the target pages outside the mapping */
prot1 = 0;
for(addr = host_start; addr < host_end; addr++) {
if (addr < start || addr >= end)
prot1 |= page_get_flags(addr);
}
if (prot1 == 0) {
/* no page was there, so we allocate one */
ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
flags | MAP_ANONYMOUS, -1, 0);
if (ret == -1)
return ret;
}
prot1 &= PAGE_BITS;
prot_new = prot | prot1;
if (!(flags & MAP_ANONYMOUS)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
#ifndef __APPLE__
if ((flags & MAP_TYPE) == MAP_SHARED &&
#else
if ((flags & MAP_SHARED) &&
#endif
(prot & PROT_WRITE))
return -EINVAL;
/* adjust protection to be able to read */
if (!(prot1 & PROT_WRITE))
mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
pread(fd, (void *)start, end - start, offset);
/* put final protection */
if (prot_new != (prot1 | PROT_WRITE))
mprotect((void *)host_start, qemu_host_page_size, prot_new);
} else {
/* just update the protection */
if (prot_new != prot1) {
mprotect((void *)host_start, qemu_host_page_size, prot_new);
}
}
return 0;
}
/* NOTE: all the constants are the HOST ones */
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset)
{
unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
static unsigned long last_start = 0x40000000;
#endif
#ifdef DEBUG_MMAP
{
printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
start, len,
prot & PROT_READ ? 'r' : '-',
prot & PROT_WRITE ? 'w' : '-',
prot & PROT_EXEC ? 'x' : '-');
if (flags & MAP_FIXED)
printf("MAP_FIXED ");
if (flags & MAP_ANONYMOUS)
printf("MAP_ANON ");
#ifndef MAP_TYPE
# define MAP_TYPE 0x3
#endif
switch(flags & MAP_TYPE) {
case MAP_PRIVATE:
printf("MAP_PRIVATE ");
break;
case MAP_SHARED:
printf("MAP_SHARED ");
break;
default:
printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
break;
}
printf("fd=%d offset=%lx\n", fd, offset);
}
#endif
if (offset & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return start;
host_start = start & qemu_host_page_mask;
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
/* tell the kenel to search at the same place as i386 */
if (host_start == 0) {
host_start = last_start;
last_start += HOST_PAGE_ALIGN(len);
}
#endif
if (qemu_host_page_size != qemu_real_host_page_size) {
/* NOTE: this code is only for debugging with '-p' option */
/* reserve a memory area */
host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (host_start == -1)
return host_start;
host_end = host_start + host_len;
start = HOST_PAGE_ALIGN(host_start);
end = start + HOST_PAGE_ALIGN(len);
if (start > host_start)
munmap((void *)host_start, start - host_start);
if (end < host_end)
munmap((void *)end, host_end - end);
/* use it as a fixed mapping */
flags |= MAP_FIXED;
} else {
/* if not fixed, no need to do anything */
host_offset = offset & qemu_host_page_mask;
host_len = len + offset - host_offset;
start = (long)mmap((void *)host_start, host_len,
prot, flags, fd, host_offset);
if (start == -1)
return start;
/* update start so that it points to the file position at 'offset' */
if (!(flags & MAP_ANONYMOUS))
start += offset - host_offset;
goto the_end1;
}
}
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
end = start + len;
host_end = HOST_PAGE_ALIGN(end);
/* worst case: we cannot map the file because the offset is not
aligned, so we read it */
if (!(flags & MAP_ANONYMOUS) &&
(offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
/* msync() won't work here, so we return an error if write is
possible while it is a shared mapping */
#ifndef __APPLE__
if ((flags & MAP_TYPE) == MAP_SHARED &&
#else
if ((flags & MAP_SHARED) &&
#endif
(prot & PROT_WRITE))
return -EINVAL;
retaddr = target_mmap(start, len, prot | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
if (retaddr == -1)
return retaddr;
pread(fd, (void *)start, len, offset);
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
if (ret != 0)
return ret;
}
goto the_end;
}
/* handle the start of the mapping */
if (start > host_start) {
if (host_end == host_start + qemu_host_page_size) {
/* one single host page */
ret = mmap_frag(host_start, start, end,
prot, flags, fd, offset);
if (ret == -1)
return ret;
goto the_end1;
}
ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
prot, flags, fd, offset);
if (ret == -1)
return ret;
host_start += qemu_host_page_size;
}
/* handle the end of the mapping */
if (end < host_end) {
ret = mmap_frag(host_end - qemu_host_page_size,
host_end - qemu_host_page_size, host_end,
prot, flags, fd,
offset + host_end - qemu_host_page_size - start);
if (ret == -1)
return ret;
host_end -= qemu_host_page_size;
}
/* map the middle (easier) */
if (host_start < host_end) {
unsigned long offset1;
if (flags & MAP_ANONYMOUS)
offset1 = 0;
else
offset1 = offset + host_start - start;
ret = (long)mmap((void *)host_start, host_end - host_start,
prot, flags, fd, offset1);
if (ret == -1)
return ret;
}
the_end1:
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
printf("target_mmap: ret=0x%lx\n", (long)start);
page_dump(stdout);
printf("\n");
#endif
return start;
}
int target_munmap(unsigned long start, unsigned long len)
{
unsigned long end, host_start, host_end, addr;
int prot, ret;
#ifdef DEBUG_MMAP
printf("munmap: start=0x%lx len=0x%lx\n", start, len);
#endif
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
if (len == 0)
return -EINVAL;
end = start + len;
host_start = start & qemu_host_page_mask;
host_end = HOST_PAGE_ALIGN(end);
if (start > host_start) {
/* handle host page containing start */
prot = 0;
for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (host_end == host_start + qemu_host_page_size) {
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
end = host_end;
}
if (prot != 0)
host_start += qemu_host_page_size;
}
if (end < host_end) {
prot = 0;
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= page_get_flags(addr);
}
if (prot != 0)
host_end -= qemu_host_page_size;
}
/* unmap what we can */
if (host_start < host_end) {
ret = munmap((void *)host_start, host_end - host_start);
if (ret != 0)
return ret;
}
page_set_flags(start, start + len, 0);
return 0;
}
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
blocks which have been allocated starting on a host page */
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr)
{
#ifndef __APPLE__
/* XXX: use 5 args syscall */
new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
if (new_addr == -1)
return new_addr;
prot = page_get_flags(old_addr);
page_set_flags(old_addr, old_addr + old_size, 0);
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
return new_addr;
#else
qerror("target_mremap: unsupported\n");
#endif
}
int target_msync(unsigned long start, unsigned long len, int flags)
{
unsigned long end;
if (start & ~TARGET_PAGE_MASK)
return -EINVAL;
len = TARGET_PAGE_ALIGN(len);
end = start + len;
if (end < start)
return -EINVAL;
if (end == start)
return 0;
start &= qemu_host_page_mask;
return msync((void *)start, end - start, flags);
}

179
darwin-user/qemu.h Normal file
View File

@@ -0,0 +1,179 @@
#ifndef GEMU_H
#define GEMU_H
#include "thunk.h"
#include <signal.h>
#include <string.h>
#include "cpu.h"
#include "gdbstub.h"
typedef siginfo_t target_siginfo_t;
#define target_sigaction sigaction
#ifdef TARGET_I386
struct target_pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
struct target_sigcontext {
int sc_onstack;
int sc_mask;
int sc_eax;
int sc_ebx;
int sc_ecx;
int sc_edx;
int sc_edi;
int sc_esi;
int sc_ebp;
int sc_esp;
int sc_ss;
int sc_eflags;
int sc_eip;
int sc_cs;
int sc_ds;
int sc_es;
int sc_fs;
int sc_gs;
};
#define __USER_CS (0x17)
#define __USER_DS (0x1F)
#elif defined(TARGET_PPC)
struct target_pt_regs {
unsigned long gpr[32];
unsigned long nip;
unsigned long msr;
unsigned long orig_gpr3; /* Used for restarting system calls */
unsigned long ctr;
unsigned long link;
unsigned long xer;
unsigned long ccr;
unsigned long mq; /* 601 only (not used at present) */
/* Used on APUS to hold IPL value. */
unsigned long trap; /* Reason for being here */
unsigned long dar; /* Fault registers */
unsigned long dsisr;
unsigned long result; /* Result of a system call */
};
struct target_sigcontext {
int sc_onstack; /* sigstack state to restore */
int sc_mask; /* signal mask to restore */
int sc_ir; /* pc */
int sc_psw; /* processor status word */
int sc_sp; /* stack pointer if sc_regs == NULL */
void *sc_regs; /* (kernel private) saved state */
};
#endif
typedef struct TaskState {
struct TaskState *next;
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
void syscall_init(void);
long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
long do_unix_syscall(void *cpu_env, int num);
int do_sigaction(int sig, const struct sigaction *act,
struct sigaction *oact);
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
void qerror(const char *fmt, ...);
void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
extern CPUState *global_env;
void cpu_loop(CPUState *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
extern int loglevel;
extern FILE *logfile;
/* commpage.c */
void commpage_init();
void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
/* signal.c */
void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUState *env, int num);
/* machload.c */
int mach_exec(const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs);
/* mmap.c */
int target_mprotect(unsigned long start, unsigned long len, int prot);
long target_mmap(unsigned long start, unsigned long len, int prot,
int flags, int fd, unsigned long offset);
int target_munmap(unsigned long start, unsigned long len);
long target_mremap(unsigned long old_addr, unsigned long old_size,
unsigned long new_size, unsigned long flags,
unsigned long new_addr);
int target_msync(unsigned long start, unsigned long len, int flags);
/* user access */
/* XXX: todo protect every memory access */
#define lock_user(x,y,z) (void*)(x)
#define unlock_user(x,y,z)
/* Mac OS X ABI arguments processing */
#ifdef TARGET_I386
static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
{
uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
*i+=4;
return tswap32(*args);
}
static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
{
uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
*i+=8;
return tswap64(*args);
}
#elif defined(TARGET_PPC)
static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
{
/* XXX: won't work when args goes on stack after gpr10 */
uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
*i+=4;
return tswap32(args);
}
static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
{
/* XXX: won't work when args goes on stack after gpr10 */
uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
*i+=(8 << 8) + 8;
return tswap64(args);
}
#endif
#endif

463
darwin-user/signal.c Normal file
View File

@@ -0,0 +1,463 @@
/*
* Emulation of Linux signals
*
* Copyright (c) 2003 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>
#ifdef __ia64__
#undef uc_mcontext
#undef uc_sigmask
#undef uc_stack
#undef uc_link
#endif
#include <signal.h>
#include "qemu.h"
#define DEBUG_SIGNAL
#define MAX_SIGQUEUE_SIZE 1024
struct sigqueue {
struct sigqueue *next;
target_siginfo_t info;
};
struct emulated_sigaction {
struct target_sigaction sa;
int pending; /* true if signal is pending */
struct sigqueue *first;
struct sigqueue info; /* in order to always have memory for the
first signal, we put it here */
};
struct sigaltstack target_sigaltstack_used = {
0, 0, SA_DISABLE
};
static struct emulated_sigaction sigact_table[NSIG];
static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
static struct sigqueue *first_free; /* first free siginfo queue entry */
static int signal_pending; /* non zero if a signal may be pending */
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
static inline int host_to_target_signal(int sig)
{
return sig;
}
static inline int target_to_host_signal(int sig)
{
return sig;
}
/* siginfo conversion */
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
{
}
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
{
}
void signal_init(void)
{
struct sigaction act;
int i;
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = host_signal_handler;
for(i = 1; i < NSIG; i++) {
sigaction(i, &act, NULL);
}
memset(sigact_table, 0, sizeof(sigact_table));
first_free = &sigqueue_table[0];
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
sigqueue_table[i].next = &sigqueue_table[i + 1];
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
}
/* signal queue handling */
static inline struct sigqueue *alloc_sigqueue(void)
{
struct sigqueue *q = first_free;
if (!q)
return NULL;
first_free = q->next;
return q;
}
static inline void free_sigqueue(struct sigqueue *q)
{
q->next = first_free;
first_free = q;
}
/* abort execution with signal */
void __attribute((noreturn)) force_sig(int sig)
{
int host_sig;
host_sig = target_to_host_signal(sig);
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
_exit(-host_sig);
}
/* queue a signal so that it will be send to the virtual CPU as soon
as possible */
int queue_signal(int sig, target_siginfo_t *info)
{
struct emulated_sigaction *k;
struct sigqueue *q, **pq;
target_ulong handler;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "queue_signal: sig=%d\n",
sig);
#endif
k = &sigact_table[sig - 1];
handler = (target_ulong)k->sa.sa_handler;
if (handler == SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != SIGCHLD &&
sig != SIGURG &&
sig != SIGWINCH) {
force_sig(sig);
} else {
return 0; /* indicate ignored */
}
} else if (handler == host_to_target_signal(SIG_IGN)) {
/* ignore signal */
return 0;
} else if (handler == host_to_target_signal(SIG_ERR)) {
force_sig(sig);
} else {
pq = &k->first;
if (!k->pending) {
/* first signal */
q = &k->info;
} else {
q = alloc_sigqueue();
if (!q)
return -EAGAIN;
while (*pq != NULL)
pq = &(*pq)->next;
}
*pq = q;
q->info = *info;
q->next = NULL;
k->pending = 1;
/* signal that a new signal is pending */
signal_pending = 1;
return 1; /* indicates that the signal was queued */
}
}
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc)
{
int sig;
target_siginfo_t tinfo;
/* the CPU emulator uses some host signals to detect exceptions,
we we forward to it some signals */
if (host_signum == SIGSEGV || host_signum == SIGBUS
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
|| host_signum == SIGFPE
#endif
) {
if (cpu_signal_handler(host_signum, (void*)info, puc))
return;
}
/* get target signal number */
sig = host_to_target_signal(host_signum);
if (sig < 1 || sig > NSIG)
return;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "qemu: got signal %d\n", sig);
#endif
if (queue_signal(sig, &tinfo) == 1) {
/* interrupt the virtual CPU as soon as possible */
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
{
/* XXX: test errors */
if(oss)
{
oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
}
if(ss)
{
target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
}
return 0;
}
int do_sigaction(int sig, const struct sigaction *act,
struct sigaction *oact)
{
struct emulated_sigaction *k;
struct sigaction act1;
int host_sig;
if (sig < 1 || sig > NSIG)
return -EINVAL;
k = &sigact_table[sig - 1];
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
if (oact) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
sig, (int)act, (int)oact);
#endif
oact->sa_handler = tswapl(k->sa.sa_handler);
oact->sa_flags = tswapl(k->sa.sa_flags);
oact->sa_mask = tswapl(k->sa.sa_mask);
}
if (act) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
act->sa_handler, act->sa_flags, act->sa_mask);
#endif
k->sa.sa_handler = tswapl(act->sa_handler);
k->sa.sa_flags = tswapl(act->sa_flags);
k->sa.sa_mask = tswapl(act->sa_mask);
/* we update the host signal state */
host_sig = target_to_host_signal(sig);
if (host_sig != SIGSEGV && host_sig != SIGBUS) {
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "sigaction handler going to call sigaction\n",
act->sa_handler, act->sa_flags, act->sa_mask);
#endif
sigfillset(&act1.sa_mask);
act1.sa_flags = SA_SIGINFO;
if (k->sa.sa_flags & SA_RESTART)
act1.sa_flags |= SA_RESTART;
/* NOTE: it is important to update the host kernel signal
ignore state to avoid getting unexpected interrupted
syscalls */
if (k->sa.sa_handler == SIG_IGN) {
act1.sa_sigaction = (void *)SIG_IGN;
} else if (k->sa.sa_handler == SIG_DFL) {
act1.sa_sigaction = (void *)SIG_DFL;
} else {
act1.sa_sigaction = host_signal_handler;
}
sigaction(host_sig, &act1, NULL);
}
}
return 0;
}
#ifdef TARGET_I386
static inline void *
get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
{
/* XXX Fix that */
if(target_sigaltstack_used.ss_flags & SA_DISABLE)
{
int esp;
/* Default to using normal stack */
esp = env->regs[R_ESP];
return (void *)((esp - frame_size) & -8ul);
}
else
{
return target_sigaltstack_used.ss_sp;
}
}
static void setup_frame(int sig, struct emulated_sigaction *ka,
void *set, CPUState *env)
{
void *frame;
int i, err = 0;
fprintf(stderr, "setup_frame %d\n", sig);
frame = get_sigframe(ka, env, sizeof(*frame));
/* Set up registers for signal handler */
env->regs[R_ESP] = (unsigned long) frame;
env->eip = (unsigned long) ka->sa.sa_handler;
env->eflags &= ~TF_MASK;
return;
give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV /* , current */);
}
long do_sigreturn(CPUState *env, int num)
{
int i = 0;
struct target_sigcontext *scp = get_int_arg(&i, env);
/* XXX Get current signal number */
/* XXX Adjust accordin to sc_onstack, sc_mask */
if(tswapl(scp->sc_onstack) & 0x1)
target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
else
target_sigaltstack_used.ss_flags &= SA_DISABLE;
int set = tswapl(scp->sc_eax);
sigprocmask(SIG_SETMASK, &set, NULL);
fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
env->regs[R_EAX] = tswapl(scp->sc_eax);
env->regs[R_EBX] = tswapl(scp->sc_ebx);
env->regs[R_ECX] = tswapl(scp->sc_ecx);
env->regs[R_EDX] = tswapl(scp->sc_edx);
env->regs[R_EDI] = tswapl(scp->sc_edi);
env->regs[R_ESI] = tswapl(scp->sc_esi);
env->regs[R_EBP] = tswapl(scp->sc_ebp);
env->regs[R_ESP] = tswapl(scp->sc_esp);
env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
env->eflags = tswapl(scp->sc_eflags);
env->eip = tswapl(scp->sc_eip);
env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
/* Again, because our caller's caller will reset EAX */
return env->regs[R_EAX];
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
void *set, CPUState *env)
{
fprintf(stderr, "setup_frame: not implemented\n");
}
long do_sigreturn(CPUState *env, int num)
{
int i = 0;
struct target_sigcontext *scp = get_int_arg(&i, env);
fprintf(stderr, "do_sigreturn: not implemented\n");
return -ENOSYS;
}
#endif
void process_pending_signals(void *cpu_env)
{
struct emulated_sigaction *k;
struct sigqueue *q;
target_ulong handler;
int sig;
if (!signal_pending)
return;
k = sigact_table;
for(sig = 1; sig <= NSIG; sig++) {
if (k->pending)
goto handle_signal;
k++;
}
/* if no signal is pending, just return */
signal_pending = 0;
return;
handle_signal:
#ifdef DEBUG_SIGNAL
fprintf(stderr, "qemu: process signal %d\n", sig);
#endif
/* dequeue signal */
q = k->first;
k->first = q->next;
if (!k->first)
k->pending = 0;
sig = gdb_handlesig (cpu_env, sig);
if (!sig) {
fprintf (stderr, "Lost signal\n");
abort();
}
handler = k->sa.sa_handler;
if (handler == SIG_DFL) {
/* default handler : ignore some signal. The other are fatal */
if (sig != SIGCHLD &&
sig != SIGURG &&
sig != SIGWINCH) {
force_sig(sig);
}
} else if (handler == SIG_IGN) {
/* ignore sig */
} else if (handler == SIG_ERR) {
force_sig(sig);
} else {
setup_frame(sig, k, 0, cpu_env);
if (k->sa.sa_flags & SA_RESETHAND)
k->sa.sa_handler = SIG_DFL;
}
if (q != &k->info)
free_sigqueue(q);
}

1527
darwin-user/syscall.c Normal file

File diff suppressed because it is too large Load Diff

384
darwin-user/syscalls.h Normal file
View File

@@ -0,0 +1,384 @@
/* generated from xnu/bsd/kern/syscalls.master */
ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */
ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */
ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */
ENTRY("read", SYS_read, do_read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */
ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */
ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */
ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */
ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */
ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */
ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */
ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */
ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */
ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */
ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */
ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */
ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */
ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */
ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */
ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */
ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */
ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */
ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */
ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */
ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */
ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */
ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */
ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */
ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */
ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */
ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */
ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */
ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */
ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */
ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */
ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */
ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */
ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */
ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */
ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */
ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */
ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */
ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */
ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */
ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */
ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */
ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */
ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */
ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */
ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */
ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */
ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */
ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */
ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */
ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */
ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */
ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */
ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */
ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */
ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */
ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */
ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */
ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */
ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */
ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */
ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */
ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */
ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */
ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */
ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */
ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */
ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */
ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */
ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */
ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */
ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */
ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */
ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */
ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */
ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */
ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */
ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */
ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */
ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */
ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */
ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */
ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */
ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */
ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */
ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */
ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */
ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */
ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */
ENTRY("fcntl", SYS_fcntl, do_fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */
ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */
ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */
ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */
ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */
ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */
ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */
ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */
ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */
ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */
ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */
ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */
ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */
ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */
ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */
ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */
ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */
ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */
ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */
ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */
ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */
ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */
ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */
ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */
ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */
ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */
ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */
ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */
ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */
ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */
ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */
ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */
ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */
ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */
ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */
ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */
ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */
ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */
ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */
ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */
ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */
ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */
ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */
ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */
ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */
ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */
ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */
ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */
ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */
ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */
ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */
ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */
ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */
ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */
ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */
ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */
ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */
ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */
ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */
ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */
ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */
ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */
ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */
#ifdef SYS_nfssvc
ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */
#else
ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */
#endif
ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */
ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */
ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */
ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */
ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */
ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */
ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */
ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */
ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */
ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */
ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */
ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */
ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */
ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */
ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */
ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */
ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */
ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */
ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */
ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */
ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */
ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */
ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */
ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */
ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */
ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */
ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */
ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */
ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */
ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */
ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */
ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */
ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */
ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */
ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */
ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */
ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */
ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */
ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */
ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */
ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */
ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */
ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */
ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */
ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */
ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */
ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */
ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */
ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */
ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */
ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */
ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */
ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */
ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */
ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */
ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */
ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */
ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */
ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */
ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */
ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */
ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */
ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */
ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */
ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */
ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */
ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */
ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */
ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */
ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */
ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */
ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */
ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */
ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */
ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */
ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */
ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */
ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */
ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */
ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */
ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */
ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */
ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */
ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */
ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */
ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */
ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */
ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */
ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */
ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */
ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */
ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */
ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */
ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */
#ifdef SYS_nfsclnt
ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */
#else
ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */
#endif
ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */
ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */
ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */
ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */
ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */
ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */
ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */
ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */
ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */
ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */
ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */
ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */
ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */
ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */
ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */
ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */
ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */
ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */
ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */
ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */
ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */
ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */
ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */
ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */
ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */
ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */
ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */
ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */
ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */
ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */
ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */
ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */
ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */
ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */
ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */
ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */
ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */
ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */
ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */
ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */
ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */
ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */
ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */
ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */
ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */
ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */
ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */
ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */
ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */
ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */
ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */
ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */
ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */
ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */
ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */
ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */
ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */
ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */
ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */
ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */
ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */
ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */
ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */
ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */
ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */
ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */
ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */
ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */
ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */
ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */
ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */
ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */
ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */
ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */
ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */
ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */
ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */
ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */
ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */
ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */
ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */
ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */
ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */
ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */
ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */
ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */
ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */
ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */
ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */
ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */
ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */
ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */
ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */
ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */
ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */
ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */
ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */
ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */
ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */
ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */
ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */
ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */
ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */
ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */
ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */
ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */
ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */
ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */
ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */
ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */
ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */
ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */
ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */
ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */
ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */
ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */
ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */
ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */
ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */
ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */
ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */
ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */
ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */

18
disas.c
View File

@@ -58,7 +58,7 @@ perror_memory (status, memaddr, info)
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%llx is out of bounds.\n", memaddr);
"Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
@@ -73,7 +73,7 @@ generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%llx", addr);
(*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
}
/* Just return the given address. */
@@ -186,14 +186,14 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#elif defined(TARGET_MIPS)
#ifdef TARGET_WORDS_BIGENDIAN
print_insn = print_insn_big_mips;
#else
print_insn = print_insn_little_mips;
#endif
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#elif defined(TARGET_SH4)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
@@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size)
for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
fprintf(out, "0x%08lx: ", pc);
#ifdef __arm__
/* since data are included in the code, it is better to
/* since data is included in the code, it is better to
display code data too */
if (is_host) {
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
}
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
#endif
count = print_insn(pc, &disasm_info);
fprintf(out, "\n");
@@ -387,14 +385,14 @@ void monitor_disas(CPUState *env,
disasm_info.mach = bfd_mach_ppc;
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#elif defined(TARGET_MIPS)
#ifdef TARGET_WORDS_BIGENDIAN
print_insn = print_insn_big_mips;
#else
print_insn = print_insn_little_mips;
#endif
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);

View File

@@ -35,12 +35,15 @@
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Linux/Sparc64 defines uint64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
#endif
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
prior to this and will cause an error in compliation, conflicting
@@ -50,11 +53,17 @@ typedef signed char int8_t;
#endif
typedef signed short int16_t;
typedef signed int int32_t;
// Linux/Sparc64 defines int64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
#if defined (__x86_64__) || defined(__ia64)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
#endif
/* XXX: This may be wrong for 64-bit ILP32 hosts. */
typedef void * host_reg_t;
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
@@ -121,6 +130,19 @@ extern int printf(const char *, ...);
#define AREG3 "s2"
#endif
#ifdef __sparc__
#ifdef HOST_SOLARIS
#define AREG0 "g2"
#define AREG1 "g3"
#define AREG2 "g4"
#define AREG3 "g5"
#define AREG4 "g6"
#else
#ifdef __sparc_v9__
#define AREG0 "g1"
#define AREG1 "g4"
#define AREG2 "g5"
#define AREG3 "g7"
#else
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
@@ -133,6 +155,8 @@ extern int printf(const char *, ...);
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
#endif
#endif
#define USE_FP_CONVERT
#endif
#ifdef __s390__
@@ -167,7 +191,7 @@ extern int printf(const char *, ...);
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
#ifndef OPPROTO
#define OPPROTO
@@ -241,10 +265,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
"nop")
#define GOTO_LABEL_PARAM(n) asm volatile ( \
"set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop")
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")

379
dyngen.c
View File

@@ -127,10 +127,12 @@
typedef int32_t host_long;
typedef uint32_t host_ulong;
#define swabls(x) swab32s(x)
#define swablss(x) swab32ss(x)
#else
typedef int64_t host_long;
typedef uint64_t host_ulong;
#define swabls(x) swab64s(x)
#define swablss(x) swab64ss(x)
#endif
#ifdef ELF_USES_RELOCA
@@ -284,11 +286,21 @@ void swab32s(uint32_t *p)
*p = bswap32(*p);
}
void swab32ss(int32_t *p)
{
*p = bswap32(*p);
}
void swab64s(uint64_t *p)
{
*p = bswap64(*p);
}
void swab64ss(int64_t *p)
{
*p = bswap64(*p);
}
uint16_t get16(uint16_t *p)
{
uint16_t val;
@@ -397,7 +409,7 @@ void elf_swap_rel(ELF_RELOC *rel)
swabls(&rel->r_offset);
swabls(&rel->r_info);
#ifdef ELF_USES_RELOCA
swabls(&rel->r_addend);
swablss(&rel->r_addend);
#endif
}
@@ -505,7 +517,7 @@ int load_object(const char *filename)
}
sec = &shdr[ehdr.e_shstrndx];
shstr = sdata[ehdr.e_shstrndx];
shstr = (char *)sdata[ehdr.e_shstrndx];
/* swap relocations */
for(i = 0; i < ehdr.e_shnum; i++) {
@@ -541,7 +553,7 @@ int load_object(const char *filename)
strtab_sec = &shdr[symtab_sec->sh_link];
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
strtab = sdata[symtab_sec->sh_link];
strtab = (char *)sdata[symtab_sec->sh_link];
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
if (do_swap) {
@@ -1196,7 +1208,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name)
} else {
#ifdef HOST_SPARC
if (sym_name[0] == '.')
snprintf(name, sizeof(name),
snprintf(name, name_size,
"(long)(&__dot_%s)",
sym_name + 1);
else
@@ -1255,90 +1267,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
{
uint8_t *p;
uint32_t insn;
int offset, min_offset, pc_offset, data_size;
int offset, min_offset, pc_offset, data_size, spare, max_pool;
uint8_t data_allocated[1024];
unsigned int data_index;
int type;
memset(data_allocated, 0, sizeof(data_allocated));
p = p_start;
min_offset = p_end - p_start;
spare = 0x7fffffff;
while (p < p_start + min_offset) {
insn = get32((uint32_t *)p);
/* TODO: Armv5e ldrd. */
/* TODO: VFP load. */
if ((insn & 0x0d5f0000) == 0x051f0000) {
/* ldr reg, [pc, #im] */
offset = insn & 0xfff;
if (!(insn & 0x00800000))
offset = -offset;
offset = -offset;
max_pool = 4096;
type = 0;
} else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
/* FPA ldf. */
offset = (insn & 0xff) << 2;
if (!(insn & 0x00800000))
offset = -offset;
max_pool = 1024;
type = 1;
} else if ((insn & 0x0fff0000) == 0x028f0000) {
/* Some gcc load a doubleword immediate with
add regN, pc, #imm
ldmia regN, {regN, regM}
Hope and pray the compiler never generates somethin like
add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
int r;
r = (insn & 0xf00) >> 7;
offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
max_pool = 1024;
type = 2;
} else {
max_pool = 0;
type = -1;
}
if (type >= 0) {
/* PC-relative load needs fixing up. */
if (spare > max_pool - offset)
spare = max_pool - offset;
if ((offset & 3) !=0)
error("%s:%04x: ldr pc offset must be 32 bit aligned",
error("%s:%04x: pc offset must be 32 bit aligned",
name, start_offset + p - p_start);
if (offset < 0)
error("%s:%04x: Embedded literal value",
name, start_offset + p - p_start);
pc_offset = p - p_start + offset + 8;
if (pc_offset <= (p - p_start) ||
pc_offset >= (p_end - p_start))
error("%s:%04x: ldr pc offset must point inside the function code",
error("%s:%04x: pc offset must point inside the function code",
name, start_offset + p - p_start);
if (pc_offset < min_offset)
min_offset = pc_offset;
if (outfile) {
/* ldr position */
/* The intruction position */
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
p - p_start);
/* ldr data index */
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
/* The position of the constant pool data. */
data_index = ((p_end - p_start) - pc_offset) >> 2;
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
data_index);
fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
fprintf(outfile, " arm_ldr_ptr++;\n");
if (data_index >= sizeof(data_allocated))
error("%s: too many data", name);
if (!data_allocated[data_index]) {
ELF_RELOC *rel;
int i, addend, type;
const char *sym_name, *p;
char relname[1024];
data_allocated[data_index] = 1;
/* data value */
addend = get32((uint32_t *)(p_start + pc_offset));
relname[0] = '\0';
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset == (pc_offset + start_offset)) {
sym_name = get_rel_sym_name(rel);
/* the compiler leave some unnecessary references to the code */
get_reloc_expr(relname, sizeof(relname), sym_name);
type = ELF32_R_TYPE(rel->r_info);
if (type != R_ARM_ABS32)
error("%s: unsupported data relocation", name);
break;
}
}
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
data_index, addend);
if (relname[0] != '\0')
fprintf(outfile, " + %s", relname);
fprintf(outfile, ";\n");
}
}
}
p += 4;
}
/* Copy and relocate the constant pool data. */
data_size = (p_end - p_start) - min_offset;
if (data_size > 0 && outfile) {
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
spare += min_offset;
fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2);
fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size);
fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n"
" arm_pool_ptr = gen_code_ptr + %d;\n",
spare, spare);
data_index = 0;
for (pc_offset = min_offset;
pc_offset < p_end - p_start;
pc_offset += 4) {
ELF_RELOC *rel;
int i, addend, type;
const char *sym_name;
char relname[1024];
/* data value */
addend = get32((uint32_t *)(p_start + pc_offset));
relname[0] = '\0';
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset == (pc_offset + start_offset)) {
sym_name = get_rel_sym_name(rel);
/* the compiler leave some unnecessary references to the code */
get_reloc_expr(relname, sizeof(relname), sym_name);
type = ELF32_R_TYPE(rel->r_info);
if (type != R_ARM_ABS32)
error("%s: unsupported data relocation", name);
break;
}
}
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
data_index, addend);
if (relname[0] != '\0')
fprintf(outfile, " + %s", relname);
fprintf(outfile, ";\n");
data_index++;
}
}
/* the last instruction must be a mov pc, lr */
if (p == p_start)
goto arm_ret_error;
p -= 4;
insn = get32((uint32_t *)p);
if ((insn & 0xffff0000) != 0xe91b0000) {
/* The last instruction must be an ldm instruction. There are several
forms generated by gcc:
ldmib sp, {..., pc} (implies a sp adjustment of +4)
ldmia sp, {..., pc}
ldmea fp, {..., pc} */
if ((insn & 0xffff8000) == 0xe99d8000) {
if (outfile) {
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
p - p_start);
}
p += 4;
} else if ((insn & 0xffff8000) != 0xe89d8000
&& (insn & 0xffff8000) != 0xe91b8000) {
arm_ret_error:
if (!outfile)
printf("%s: invalid epilog\n", name);
}
return p - p_start;
return p - p_start;
}
#endif
@@ -1440,6 +1511,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_SPARC)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
uint32_t start_insn, end_insn1, end_insn2;
uint8_t *p;
p = (void *)(p_end - 8);
@@ -1448,13 +1528,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if ((start_insn & ~0x1fff) == 0x9de3a000) {
if (((start_insn & ~0x1fff) == INSN_SAVE) ||
(start_insn & ~0x1fff) == INSN_ADD_SP) {
p_start += 0x4;
start_offset += 0x4;
if ((int)(start_insn | ~0x1fff) < -128)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
/* SPARC v7: ret; restore; */ ;
else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
/* SPARC v9: return; nop; */ ;
else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
error("ret; restore; not found at end of %s", name);
} else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
;
} else {
error("No save at the beginning of %s", name);
}
@@ -1462,7 +1550,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == 0x01000000)
if (skip_insn == INSN_NOP)
p -= 4;
}
#endif
@@ -1470,21 +1558,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_SPARC64)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
#if 0
/* XXX: check why it occurs */
if (p <= p_start)
error("empty code for %s", name);
#endif
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if ((start_insn & ~0x1fff) == 0x9de3a000) {
if (((start_insn & ~0x1fff) == INSN_SAVE) ||
(start_insn & ~0x1fff) == INSN_ADD_SP) {
p_start += 0x4;
start_offset += 0x4;
if ((int)(start_insn | ~0x1fff) < -256)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
/* SPARC v7: ret; restore; */ ;
else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
/* SPARC v9: return; nop; */ ;
else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
error("ret; restore; not found at end of %s", name);
} else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
;
} else {
error("No save at the beginning of %s", name);
}
@@ -1500,6 +1608,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_ARM)
{
uint32_t insn;
if ((p_end - p_start) <= 16)
error("%s: function too small", name);
if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
@@ -1508,6 +1618,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
error("%s: invalid prolog", name);
p_start += 12;
start_offset += 12;
insn = get32((uint32_t *)p_start);
if ((insn & 0xffffff00) == 0xe24dd000) {
/* Stack adjustment. Assume op uses the frame pointer. */
p_start -= 4;
start_offset -= 4;
}
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
relocs, nb_relocs);
}
@@ -2151,6 +2267,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
case R_SPARC_WDISP22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
default:
error("unsupported sparc relocation (%d)", type);
}
@@ -2168,7 +2296,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF64_R_TYPE(rel->r_info);
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
@@ -2192,6 +2320,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
break;
case R_SPARC_OLO10:
addend += ELF64_R_TYPE_DATA (rel->r_info);
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
break;
case R_SPARC_WDISP30:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
@@ -2202,8 +2339,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
case R_SPARC_WDISP22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
default:
error("unsupported sparc64 relocation (%d)", type);
error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
}
}
}
@@ -2214,7 +2361,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
int type;
int addend;
int reloc_offset;
uint32_t insn;
insn = get32((uint32_t *)(p_start + 4));
/* If prologue ends in sub sp, sp, #const then assume
op has a stack frame and needs the frame pointer. */
if ((insn & 0xffffff00) == 0xe24dd000) {
int i;
uint32_t opcode;
opcode = 0xe28db000; /* add fp, sp, #0. */
#if 0
/* ??? Need to undo the extra stack adjustment at the end of the op.
For now just leave the stack misaligned and hope it doesn't break anything
too important. */
if ((insn & 4) != 0) {
/* Preserve doubleword stack alignment. */
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
insn + 4);
opcode -= 4;
}
#endif
insn = get32((uint32_t *)(p_start - 4));
/* Calculate the size of the saved registers,
excluding pc. */
for (i = 0; i < 15; i++) {
if (insn & (1 << i))
opcode += 4;
}
fprintf(outfile,
" *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
}
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
relocs, nb_relocs);
@@ -2235,6 +2412,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset, name, addend);
break;
case R_ARM_PC24:
case R_ARM_JUMP24:
case R_ARM_CALL:
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
reloc_offset, addend, name);
break;
@@ -2339,6 +2518,28 @@ int gen_file(FILE *outfile, int out_type)
} else {
/* generate big code generation switch */
#ifdef HOST_ARM
/* We need to know the size of all the ops so we can figure out when
to emit constant pools. This must be consistent with opc.h. */
fprintf(outfile,
"static const uint32_t arm_opc_size[] = {\n"
" 0,\n" /* end */
" 0,\n" /* nop */
" 0,\n" /* nop1 */
" 0,\n" /* nop2 */
" 0,\n"); /* nop3 */
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
name = get_sym_name(sym);
if (strstart(name, OP_PREFIX, NULL)) {
fprintf(outfile, " %d,\n", sym->st_size);
}
}
fprintf(outfile,
"};\n");
#endif
fprintf(outfile,
"int dyngen_code(uint8_t *gen_code_buf,\n"
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
@@ -2349,10 +2550,36 @@ fprintf(outfile,
" const uint32_t *opparam_ptr;\n");
#ifdef HOST_ARM
/* Arm is tricky because it uses constant pools for loading immediate values.
We assume (and require) each function is code followed by a constant pool.
All the ops are small so this should be ok. For each op we figure
out how much "spare" range we have in the load instructions. This allows
us to insert subsequent ops in between the op and the constant pool,
eliminating the neeed to jump around the pool.
We currently generate:
[ For this example we assume merging would move op1_pool out of range.
In practice we should be able to combine many ops before the offset
limits are reached. ]
op1_code;
op2_code;
goto op3;
op2_pool;
op1_pool;
op3:
op3_code;
ret;
op3_pool;
Ideally we'd put op1_pool before op2_pool, but that requires two passes.
*/
fprintf(outfile,
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
" uint32_t *arm_data_ptr = arm_data_table;\n");
" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
/* Initialise the parmissible pool offset to an arbitary large value. */
" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
#endif
#ifdef HOST_IA64
{
@@ -2421,9 +2648,23 @@ fprintf(outfile,
/* Generate prologue, if needed. */
fprintf(outfile,
" for(;;) {\n"
" switch(*opc_ptr++) {\n"
);
" for(;;) {\n");
#ifdef HOST_ARM
/* Generate constant pool if needed */
fprintf(outfile,
" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
" last_gen_code_ptr = gen_code_ptr;\n"
" arm_ldr_ptr = arm_ldr_table;\n"
" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
" }\n");
#endif
fprintf(outfile,
" switch(*opc_ptr++) {\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
@@ -2457,17 +2698,6 @@ fprintf(outfile,
" goto the_end;\n"
" }\n");
#ifdef HOST_ARM
/* generate constant table if needed */
fprintf(outfile,
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
" last_gen_code_ptr = gen_code_ptr;\n"
" arm_ldr_ptr = arm_ldr_table;\n"
" arm_data_ptr = arm_data_table;\n"
" }\n");
#endif
fprintf(outfile,
" }\n"
@@ -2485,7 +2715,10 @@ fprintf(outfile,
/* generate some code patching */
#ifdef HOST_ARM
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
fprintf(outfile,
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
#endif
/* flush instruction cache */
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");

View File

@@ -19,7 +19,13 @@
*/
int __op_param1, __op_param2, __op_param3;
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
#if defined(__sparc__) || defined(__arm__)
void __op_gen_label1(){}
void __op_gen_label2(){}
void __op_gen_label3(){}
#else
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
#endif
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
@@ -139,18 +145,16 @@ void fix_bsr(void *p, int offset) {
#ifdef __arm__
#define MAX_OP_SIZE (128 * 4) /* in bytes */
/* max size of the code that can be generated without calling arm_flush_ldr */
#define MAX_FRAG_SIZE (1024 * 4)
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
#define ARM_LDR_TABLE_SIZE 1024
typedef struct LDREntry {
uint8_t *ptr;
uint32_t *data_ptr;
unsigned type:2;
} LDREntry;
static LDREntry arm_ldr_table[1024];
static uint32_t arm_data_table[1024];
static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
extern char exec_loop;
@@ -169,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
int offset, data_size, target;
uint8_t *data_ptr;
uint32_t insn;
uint32_t mask;
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
data_size = (data_end - data_start) << 2;
if (gen_jmp) {
/* generate branch to skip the data */
@@ -192,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
(unsigned long)data_ptr -
(unsigned long)ptr - 8;
insn = *ptr & ~(0xfff | 0x00800000);
if (offset < 0) {
offset = - offset;
} else {
insn |= 0x00800000;
}
if (offset > 0xfff) {
fprintf(stderr, "Error ldr offset\n");
fprintf(stderr, "Negative constant pool offset\n");
abort();
}
insn |= offset;
switch (le->type) {
case 0: /* ldr */
mask = ~0x00800fff;
if (offset >= 4096) {
fprintf(stderr, "Bad ldr offset\n");
abort();
}
break;
case 1: /* ldc */
mask = ~0x008000ff;
if (offset >= 1024 ) {
fprintf(stderr, "Bad ldc offset\n");
abort();
}
break;
case 2: /* add */
mask = ~0xfff;
if (offset >= 1024 ) {
fprintf(stderr, "Bad add offset\n");
abort();
}
break;
default:
fprintf(stderr, "Bad pc relative fixup\n");
abort();
}
insn = *ptr & mask;
switch (le->type) {
case 0: /* ldr */
insn |= offset | 0x00800000;
break;
case 1: /* ldc */
insn |= (offset >> 2) | 0x00800000;
break;
case 2: /* add */
insn |= (offset >> 2) | 0xf00;
break;
}
*ptr = insn;
}
return gen_code_ptr;

4
elf.h
View File

@@ -227,6 +227,7 @@ typedef struct {
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
#define R_386_NONE 0
#define R_386_32 1
@@ -326,6 +327,7 @@ typedef struct {
#define R_SPARC_10 30
#define R_SPARC_11 31
#define R_SPARC_64 32
#define R_SPARC_OLO10 33
#define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41
#define R_SPARC_7 43
@@ -500,6 +502,8 @@ typedef struct {
#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
#define R_ARM_GOT32 26 /* 32 bit GOT entry */
#define R_ARM_PLT32 27 /* 32 bit PLT address */
#define R_ARM_CALL 28
#define R_ARM_JUMP24 29
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
#define R_ARM_THM_PC11 102 /* thumb unconditional branch */

View File

@@ -153,6 +153,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
glue(bswap_ehdr, SZ)(&ehdr);
}
if (ELF_MACHINE != ehdr.e_machine)
goto fail;
if (pentry)
*pentry = (uint64_t)ehdr.e_entry;
@@ -202,4 +205,3 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
qemu_free(phdr);
return -1;
}

View File

@@ -196,9 +196,19 @@ typedef struct TranslationBlock {
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
{
target_ulong tmp;
tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK;
}
static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
{
return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
target_ulong tmp;
tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
(tmp & TB_JMP_ADDR_MASK));
}
static inline unsigned int tb_phys_hash_func(unsigned long pc)
@@ -570,7 +580,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
ldub_code(addr);
}
pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM) {
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
}
return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;

66
exec.c
View File

@@ -41,6 +41,7 @@
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
//#define DEBUG_TLB
//#define DEBUG_UNASSIGNED
/* make various TB consistency checks */
//#define DEBUG_TB_CHECK
@@ -1288,14 +1289,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
tlb_flush_entry(&env->tlb_table[0][i], addr);
tlb_flush_entry(&env->tlb_table[1][i], addr);
for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
tb = env->tb_jmp_cache[i];
if (tb &&
((tb->pc & TARGET_PAGE_MASK) == addr ||
((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
env->tb_jmp_cache[i] = NULL;
}
}
/* Discard jump cache entries for any tb which might potentially
overlap the flushed page. */
i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
i = tb_jmp_cache_hash_page(addr);
memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
#if !defined(CONFIG_SOFTMMU)
if (addr < MMAP_AREA_END)
@@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
if (is_softmmu)
#endif
{
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
/* IO memory case */
address = vaddr | pd;
addend = paddr;
@@ -1513,9 +1513,11 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
te->addr_code = -1;
}
if (prot & PAGE_WRITE) {
if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
/* ROM: access is ignored (same as unassigned) */
te->addr_write = vaddr | IO_MEM_ROM;
if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
(pd & IO_MEM_ROMD)) {
/* write access calls the I/O callback */
te->addr_write = vaddr |
(pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
} else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
!cpu_physical_memory_is_dirty(pd)) {
te->addr_write = vaddr | IO_MEM_NOTDIRTY;
@@ -1779,24 +1781,50 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
{
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
CPUState *env;
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, 1);
p->phys_offset = phys_offset;
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
(phys_offset & IO_MEM_ROMD))
phys_offset += TARGET_PAGE_SIZE;
}
/* since each CPU stores ram addresses in its TLB cache, we must
reset the modified entries */
/* XXX: slow ! */
for(env = first_cpu; env != NULL; env = env->next_cpu) {
tlb_flush(env, 1);
}
}
/* XXX: temporary until new memory mapping API */
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
{
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p)
return IO_MEM_UNASSIGNED;
return p->phys_offset;
}
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read 0x%08x\n", (int)addr);
#endif
return 0;
}
static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
#endif
}
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
@@ -2048,7 +2076,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
}
}
} else {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
if (l >= 4 && ((addr & 3) == 0)) {
@@ -2103,7 +2132,8 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
(pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
(pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* do nothing */
} else {
unsigned long addr1;
@@ -2135,7 +2165,8 @@ uint32_t ldl_phys(target_phys_addr_t addr)
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
@@ -2164,7 +2195,8 @@ uint64_t ldq_phys(target_phys_addr_t addr)
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#ifdef TARGET_WORDS_BIGENDIAN

View File

@@ -6,7 +6,7 @@
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
#if defined(_BSD) && !defined(__APPLE__)
#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
@@ -22,9 +22,14 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM)
}
#endif
#if defined(_BSD)
#define lrint(d) ((long)rint(d))
#define llrint(d) ((long long)rint(d))
#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
#define lrint(d) ((int32_t)rint(d))
#define llrint(d) ((int64_t)rint(d))
#define lrintf(f) ((int32_t)rint(f))
#define llrintf(f) ((int64_t)rint(f))
#define sqrtf(f) ((float)sqrt(f))
#define remainderf(fa, fb) ((float)remainder(fa, fb))
#define rintf(f) ((float)rint(f))
#endif
#if defined(__powerpc__)
@@ -144,7 +149,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM)
{
return sqrtf(a);
}
char float32_compare( float32 a, float32 b STATUS_PARAM )
int float32_compare( float32 a, float32 b STATUS_PARAM )
{
if (a < b) {
return -1;
@@ -156,7 +161,7 @@ char float32_compare( float32 a, float32 b STATUS_PARAM )
return 2;
}
}
char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
@@ -168,7 +173,7 @@ char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
return 2;
}
}
char float32_is_signaling_nan( float32 a1)
int float32_is_signaling_nan( float32 a1)
{
float32u u;
uint32_t a;
@@ -216,6 +221,11 @@ float128 float64_to_float128( float64 a STATUS_PARAM)
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_trunc_to_int( float64 a STATUS_PARAM )
{
return trunc(a);
}
float64 float64_round_to_int( float64 a STATUS_PARAM )
{
#if defined(__arm__)
@@ -248,7 +258,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM)
{
return sqrt(a);
}
char float64_compare( float64 a, float64 b STATUS_PARAM )
int float64_compare( float64 a, float64 b STATUS_PARAM )
{
if (a < b) {
return -1;
@@ -260,7 +270,7 @@ char float64_compare( float64 a, float64 b STATUS_PARAM )
return 2;
}
}
char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
@@ -272,7 +282,7 @@ char float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
return 2;
}
}
char float64_is_signaling_nan( float64 a1)
int float64_is_signaling_nan( float64 a1)
{
float64u u;
uint64_t a;
@@ -284,6 +294,17 @@ char float64_is_signaling_nan( float64 a1)
}
int float64_is_nan( float64 a1 )
{
float64u u;
uint64_t a;
u.f = a1;
a = u.i;
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
@@ -329,7 +350,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
{
return sqrtl(a);
}
char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
{
if (a < b) {
return -1;
@@ -341,7 +362,7 @@ char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
return 2;
}
}
char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
if (isless(a, b)) {
return -1;
@@ -353,7 +374,7 @@ char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
return 2;
}
}
char floatx80_is_signaling_nan( floatx80 a1)
int floatx80_is_signaling_nan( floatx80 a1)
{
floatx80u u;
u.f = a1;

View File

@@ -152,38 +152,38 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
}
float32 float32_rem( float32, float32 STATUS_PARAM);
float32 float32_sqrt( float32 STATUS_PARAM);
INLINE char float32_eq( float32 a, float32 b STATUS_PARAM)
INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
{
return a == b;
}
INLINE char float32_le( float32 a, float32 b STATUS_PARAM)
INLINE int float32_le( float32 a, float32 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float32_lt( float32 a, float32 b STATUS_PARAM)
INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
{
return a < b;
}
INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM)
INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM)
INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
int float32_compare( float32, float32 STATUS_PARAM );
int float32_compare_quiet( float32, float32 STATUS_PARAM );
int float32_is_signaling_nan( float32 );
INLINE float32 float32_abs(float32 a)
{
@@ -214,6 +214,7 @@ float128 float64_to_float128( float64 STATUS_PARAM );
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
float64 float64_trunc_to_int( float64 STATUS_PARAM );
INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM)
{
return a + b;
@@ -232,39 +233,40 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
}
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
INLINE char float64_eq( float64 a, float64 b STATUS_PARAM)
INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
{
return a == b;
}
INLINE char float64_le( float64 a, float64 b STATUS_PARAM)
INLINE int float64_le( float64 a, float64 b STATUS_PARAM)
{
return a <= b;
}
INLINE char float64_lt( float64 a, float64 b STATUS_PARAM)
INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
{
return a < b;
}
INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM)
INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM)
INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
{
return isunordered(a, b);
}
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
int float64_compare( float64, float64 STATUS_PARAM );
int float64_compare_quiet( float64, float64 STATUS_PARAM );
int float64_is_signaling_nan( float64 );
int float64_is_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
@@ -313,39 +315,39 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
}
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
{
return a == b;
}
INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b;
}
INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
{
return a < b;
}
INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM)
{
return a <= b && a >= b;
}
INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return islessequal(a, b);
}
INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
{
return isless(a, b);
}
INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
{
return isunordered(a, b);
}
char floatx80_compare( floatx80, floatx80 STATUS_PARAM );
char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{

View File

@@ -68,7 +68,7 @@ typedef struct {
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_nan( float32 a )
int float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
@@ -80,7 +80,7 @@ flag float32_is_nan( float32 a )
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_signaling_nan( float32 a )
int float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
@@ -161,7 +161,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_nan( float64 a )
int float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
@@ -173,7 +173,7 @@ flag float64_is_nan( float64 a )
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_signaling_nan( float64 a )
int float64_is_signaling_nan( float64 a )
{
return
@@ -264,7 +264,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_nan( floatx80 a )
int floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
@@ -276,7 +276,7 @@ flag floatx80_is_nan( floatx80 a )
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_signaling_nan( floatx80 a )
int floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
@@ -371,7 +371,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_nan( float128 a )
int float128_is_nan( float128 a )
{
return
@@ -385,7 +385,7 @@ flag float128_is_nan( float128 a )
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_signaling_nan( float128 a )
int float128_is_signaling_nan( float128 a )
{
return

View File

@@ -2023,7 +2023,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_eq( float32 a, float32 b STATUS_PARAM )
int float32_eq( float32 a, float32 b STATUS_PARAM )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
@@ -2045,7 +2045,7 @@ flag float32_eq( float32 a, float32 b STATUS_PARAM )
| Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_le( float32 a, float32 b STATUS_PARAM )
int float32_le( float32 a, float32 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -2068,7 +2068,7 @@ flag float32_le( float32 a, float32 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_lt( float32 a, float32 b STATUS_PARAM )
int float32_lt( float32 a, float32 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -2092,7 +2092,7 @@ flag float32_lt( float32 a, float32 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
@@ -2112,7 +2112,7 @@ flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_le_quiet( float32 a, float32 b STATUS_PARAM )
int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -2138,7 +2138,7 @@ flag float32_le_quiet( float32 a, float32 b STATUS_PARAM )
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -2483,6 +2483,17 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
}
float64 float64_trunc_to_int( float64 a STATUS_PARAM)
{
int oldmode;
float64 res;
oldmode = STATUS(float_rounding_mode);
STATUS(float_rounding_mode) = float_round_to_zero;
res = float64_round_to_int(a STATUS_VAR);
STATUS(float_rounding_mode) = oldmode;
return res;
}
/*----------------------------------------------------------------------------
| Returns the result of adding the absolute values of the double-precision
| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
@@ -2941,7 +2952,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_eq( float64 a, float64 b STATUS_PARAM )
int float64_eq( float64 a, float64 b STATUS_PARAM )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
@@ -2963,7 +2974,7 @@ flag float64_eq( float64 a, float64 b STATUS_PARAM )
| Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_le( float64 a, float64 b STATUS_PARAM )
int float64_le( float64 a, float64 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -2986,7 +2997,7 @@ flag float64_le( float64 a, float64 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_lt( float64 a, float64 b STATUS_PARAM )
int float64_lt( float64 a, float64 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -3010,7 +3021,7 @@ flag float64_lt( float64 a, float64 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
@@ -3030,7 +3041,7 @@ flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_le_quiet( float64 a, float64 b STATUS_PARAM )
int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -3056,7 +3067,7 @@ flag float64_le_quiet( float64 a, float64 b STATUS_PARAM )
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -3879,7 +3890,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
| Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
@@ -3909,7 +3920,7 @@ flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -3942,7 +3953,7 @@ flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
| Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -3975,7 +3986,7 @@ flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
@@ -4002,7 +4013,7 @@ flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -4038,7 +4049,7 @@ flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -4999,7 +5010,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_eq( float128 a, float128 b STATUS_PARAM )
int float128_eq( float128 a, float128 b STATUS_PARAM )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
@@ -5029,7 +5040,7 @@ flag float128_eq( float128 a, float128 b STATUS_PARAM )
| Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_le( float128 a, float128 b STATUS_PARAM )
int float128_le( float128 a, float128 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -5061,7 +5072,7 @@ flag float128_le( float128 a, float128 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_lt( float128 a, float128 b STATUS_PARAM )
int float128_lt( float128 a, float128 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -5094,7 +5105,7 @@ flag float128_lt( float128 a, float128 b STATUS_PARAM )
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
@@ -5121,7 +5132,7 @@ flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_le_quiet( float128 a, float128 b STATUS_PARAM )
int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -5157,7 +5168,7 @@ flag float128_le_quiet( float128 a, float128 b STATUS_PARAM )
| Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
{
flag aSign, bSign;
@@ -5272,7 +5283,7 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
}
#define COMPARE(s, nan_exp) \
INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \
INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
int is_quiet STATUS_PARAM ) \
{ \
flag aSign, bSign; \
@@ -5306,12 +5317,12 @@ INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \
} \
} \
\
char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \
{ \
return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \
} \
\
char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
{ \
return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \
}

View File

@@ -43,7 +43,7 @@ these four paragraphs for those parts of this code that are retained.
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
| to the same as `int'.
*----------------------------------------------------------------------------*/
typedef char flag;
typedef uint8_t flag;
typedef uint8_t uint8;
typedef int8_t int8;
typedef int uint16;
@@ -228,15 +228,16 @@ float32 float32_mul( float32, float32 STATUS_PARAM );
float32 float32_div( float32, float32 STATUS_PARAM );
float32 float32_rem( float32, float32 STATUS_PARAM );
float32 float32_sqrt( float32 STATUS_PARAM );
char float32_eq( float32, float32 STATUS_PARAM );
char float32_le( float32, float32 STATUS_PARAM );
char float32_lt( float32, float32 STATUS_PARAM );
char float32_eq_signaling( float32, float32 STATUS_PARAM );
char float32_le_quiet( float32, float32 STATUS_PARAM );
char float32_lt_quiet( float32, float32 STATUS_PARAM );
char float32_compare( float32, float32 STATUS_PARAM );
char float32_compare_quiet( float32, float32 STATUS_PARAM );
char float32_is_signaling_nan( float32 );
int float32_eq( float32, float32 STATUS_PARAM );
int float32_le( float32, float32 STATUS_PARAM );
int float32_lt( float32, float32 STATUS_PARAM );
int float32_eq_signaling( float32, float32 STATUS_PARAM );
int float32_le_quiet( float32, float32 STATUS_PARAM );
int float32_lt_quiet( float32, float32 STATUS_PARAM );
int float32_compare( float32, float32 STATUS_PARAM );
int float32_compare_quiet( float32, float32 STATUS_PARAM );
int float32_is_signaling_nan( float32 );
int float64_is_nan( float64 a );
INLINE float32 float32_abs(float32 a)
{
@@ -269,21 +270,22 @@ float128 float64_to_float128( float64 STATUS_PARAM );
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 STATUS_PARAM );
float64 float64_trunc_to_int( float64 STATUS_PARAM );
float64 float64_add( float64, float64 STATUS_PARAM );
float64 float64_sub( float64, float64 STATUS_PARAM );
float64 float64_mul( float64, float64 STATUS_PARAM );
float64 float64_div( float64, float64 STATUS_PARAM );
float64 float64_rem( float64, float64 STATUS_PARAM );
float64 float64_sqrt( float64 STATUS_PARAM );
char float64_eq( float64, float64 STATUS_PARAM );
char float64_le( float64, float64 STATUS_PARAM );
char float64_lt( float64, float64 STATUS_PARAM );
char float64_eq_signaling( float64, float64 STATUS_PARAM );
char float64_le_quiet( float64, float64 STATUS_PARAM );
char float64_lt_quiet( float64, float64 STATUS_PARAM );
char float64_compare( float64, float64 STATUS_PARAM );
char float64_compare_quiet( float64, float64 STATUS_PARAM );
char float64_is_signaling_nan( float64 );
int float64_eq( float64, float64 STATUS_PARAM );
int float64_le( float64, float64 STATUS_PARAM );
int float64_lt( float64, float64 STATUS_PARAM );
int float64_eq_signaling( float64, float64 STATUS_PARAM );
int float64_le_quiet( float64, float64 STATUS_PARAM );
int float64_lt_quiet( float64, float64 STATUS_PARAM );
int float64_compare( float64, float64 STATUS_PARAM );
int float64_compare_quiet( float64, float64 STATUS_PARAM );
int float64_is_signaling_nan( float64 );
INLINE float64 float64_abs(float64 a)
{
@@ -320,13 +322,13 @@ floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
char floatx80_eq( floatx80, floatx80 STATUS_PARAM );
char floatx80_le( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt( floatx80, floatx80 STATUS_PARAM );
char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
char floatx80_is_signaling_nan( floatx80 );
int floatx80_eq( floatx80, floatx80 STATUS_PARAM );
int floatx80_le( floatx80, floatx80 STATUS_PARAM );
int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_signaling_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
@@ -367,13 +369,13 @@ float128 float128_mul( float128, float128 STATUS_PARAM );
float128 float128_div( float128, float128 STATUS_PARAM );
float128 float128_rem( float128, float128 STATUS_PARAM );
float128 float128_sqrt( float128 STATUS_PARAM );
char float128_eq( float128, float128 STATUS_PARAM );
char float128_le( float128, float128 STATUS_PARAM );
char float128_lt( float128, float128 STATUS_PARAM );
char float128_eq_signaling( float128, float128 STATUS_PARAM );
char float128_le_quiet( float128, float128 STATUS_PARAM );
char float128_lt_quiet( float128, float128 STATUS_PARAM );
char float128_is_signaling_nan( float128 );
int float128_eq( float128, float128 STATUS_PARAM );
int float128_le( float128, float128 STATUS_PARAM );
int float128_lt( float128, float128 STATUS_PARAM );
int float128_eq_signaling( float128, float128 STATUS_PARAM );
int float128_le_quiet( float128, float128 STATUS_PARAM );
int float128_lt_quiet( float128, float128 STATUS_PARAM );
int float128_is_signaling_nan( float128 );
INLINE float128 float128_abs(float128 a)
{

520
gdbstub.c
View File

@@ -17,6 +17,7 @@
* 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"
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
@@ -24,16 +25,25 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qemu.h"
#else
#include "vl.h"
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "qemu_socket.h"
#ifdef _WIN32
/* XXX: these constants may be independent of the host ones even for Unix */
#ifndef SIGTRAP
#define SIGTRAP 5
#endif
#ifndef SIGINT
#define SIGINT 2
#endif
#else
#include <signal.h>
#endif
//#define DEBUG_GDB
@@ -42,26 +52,30 @@ enum RSState {
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
RS_SYSCALL,
};
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
typedef struct GDBState {
CPUState *env; /* current CPU */
enum RSState state; /* parsing state */
int fd;
char line_buf[4096];
int line_buf_index;
int line_csum;
char last_packet[4100];
int last_packet_len;
#ifdef CONFIG_USER_ONLY
int fd;
int running_state;
#else
CharDriverState *chr;
#endif
} GDBState;
#ifdef CONFIG_USER_ONLY
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
/* XXX: remove this hack. */
static GDBState gdbserver_state;
#endif
static int get_char(GDBState *s)
{
@@ -69,7 +83,7 @@ static int get_char(GDBState *s)
int ret;
for(;;) {
ret = read(s->fd, &ch, 1);
ret = recv(s->fd, &ch, 1, 0);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
@@ -81,13 +95,36 @@ static int get_char(GDBState *s)
}
return ch;
}
#endif
/* GDB stub state for use by semihosting syscalls. */
static GDBState *gdb_syscall_state;
static gdb_syscall_complete_cb gdb_current_syscall_cb;
enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
GDB_SYS_DISABLED,
} gdb_syscall_mode;
/* If gdb is connected when the first semihosting syscall occurs then use
remote gdb syscalls. Otherwise use native file IO. */
int use_gdb_syscalls(void)
{
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED
: GDB_SYS_DISABLED);
}
return gdb_syscall_mode == GDB_SYS_ENABLED;
}
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
{
#ifdef CONFIG_USER_ONLY
int ret;
while (len > 0) {
ret = write(s->fd, buf, len);
ret = send(s->fd, buf, len, 0);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
@@ -96,6 +133,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
len -= ret;
}
}
#else
qemu_chr_write(s->chr, buf, len);
#endif
}
static inline int fromhex(int v)
@@ -144,33 +184,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len)
/* return -1 if error, 0 if OK */
static int put_packet(GDBState *s, char *buf)
{
char buf1[3];
int len, csum, ch, i;
int len, csum, i;
char *p;
#ifdef DEBUG_GDB
printf("reply='%s'\n", buf);
#endif
for(;;) {
buf1[0] = '$';
put_buffer(s, buf1, 1);
p = s->last_packet;
*(p++) = '$';
len = strlen(buf);
put_buffer(s, buf, len);
memcpy(p, buf, len);
p += len;
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
buf1[0] = '#';
buf1[1] = tohex((csum >> 4) & 0xf);
buf1[2] = tohex((csum) & 0xf);
*(p++) = '#';
*(p++) = tohex((csum >> 4) & 0xf);
*(p++) = tohex((csum) & 0xf);
put_buffer(s, buf1, 3);
s->last_packet_len = p - s->last_packet;
put_buffer(s, s->last_packet, s->last_packet_len);
ch = get_char(s);
if (ch < 0)
#ifdef CONFIG_USER_ONLY
i = get_char(s);
if (i < 0)
return -1;
if (ch == '+')
if (i == '+')
break;
#else
break;
#endif
}
return 0;
}
@@ -305,11 +351,11 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
for(i = 0; i < 24; i++) {
registers[i + 8] = tswapl(env->regwptr[i]);
}
#ifndef TARGET_SPARC64
/* fill in fprs */
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);
{
@@ -327,16 +373,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
registers[72] = 0;
return 73 * sizeof(target_ulong);
#else
for (i = 0; i < 32; i += 2) {
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
/* fill in fprs */
for (i = 0; i < 64; i += 2) {
uint64_t tmp;
tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
registers[i/2 + 32] = tmp;
}
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);
registers[64] = tswapl(env->pc);
registers[65] = tswapl(env->npc);
registers[66] = tswapl(env->tstate[env->tl]);
registers[67] = tswapl(env->fsr);
registers[68] = tswapl(env->fprs);
registers[69] = tswapl(env->y);
return 70 * sizeof(target_ulong);
#endif
}
@@ -353,11 +404,11 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i + 8]);
}
#ifndef TARGET_SPARC64
/* 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]));
@@ -367,18 +418,16 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
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;
for (i = 0; i < 64; i += 2) {
*((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
*((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff);
}
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]);
env->pc = tswapl(registers[64]);
env->npc = tswapl(registers[65]);
env->tstate[env->tl] = tswapl(registers[66]);
env->fsr = tswapl(registers[67]);
env->fprs = tswapl(registers[68]);
env->y = tswapl(registers[69]);
#endif
}
#elif defined (TARGET_ARM)
@@ -421,6 +470,73 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
ptr += 8 * 12 + 4;
cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
}
#elif defined (TARGET_M68K)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
int i;
uint8_t *ptr;
CPU_DoubleU u;
ptr = mem_buf;
/* D0-D7 */
for (i = 0; i < 8; i++) {
*(uint32_t *)ptr = tswapl(env->dregs[i]);
ptr += 4;
}
/* A0-A7 */
for (i = 0; i < 8; i++) {
*(uint32_t *)ptr = tswapl(env->aregs[i]);
ptr += 4;
}
*(uint32_t *)ptr = tswapl(env->sr);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->pc);
ptr += 4;
/* F0-F7. The 68881/68040 have 12-bit extended precision registers.
ColdFire has 8-bit double precision registers. */
for (i = 0; i < 8; i++) {
u.d = env->fregs[i];
*(uint32_t *)ptr = tswap32(u.l.upper);
*(uint32_t *)ptr = tswap32(u.l.lower);
}
/* FP control regs (not implemented). */
memset (ptr, 0, 3 * 4);
ptr += 3 * 4;
return ptr - mem_buf;
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
int i;
uint8_t *ptr;
CPU_DoubleU u;
ptr = mem_buf;
/* D0-D7 */
for (i = 0; i < 8; i++) {
env->dregs[i] = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
/* A0-A7 */
for (i = 0; i < 8; i++) {
env->aregs[i] = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
env->sr = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->pc = tswapl(*(uint32_t *)ptr);
ptr += 4;
/* F0-F7. The 68881/68040 have 12-bit extended precision registers.
ColdFire has 8-bit double precision registers. */
for (i = 0; i < 8; i++) {
u.l.upper = tswap32(*(uint32_t *)ptr);
u.l.lower = tswap32(*(uint32_t *)ptr);
env->fregs[i] = u.d;
}
/* FP control regs (not implemented). */
ptr += 3 * 4;
}
#elif defined (TARGET_MIPS)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
@@ -452,11 +568,37 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
*(uint32_t *)ptr = tswapl(env->PC);
ptr += 4;
#ifdef MIPS_USES_FPU
for (i = 0; i < 32; i++)
{
*(uint32_t *)ptr = tswapl(FPR_W (env, i));
ptr += 4;
}
*(uint32_t *)ptr = tswapl(env->fcr31);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->fcr0);
ptr += 4;
#endif
/* 32 FP registers, fsr, fir, fp. Not yet implemented. */
/* what's 'fp' mean here? */
return ptr - mem_buf;
}
/* convert MIPS rounding mode in FCR31 to IEEE library */
static unsigned int ieee_rm[] =
{
float_round_nearest_even,
float_round_to_zero,
float_round_up,
float_round_down
};
#define RESTORE_ROUNDING_MODE \
set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
int i;
@@ -486,6 +628,28 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
env->PC = tswapl(*(uint32_t *)ptr);
ptr += 4;
#ifdef MIPS_USES_FPU
for (i = 0; i < 32; i++)
{
FPR_W (env, i) = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF;
ptr += 4;
env->fcr0 = tswapl(*(uint32_t *)ptr);
ptr += 4;
/* set rounding mode */
RESTORE_ROUNDING_MODE;
#ifndef CONFIG_SOFTFLOAT
/* no floating point exception for native float */
SET_FP_ENABLE(env->fcr31, 0);
#endif
#endif
}
#elif defined (TARGET_SH4)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -494,7 +658,12 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
int i;
#define SAVE(x) *ptr++=tswapl(x)
for (i = 0; i < 16; i++) SAVE(env->gregs[i]);
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
} else {
for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
}
for (i = 8; i < 16; i++) SAVE(env->gregs[i]);
SAVE (env->pc);
SAVE (env->pr);
SAVE (env->gbr);
@@ -517,7 +686,12 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
int i;
#define LOAD(x) (x)=*ptr++;
for (i = 0; i < 16; i++) LOAD(env->gregs[i]);
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
} else {
for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
}
for (i = 8; i < 16; i++) LOAD(env->gregs[i]);
LOAD (env->pc);
LOAD (env->pr);
LOAD (env->gbr);
@@ -545,7 +719,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
uint32_t addr, len;
target_ulong addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf);
@@ -560,7 +734,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
break;
case 'c':
if (*p != '\0') {
addr = strtoul(p, (char **)&p, 16);
addr = strtoull(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
@@ -603,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
vm_start();
#endif
return RS_IDLE;
case 'F':
{
target_ulong ret;
target_ulong err;
ret = strtoull(p, (char **)&p, 16);
if (*p == ',') {
p++;
err = strtoull(p, (char **)&p, 16);
} else {
err = 0;
}
if (*p == ',')
p++;
type = *p;
if (gdb_current_syscall_cb)
gdb_current_syscall_cb(s->env, ret, err);
if (type == 'C') {
put_packet(s, "T02");
} else {
#ifdef CONFIG_USER_ONLY
s->running_state = 1;
#else
vm_start();
#endif
}
}
break;
case 'g':
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
@@ -616,10 +818,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
put_packet(s, "OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
len = strtoull(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
put_packet (s, "E14");
} else {
@@ -628,10 +830,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
}
break;
case 'M':
addr = strtoul(p, (char **)&p, 16);
addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
len = strtoull(p, (char **)&p, 16);
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
@@ -644,10 +846,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
len = strtoull(p, (char **)&p, 16);
if (type == 0 || type == 1) {
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
@@ -661,10 +863,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoul(p, (char **)&p, 16);
addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
len = strtoull(p, (char **)&p, 16);
if (type == 0 || type == 1) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
@@ -672,6 +874,18 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
goto breakpoint_error;
}
break;
#ifdef CONFIG_LINUX_USER
case 'q':
if (strncmp(p, "Offsets", 7) == 0) {
TaskState *ts = env->opaque;
sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
ts->info->data_offset, ts->info->data_offset);
put_packet(s, buf);
break;
}
/* Fall through. */
#endif
default:
// unknown_command:
/* put empty packet */
@@ -691,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
char buf[256];
int ret;
if (s->state == RS_SYSCALL)
return;
/* disable single step if it was enable */
cpu_single_step(s->env, 0);
@@ -707,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason)
}
#endif
/* Send a gdb syscall request.
This accepts limited printf-style format specifiers, specifically:
%x - target_ulong argument printed in hex.
%s - string pointer (target_ulong) and length (int) pair. */
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
{
va_list va;
char buf[256];
char *p;
target_ulong addr;
GDBState *s;
s = gdb_syscall_state;
if (!s)
return;
gdb_current_syscall_cb = cb;
s->state = RS_SYSCALL;
#ifndef CONFIG_USER_ONLY
vm_stop(EXCP_DEBUG);
#endif
s->state = RS_IDLE;
va_start(va, fmt);
p = buf;
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
fmt++;
switch (*fmt++) {
case 'x':
addr = va_arg(va, target_ulong);
p += sprintf(p, TARGET_FMT_lx, addr);
break;
case 's':
addr = va_arg(va, target_ulong);
p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int));
break;
default:
fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
fmt - 1);
break;
}
} else {
*(p++) = *(fmt++);
}
}
va_end(va);
put_packet(s, buf);
#ifdef CONFIG_USER_ONLY
gdb_handlesig(s->env, 0);
#else
cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
#endif
}
static void gdb_read_byte(GDBState *s, int ch)
{
CPUState *env = s->env;
@@ -714,6 +985,26 @@ static void gdb_read_byte(GDBState *s, int ch)
char reply[1];
#ifndef CONFIG_USER_ONLY
if (s->last_packet_len) {
/* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */
if (ch == '-') {
#ifdef DEBUG_GDB
printf("Got NACK, retransmitting\n");
#endif
put_buffer(s, s->last_packet, s->last_packet_len);
}
#ifdef DEBUG_GDB
else if (ch == '+')
printf("Got ACK\n");
else
printf("Got '%c' when expecting ACK/NACK\n", ch);
#endif
if (ch == '+' || ch == '$')
s->last_packet_len = 0;
if (ch != '$')
return;
}
if (vm_running) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
@@ -758,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch)
s->state = gdb_handle_packet(s, env, s->line_buf);
}
break;
default:
abort();
}
}
}
@@ -822,29 +1115,6 @@ void gdb_exit(CPUState *env, int code)
put_packet(s, buf);
}
#else
static void gdb_read(void *opaque)
{
GDBState *s = opaque;
int i, size;
uint8_t buf[4096];
size = read(s->fd, buf, sizeof(buf));
if (size < 0)
return;
if (size == 0) {
/* end of connection */
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
qemu_free(s);
vm_start();
} else {
for(i = 0; i < size; i++)
gdb_read_byte(s, buf[i]);
}
}
#endif
static void gdb_accept(void *opaque)
{
@@ -866,32 +1136,16 @@ static void gdb_accept(void *opaque)
/* set short latency */
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
memset (s, 0, sizeof (GDBState));
#else
s = qemu_mallocz(sizeof(GDBState));
if (!s) {
close(fd);
return;
}
#endif
s->env = first_cpu; /* XXX: allow to change CPU */
s->fd = fd;
gdb_syscall_state = s;
fcntl(fd, F_SETFL, O_NONBLOCK);
#ifndef CONFIG_USER_ONLY
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
/* start handling I/O */
qemu_set_fd_handler(s->fd, gdb_read, NULL, s);
/* when the VM is stopped, the following callback is called */
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
#endif
}
static int gdbserver_open(int port)
@@ -907,7 +1161,7 @@ static int gdbserver_open(int port)
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
@@ -922,9 +1176,6 @@ static int gdbserver_open(int port)
perror("listen");
return -1;
}
#ifndef CONFIG_USER_ONLY
fcntl(fd, F_SETFL, O_NONBLOCK);
#endif
return fd;
}
@@ -934,10 +1185,67 @@ int gdbserver_start(int port)
if (gdbserver_fd < 0)
return -1;
/* accept connections */
#ifdef CONFIG_USER_ONLY
gdb_accept (NULL);
#else
qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);
#endif
return 0;
}
#else
static int gdb_chr_can_recieve(void *opaque)
{
return 1;
}
static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size)
{
GDBState *s = opaque;
int i;
for (i = 0; i < size; i++) {
gdb_read_byte(s, buf[i]);
}
}
static void gdb_chr_event(void *opaque, int event)
{
switch (event) {
case CHR_EVENT_RESET:
vm_stop(EXCP_INTERRUPT);
gdb_syscall_state = opaque;
break;
default:
break;
}
}
int gdbserver_start(CharDriverState *chr)
{
GDBState *s;
if (!chr)
return -1;
s = qemu_mallocz(sizeof(GDBState));
if (!s) {
return -1;
}
s->env = first_cpu; /* XXX: allow to change CPU */
s->chr = chr;
qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve,
gdb_chr_event, s);
qemu_add_vm_stop_handler(gdb_vm_stopped, s);
return 0;
}
int gdbserver_start_port(int port)
{
CharDriverState *chr;
char gdbstub_port_name[128];
snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
"tcp::%d,nowait,nodelay,server", port);
chr = qemu_chr_open(gdbstub_port_name);
if (!chr)
return -EIO;
return gdbserver_start(chr);
}
#endif

View File

@@ -3,10 +3,18 @@
#define DEFAULT_GDBSTUB_PORT 1234
typedef void (*gdb_syscall_complete_cb)(CPUState *env,
target_ulong ret, target_ulong err);
void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...);
int use_gdb_syscalls(void);
#ifdef CONFIG_USER_ONLY
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
#endif
int gdbserver_start(int);
#else
int gdbserver_start(CharDriverState *chr);
int gdbserver_start_port(int port);
#endif
#endif

98
hostregs_helper.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* Save/restore host registrs.
*
* Copyright (c) 2007 CodeSourcery
*
* 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
*/
/* The GCC global register vairable extension is used to reserve some
host registers for use by dyngen. However only the core parts of the
translation engine are compiled with these settings. We must manually
save/restore these registers when called from regular code.
It is not sufficient to save/restore T0 et. al. as these may be declared
with a datatype smaller than the actual register. */
#if defined(DECLARE_HOST_REGS)
#define DO_REG(REG) \
register host_reg_t reg_AREG##REG asm(AREG##REG); \
volatile host_reg_t saved_AREG##REG;
#elif defined(SAVE_HOST_REGS)
#define DO_REG(REG) \
__asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \
saved_AREG##REG = reg_AREG##REG;
#else
#define DO_REG(REG) \
reg_AREG##REG = saved_AREG##REG; \
__asm__ __volatile__ ("" : : "r" (reg_AREG##REG));
#endif
#ifdef AREG0
DO_REG(0)
#endif
#ifdef AREG1
DO_REG(1)
#endif
#ifdef AREG2
DO_REG(2)
#endif
#ifdef AREG3
DO_REG(3)
#endif
#ifdef AREG4
DO_REG(4)
#endif
#ifdef AREG5
DO_REG(5)
#endif
#ifdef AREG6
DO_REG(6)
#endif
#ifdef AREG7
DO_REG(7)
#endif
#ifdef AREG8
DO_REG(8)
#endif
#ifdef AREG9
DO_REG(9)
#endif
#ifdef AREG10
DO_REG(10)
#endif
#ifdef AREG11
DO_REG(11)
#endif
#undef SAVE_HOST_REGS
#undef DECLARE_HOST_REGS
#undef DO_REG

523
hw/acpi.c Normal file
View File

@@ -0,0 +1,523 @@
/*
* ACPI implementation
*
* Copyright (c) 2006 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* 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 "vl.h"
//#define DEBUG
/* i82731AB (PIIX4) compatible power management function */
#define PM_FREQ 3579545
#define ACPI_DBG_IO_ADDR 0xb044
#define SMB_IO_BASE 0xb100
typedef struct PIIX4PMState {
PCIDevice dev;
uint16_t pmsts;
uint16_t pmen;
uint16_t pmcntrl;
uint8_t apmc;
uint8_t apms;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
SMBusDevice *smb_dev[128];
uint8_t smb_stat;
uint8_t smb_ctl;
uint8_t smb_cmd;
uint8_t smb_addr;
uint8_t smb_data0;
uint8_t smb_data1;
uint8_t smb_data[32];
uint8_t smb_index;
} PIIX4PMState;
#define RTC_EN (1 << 10)
#define PWRBTN_EN (1 << 8)
#define GBL_EN (1 << 5)
#define TMROF_EN (1 << 0)
#define SCI_EN (1 << 0)
#define SUS_EN (1 << 13)
#define SMBHSTSTS 0x00
#define SMBHSTCNT 0x02
#define SMBHSTCMD 0x03
#define SMBHSTADD 0x04
#define SMBHSTDAT0 0x05
#define SMBHSTDAT1 0x06
#define SMBBLKDAT 0x07
/* Note: only used for piix4_smbus_register_device */
static PIIX4PMState *piix4_pm_state;
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
return d & 0xffffff;
}
static int get_pmsts(PIIX4PMState *s)
{
int64_t d;
int pmsts;
pmsts = s->pmsts;
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
if (d >= s->tmr_overflow_time)
s->pmsts |= TMROF_EN;
return pmsts;
}
static void pm_update_sci(PIIX4PMState *s)
{
int sci_level, pmsts;
int64_t expire_time;
pmsts = get_pmsts(s);
sci_level = (((pmsts & s->pmen) &
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
pci_set_irq(&s->dev, 0, sci_level);
/* schedule a timer interruption if needed */
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
qemu_mod_timer(s->tmr_timer, expire_time);
} else {
qemu_del_timer(s->tmr_timer);
}
}
static void pm_tmr_timer(void *opaque)
{
PIIX4PMState *s = opaque;
pm_update_sci(s);
}
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
addr &= 0x3f;
switch(addr) {
case 0x00:
{
int64_t d;
int pmsts;
pmsts = get_pmsts(s);
if (pmsts & val & TMROF_EN) {
/* if TMRSTS is reset, then compute the new overflow time */
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
}
s->pmsts &= ~val;
pm_update_sci(s);
}
break;
case 0x02:
s->pmen = val;
pm_update_sci(s);
break;
case 0x04:
{
int sus_typ;
s->pmcntrl = val & ~(SUS_EN);
if (val & SUS_EN) {
/* change suspend type */
sus_typ = (val >> 10) & 3;
switch(sus_typ) {
case 0: /* soft power off */
qemu_system_shutdown_request();
break;
default:
break;
}
}
}
break;
default:
break;
}
#ifdef DEBUG
printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
#endif
}
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case 0x00:
val = get_pmsts(s);
break;
case 0x02:
val = s->pmen;
break;
case 0x04:
val = s->pmcntrl;
break;
default:
val = 0;
break;
}
#ifdef DEBUG
printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
#endif
return val;
}
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
// PIIX4PMState *s = opaque;
addr &= 0x3f;
#ifdef DEBUG
printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
#endif
}
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case 0x08:
val = get_pmtmr(s);
break;
default:
val = 0;
break;
}
#ifdef DEBUG
printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
#endif
return val;
}
static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
addr &= 1;
#ifdef DEBUG
printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
#endif
if (addr == 0) {
s->apmc = val;
if (s->dev.config[0x5b] & (1 << 1)) {
cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
}
} else {
s->apms = val;
}
}
static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 1;
if (addr == 0) {
val = s->apmc;
} else {
val = s->apms;
}
#ifdef DEBUG
printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val);
#endif
return val;
}
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
{
#if defined(DEBUG)
printf("ACPI: DBG: 0x%08x\n", val);
#endif
}
static void smb_transaction(PIIX4PMState *s)
{
uint8_t prot = (s->smb_ctl >> 2) & 0x07;
uint8_t read = s->smb_addr & 0x01;
uint8_t cmd = s->smb_cmd;
uint8_t addr = s->smb_addr >> 1;
SMBusDevice *dev = s->smb_dev[addr];
#ifdef DEBUG
printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
#endif
if (!dev) goto error;
switch(prot) {
case 0x0:
if (!dev->quick_cmd) goto error;
(*dev->quick_cmd)(dev, read);
break;
case 0x1:
if (read) {
if (!dev->receive_byte) goto error;
s->smb_data0 = (*dev->receive_byte)(dev);
}
else {
if (!dev->send_byte) goto error;
(*dev->send_byte)(dev, cmd);
}
break;
case 0x2:
if (read) {
if (!dev->read_byte) goto error;
s->smb_data0 = (*dev->read_byte)(dev, cmd);
}
else {
if (!dev->write_byte) goto error;
(*dev->write_byte)(dev, cmd, s->smb_data0);
}
break;
case 0x3:
if (read) {
uint16_t val;
if (!dev->read_word) goto error;
val = (*dev->read_word)(dev, cmd);
s->smb_data0 = val;
s->smb_data1 = val >> 8;
}
else {
if (!dev->write_word) goto error;
(*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0);
}
break;
case 0x5:
if (read) {
if (!dev->read_block) goto error;
s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data);
}
else {
if (!dev->write_block) goto error;
(*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data);
}
break;
default:
goto error;
}
return;
error:
s->smb_stat |= 0x04;
}
static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
addr &= 0x3f;
#ifdef DEBUG
printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
#endif
switch(addr) {
case SMBHSTSTS:
s->smb_stat = 0;
s->smb_index = 0;
break;
case SMBHSTCNT:
s->smb_ctl = val;
if (val & 0x40)
smb_transaction(s);
break;
case SMBHSTCMD:
s->smb_cmd = val;
break;
case SMBHSTADD:
s->smb_addr = val;
break;
case SMBHSTDAT0:
s->smb_data0 = val;
break;
case SMBHSTDAT1:
s->smb_data1 = val;
break;
case SMBBLKDAT:
s->smb_data[s->smb_index++] = val;
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
break;
}
}
static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case SMBHSTSTS:
val = s->smb_stat;
break;
case SMBHSTCNT:
s->smb_index = 0;
val = s->smb_ctl & 0x1f;
break;
case SMBHSTCMD:
val = s->smb_cmd;
break;
case SMBHSTADD:
val = s->smb_addr;
break;
case SMBHSTDAT0:
val = s->smb_data0;
break;
case SMBHSTDAT1:
val = s->smb_data1;
break;
case SMBBLKDAT:
val = s->smb_data[s->smb_index++];
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
val = 0;
break;
}
#ifdef DEBUG
printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
#endif
return val;
}
static void pm_io_space_update(PIIX4PMState *s)
{
uint32_t pm_io_base;
if (s->dev.config[0x80] & 1) {
pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
pm_io_base &= 0xfffe;
/* XXX: need to improve memory and ioport allocation */
#if defined(DEBUG)
printf("PM: mapping to 0x%x\n", pm_io_base);
#endif
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
}
}
static void pm_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
pci_default_write_config(d, address, val, len);
if (address == 0x80)
pm_io_space_update((PIIX4PMState *)d);
}
static void pm_save(QEMUFile* f,void *opaque)
{
PIIX4PMState *s = opaque;
pci_device_save(&s->dev, f);
qemu_put_be16s(f, &s->pmsts);
qemu_put_be16s(f, &s->pmen);
qemu_put_be16s(f, &s->pmcntrl);
qemu_put_8s(f, &s->apmc);
qemu_put_8s(f, &s->apms);
qemu_put_timer(f, s->tmr_timer);
qemu_put_be64s(f, &s->tmr_overflow_time);
}
static int pm_load(QEMUFile* f,void* opaque,int version_id)
{
PIIX4PMState *s = opaque;
int ret;
if (version_id > 1)
return -EINVAL;
ret = pci_device_load(&s->dev, f);
if (ret < 0)
return ret;
qemu_get_be16s(f, &s->pmsts);
qemu_get_be16s(f, &s->pmen);
qemu_get_be16s(f, &s->pmcntrl);
qemu_get_8s(f, &s->apmc);
qemu_get_8s(f, &s->apms);
qemu_get_timer(f, s->tmr_timer);
qemu_get_be64s(f, &s->tmr_overflow_time);
pm_io_space_update(s);
return 0;
}
void piix4_pm_init(PCIBus *bus, int devfn)
{
PIIX4PMState *s;
uint8_t *pci_conf;
uint32_t pm_io_base, smb_io_base;
s = (PIIX4PMState *)pci_register_device(bus,
"PM", sizeof(PIIX4PMState),
devfn, NULL, pm_write_config);
pci_conf = s->dev.config;
pci_conf[0x00] = 0x86;
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x13;
pci_conf[0x03] = 0x71;
pci_conf[0x08] = 0x00; // revision number
pci_conf[0x09] = 0x00;
pci_conf[0x0a] = 0x80; // other bridge device
pci_conf[0x0b] = 0x06; // bridge device
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 0x01; // interrupt pin 1
pci_conf[0x40] = 0x01; /* PM io base read only bit */
register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
/* XXX: which specification is used ? The i82731AB has different
mappings */
pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
pci_conf[0x63] = 0x60;
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
(serial_hds[1] != NULL ? 0x90 : 0);
smb_io_base = SMB_IO_BASE;
pci_conf[0x90] = smb_io_base | 1;
pci_conf[0x91] = smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
piix4_pm_state = s;
}
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr)
{
piix4_pm_state->smb_dev[addr] = dev;
}

View File

@@ -406,5 +406,5 @@ void adb_mouse_init(ADBBusState *bus)
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
adb_mouse_reset, s);
adb_mouse_reset(d);
qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
}

View File

@@ -301,6 +301,7 @@ int Adlib_init (AudioState *audio)
as.freq = conf.freq;
as.nchannels = SHIFT;
as.fmt = AUD_FMT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
AUD_register_card (audio, "adlib", &s->card);
@@ -310,8 +311,7 @@ int Adlib_init (AudioState *audio)
"adlib",
s,
adlib_callback,
&as,
0 /* XXX: little endian? */
&as
);
if (!s->voice) {
Adlib_fini (s);

259
hw/apb_pci.c Normal file
View File

@@ -0,0 +1,259 @@
/*
* QEMU Ultrasparc APB PCI host
*
* Copyright (c) 2006 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.
*/
/* XXX This file and most of its contests are somewhat misnamed. The
Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is
the secondary PCI bridge. */
#include "vl.h"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
typedef PCIHostState APBState;
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
APBState *s = opaque;
int i;
for (i = 11; i < 32; i++) {
if ((val & (1 << i)) != 0)
break;
}
s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
}
static uint32_t pci_apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
APBState *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 CPUWriteMemoryFunc *pci_apb_write[] = {
&pci_host_data_writeb,
&pci_host_data_writew,
&pci_host_data_writel,
};
static CPUReadMemoryFunc *pci_apb_read[] = {
&pci_host_data_readb,
&pci_host_data_readw,
&pci_host_data_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,
};
/* The APB host has an IRQ line for each IRQ line of each slot. */
static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
{
return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
}
static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
{
int bus_offset;
if (pci_dev->devfn & 1)
bus_offset = 16;
else
bus_offset = 0;
return bus_offset + irq_num;
}
static void pci_apb_set_irq(void *pic, int irq_num, int level)
{
/* PCI IRQ map onto the first 32 INO. */
pic_set_irq_new(pic, irq_num, level);
}
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
void *pic)
{
APBState *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
PCIDevice *apb;
PCIBus *secondary;
s = qemu_mallocz(sizeof(APBState));
/* Ultrasparc PBM main bus */
s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
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->bus, "Advanced PCI Bus", sizeof(PCIDevice),
0, NULL, NULL);
d->config[0x00] = 0x8e; // vendor_id : Sun
d->config[0x01] = 0x10;
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
/* APB secondary busses */
secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1");
pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2");
return secondary;
}

View File

@@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_set_apic_base: %016llx\n", val);
printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
#endif
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
@@ -255,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
#endif
return s->apicbase;
}
@@ -382,8 +382,6 @@ 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;
@@ -391,7 +389,8 @@ static void apic_init_ipi(APICState *s)
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));
for(i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = 1 << 16; /* mask LVT */
s->esr = 0;
memset(s->icr, 0, sizeof(s->icr));
s->divide_conf = 0;
@@ -477,9 +476,9 @@ int apic_get_interrupt(CPUState *env)
intno = get_highest_priority_int(s->irr);
if (intno < 0)
return -1;
reset_bit(s->irr, intno);
if (s->tpr && intno <= s->tpr)
return s->spurious_vec & 0xff;
reset_bit(s->irr, intno);
set_bit(s->isr, intno);
apic_update_irq(s);
return intno;
@@ -745,6 +744,8 @@ static void apic_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &s->initial_count);
qemu_put_be64s(f, &s->initial_count_load_time);
qemu_put_be64s(f, &s->next_time);
qemu_put_timer(f, s->timer);
}
static int apic_load(QEMUFile *f, void *opaque, int version_id)
@@ -752,7 +753,7 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
APICState *s = opaque;
int i;
if (version_id != 1)
if (version_id > 2)
return -EINVAL;
/* XXX: what if the base changes? (registered memory regions) */
@@ -779,6 +780,9 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s(f, &s->initial_count);
qemu_get_be64s(f, &s->initial_count_load_time);
qemu_get_be64s(f, &s->next_time);
if (version_id >= 2)
qemu_get_timer(f, s->timer);
return 0;
}
@@ -827,7 +831,7 @@ int apic_init(CPUState *env)
}
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
register_savevm("apic", 0, 1, apic_save, apic_load, s);
register_savevm("apic", 0, 2, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
local_apics[s->id] = s;

View File

@@ -64,42 +64,52 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size,
stl_raw(p++, 0);
}
void arm_load_kernel(int ram_size, const char *kernel_filename,
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
int board_id)
{
int kernel_size;
int initrd_size;
int n;
uint64_t entry;
/* Load the kernel. */
if (!kernel_filename) {
fprintf(stderr, "Kernel image must be specified\n");
exit(1);
}
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);
}
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 initrd '%s'\n",
initrd_filename);
kernel_size = load_elf(kernel_filename, 0, &entry);
if (kernel_size >= 0) {
/* An ELF image. Jump to the entry point. */
env->regs[15] = entry & 0xfffffffe;
env->thumb = entry & 1;
} else {
/* Raw binary image. Assume it is a Linux zImage. */
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);
}
} else {
initrd_size = 0;
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 initrd '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_size = 0;
}
bootloader[1] |= board_id & 0xff;
bootloader[2] |= (board_id >> 8) & 0xff;
bootloader[5] = KERNEL_ARGS_ADDR;
bootloader[6] = KERNEL_LOAD_ADDR;
for (n = 0; n < sizeof(bootloader) / 4; n++)
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
set_kernel_args(ram_size, initrd_size, kernel_cmdline);
}
bootloader[1] |= board_id & 0xff;
bootloader[2] |= (board_id >> 8) & 0xff;
bootloader[5] = KERNEL_ARGS_ADDR;
bootloader[6] = KERNEL_LOAD_ADDR;
for (n = 0; n < sizeof(bootloader) / 4; n++)
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
set_kernel_args(ram_size, initrd_size, kernel_cmdline);
}

547
hw/arm_gic.c Normal file
View File

@@ -0,0 +1,547 @@
/*
* ARM AMBA Generic/Distributed Interrupt Controller
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
*/
/* TODO: Some variants of this controller can handle multiple CPUs.
Currently only single CPU operation is implemented. */
#include "vl.h"
#include "arm_pic.h"
//#define DEBUG_GIC
#ifdef DEBUG_GIC
#define DPRINTF(fmt, args...) \
do { printf("arm_gic: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...) do {} while(0)
#endif
/* Distributed interrupt controller. */
static const uint8_t gic_id[] =
{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
#define GIC_NIRQ 96
typedef struct gic_irq_state
{
unsigned enabled:1;
unsigned pending:1;
unsigned active:1;
unsigned level:1;
unsigned model:1; /* 0 = 1:N, 1 = N:N */
unsigned trigger:1; /* nonzero = edge triggered. */
} gic_irq_state;
#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
#define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1
#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0
#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending
#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1
#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0
#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
#define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1
#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0
#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level
#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
typedef struct gic_state
{
arm_pic_handler handler;
uint32_t base;
void *parent;
int parent_irq;
int enabled;
int cpu_enabled;
gic_irq_state irq_state[GIC_NIRQ];
int irq_target[GIC_NIRQ];
int priority[GIC_NIRQ];
int last_active[GIC_NIRQ];
int priority_mask;
int running_irq;
int running_priority;
int current_pending;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
/* Update interrupt status after enabled or pending bits have been changed. */
static void gic_update(gic_state *s)
{
int best_irq;
int best_prio;
int irq;
s->current_pending = 1023;
if (!s->enabled || !s->cpu_enabled) {
pic_set_irq_new(s->parent, s->parent_irq, 0);
return;
}
best_prio = 0x100;
best_irq = 1023;
for (irq = 0; irq < 96; irq++) {
if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {
if (s->priority[irq] < best_prio) {
best_prio = s->priority[irq];
best_irq = irq;
}
}
}
if (best_prio > s->priority_mask) {
pic_set_irq_new(s->parent, s->parent_irq, 0);
} else {
s->current_pending = best_irq;
if (best_prio < s->running_priority) {
DPRINTF("Raised pending IRQ %d\n", best_irq);
pic_set_irq_new(s->parent, s->parent_irq, 1);
}
}
}
static void gic_set_irq(void *opaque, int irq, int level)
{
gic_state *s = (gic_state *)opaque;
/* The first external input line is internal interrupt 32. */
irq += 32;
if (level == GIC_TEST_LEVEL(irq))
return;
if (level) {
GIC_SET_LEVEL(irq);
if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
DPRINTF("Set %d pending\n", irq);
GIC_SET_PENDING(irq);
}
} else {
GIC_CLEAR_LEVEL(irq);
}
gic_update(s);
}
static void gic_set_running_irq(gic_state *s, int irq)
{
s->running_irq = irq;
if (irq == 1023)
s->running_priority = 0x100;
else
s->running_priority = s->priority[irq];
gic_update(s);
}
static uint32_t gic_acknowledge_irq(gic_state *s)
{
int new_irq;
new_irq = s->current_pending;
if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {
DPRINTF("ACK no pending IRQ\n");
return 1023;
}
pic_set_irq_new(s->parent, s->parent_irq, 0);
s->last_active[new_irq] = s->running_irq;
/* For level triggered interrupts we clear the pending bit while
the interrupt is active. */
GIC_CLEAR_PENDING(new_irq);
gic_set_running_irq(s, new_irq);
DPRINTF("ACK %d\n", new_irq);
return new_irq;
}
static void gic_complete_irq(gic_state * s, int irq)
{
int update = 0;
DPRINTF("EOI %d\n", irq);
if (s->running_irq == 1023)
return; /* No active IRQ. */
if (irq != 1023) {
/* Mark level triggered interrupts as pending if they are still
raised. */
if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
&& GIC_TEST_LEVEL(irq)) {
GIC_SET_PENDING(irq);
update = 1;
}
}
if (irq != s->running_irq) {
/* Complete an IRQ that is not currently running. */
int tmp = s->running_irq;
while (s->last_active[tmp] != 1023) {
if (s->last_active[tmp] == irq) {
s->last_active[tmp] = s->last_active[irq];
break;
}
tmp = s->last_active[tmp];
}
if (update) {
gic_update(s);
}
} else {
/* Complete the current running IRQ. */
gic_set_running_irq(s, s->last_active[s->running_irq]);
}
}
static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
{
gic_state *s = (gic_state *)opaque;
uint32_t res;
int irq;
int i;
offset -= s->base + 0x1000;
if (offset < 0x100) {
if (offset == 0)
return s->enabled;
if (offset == 4)
return (GIC_NIRQ / 32) - 1;
if (offset < 0x08)
return 0;
goto bad_reg;
} else if (offset < 0x200) {
/* Interrupt Set/Clear Enable. */
if (offset < 0x180)
irq = (offset - 0x100) * 8;
else
irq = (offset - 0x180) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
if (GIC_TEST_ENABLED(irq + i)) {
res |= (1 << i);
}
}
} else if (offset < 0x300) {
/* Interrupt Set/Clear Pending. */
if (offset < 0x280)
irq = (offset - 0x200) * 8;
else
irq = (offset - 0x280) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
if (GIC_TEST_PENDING(irq + i)) {
res |= (1 << i);
}
}
} else if (offset < 0x400) {
/* Interrupt Active. */
irq = (offset - 0x300) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
if (GIC_TEST_ACTIVE(irq + i)) {
res |= (1 << i);
}
}
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = offset - 0x400;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = s->priority[irq];
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = offset - 0x800;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = s->irq_target[irq];
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 2;
if (irq >= GIC_NIRQ)
goto bad_reg;
res = 0;
for (i = 0; i < 4; i++) {
if (GIC_TEST_MODEL(irq + i))
res |= (1 << (i * 2));
if (GIC_TEST_TRIGGER(irq + i))
res |= (2 << (i * 2));
}
} else if (offset < 0xfe0) {
goto bad_reg;
} else /* offset >= 0xfe0 */ {
if (offset & 3) {
res = 0;
} else {
res = gic_id[(offset - 0xfe0) >> 2];
}
}
return res;
bad_reg:
cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset);
return 0;
}
static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
{
uint32_t val;
val = gic_dist_readb(opaque, offset);
val |= gic_dist_readb(opaque, offset + 1) << 8;
return val;
}
static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
{
uint32_t val;
val = gic_dist_readw(opaque, offset);
val |= gic_dist_readw(opaque, offset + 2) << 16;
return val;
}
static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
gic_state *s = (gic_state *)opaque;
int irq;
int i;
offset -= s->base + 0x1000;
if (offset < 0x100) {
if (offset == 0) {
s->enabled = (value & 1);
DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
} else if (offset < 4) {
/* ignored. */
} else {
goto bad_reg;
}
} else if (offset < 0x180) {
/* Interrupt Set Enable. */
irq = (offset - 0x100) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
if (!GIC_TEST_ENABLED(irq + i))
DPRINTF("Enabled IRQ %d\n", irq + i);
GIC_SET_ENABLED(irq + i);
/* If a raised level triggered IRQ enabled then mark
is as pending. */
if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i))
GIC_SET_PENDING(irq + i);
}
}
} else if (offset < 0x200) {
/* Interrupt Clear Enable. */
irq = (offset - 0x180) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
if (GIC_TEST_ENABLED(irq + i))
DPRINTF("Disabled IRQ %d\n", irq + i);
GIC_CLEAR_ENABLED(irq + i);
}
}
} else if (offset < 0x280) {
/* Interrupt Set Pending. */
irq = (offset - 0x200) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
GIC_SET_PENDING(irq + i);
}
}
} else if (offset < 0x300) {
/* Interrupt Clear Pending. */
irq = (offset - 0x280) * 8;
if (irq >= GIC_NIRQ)
goto bad_reg;
for (i = 0; i < 8; i++) {
if (value & (1 << i)) {
GIC_CLEAR_PENDING(irq + i);
}
}
} else if (offset < 0x400) {
/* Interrupt Active. */
goto bad_reg;
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = offset - 0x400;
if (irq >= GIC_NIRQ)
goto bad_reg;
s->priority[irq] = value;
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = offset - 0x800;
if (irq >= GIC_NIRQ)
goto bad_reg;
s->irq_target[irq] = value;
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 4;
if (irq >= GIC_NIRQ)
goto bad_reg;
for (i = 0; i < 4; i++) {
if (value & (1 << (i * 2))) {
GIC_SET_MODEL(irq + i);
} else {
GIC_CLEAR_MODEL(irq + i);
}
if (value & (2 << (i * 2))) {
GIC_SET_TRIGGER(irq + i);
} else {
GIC_CLEAR_TRIGGER(irq + i);
}
}
} else {
/* 0xf00 is only handled for word writes. */
goto bad_reg;
}
gic_update(s);
return;
bad_reg:
cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);
}
static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
gic_state *s = (gic_state *)opaque;
if (offset - s->base == 0xf00) {
GIC_SET_PENDING(value & 0x3ff);
gic_update(s);
return;
}
gic_dist_writeb(opaque, offset, value & 0xff);
gic_dist_writeb(opaque, offset + 1, value >> 8);
}
static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
gic_dist_writew(opaque, offset, value & 0xffff);
gic_dist_writew(opaque, offset + 2, value >> 16);
}
static CPUReadMemoryFunc *gic_dist_readfn[] = {
gic_dist_readb,
gic_dist_readw,
gic_dist_readl
};
static CPUWriteMemoryFunc *gic_dist_writefn[] = {
gic_dist_writeb,
gic_dist_writew,
gic_dist_writel
};
static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset)
{
gic_state *s = (gic_state *)opaque;
offset -= s->base;
switch (offset) {
case 0x00: /* Control */
return s->cpu_enabled;
case 0x04: /* Priority mask */
return s->priority_mask;
case 0x08: /* Binary Point */
/* ??? Not implemented. */
return 0;
case 0x0c: /* Acknowledge */
return gic_acknowledge_irq(s);
case 0x14: /* Runing Priority */
return s->running_priority;
case 0x18: /* Highest Pending Interrupt */
return s->current_pending;
default:
cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
return 0;
}
}
static void gic_cpu_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
gic_state *s = (gic_state *)opaque;
offset -= s->base;
switch (offset) {
case 0x00: /* Control */
s->cpu_enabled = (value & 1);
DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
break;
case 0x04: /* Priority mask */
s->priority_mask = (value & 0x3ff);
break;
case 0x08: /* Binary Point */
/* ??? Not implemented. */
break;
case 0x10: /* End Of Interrupt */
return gic_complete_irq(s, value & 0x3ff);
default:
cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
return;
}
gic_update(s);
}
static CPUReadMemoryFunc *gic_cpu_readfn[] = {
gic_cpu_read,
gic_cpu_read,
gic_cpu_read
};
static CPUWriteMemoryFunc *gic_cpu_writefn[] = {
gic_cpu_write,
gic_cpu_write,
gic_cpu_write
};
static void gic_reset(gic_state *s)
{
int i;
memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
s->priority_mask = 0xf0;
s->current_pending = 1023;
s->running_irq = 1023;
s->running_priority = 0x100;
for (i = 0; i < 15; i++) {
GIC_SET_ENABLED(i);
GIC_SET_TRIGGER(i);
}
s->enabled = 0;
s->cpu_enabled = 0;
}
void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
{
gic_state *s;
int iomemtype;
s = (gic_state *)qemu_mallocz(sizeof(gic_state));
if (!s)
return NULL;
s->handler = gic_set_irq;
s->parent = parent;
s->parent_irq = parent_irq;
if (base != 0xffffffff) {
iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
gic_cpu_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
gic_dist_writefn, s);
cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
s->base = base;
} else {
s->base = 0;
}
gic_reset(s);
return s;
}

208
hw/arm_sysctl.c Normal file
View File

@@ -0,0 +1,208 @@
/*
* Status and system control registers for ARM RealView/Versatile boards.
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
*/
#include "vl.h"
#include "arm_pic.h"
#define LOCK_VALUE 0xa05f
typedef struct {
uint32_t base;
uint32_t sys_id;
uint32_t leds;
uint16_t lockval;
uint32_t cfgdata1;
uint32_t cfgdata2;
uint32_t flags;
uint32_t nvflags;
uint32_t resetlevel;
} arm_sysctl_state;
static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
{
arm_sysctl_state *s = (arm_sysctl_state *)opaque;
offset -= s->base;
switch (offset) {
case 0x00: /* ID */
return s->sys_id;
case 0x04: /* SW */
/* General purpose hardware switches.
We don't have a useful way of exposing these to the user. */
return 0;
case 0x08: /* LED */
return s->leds;
case 0x20: /* LOCK */
return s->lockval;
case 0x0c: /* OSC0 */
case 0x10: /* OSC1 */
case 0x14: /* OSC2 */
case 0x18: /* OSC3 */
case 0x1c: /* OSC4 */
case 0x24: /* 100HZ */
/* ??? Implement these. */
return 0;
case 0x28: /* CFGDATA1 */
return s->cfgdata1;
case 0x2c: /* CFGDATA2 */
return s->cfgdata2;
case 0x30: /* FLAGS */
return s->flags;
case 0x38: /* NVFLAGS */
return s->nvflags;
case 0x40: /* RESETCTL */
return s->resetlevel;
case 0x44: /* PCICTL */
return 1;
case 0x48: /* MCI */
return 0;
case 0x4c: /* FLASH */
return 0;
case 0x50: /* CLCD */
return 0x1000;
case 0x54: /* CLCDSER */
return 0;
case 0x58: /* BOOTCS */
return 0;
case 0x5c: /* 24MHz */
/* ??? not implemented. */
return 0;
case 0x60: /* MISC */
return 0;
case 0x84: /* PROCID0 */
/* ??? Don't know what the proper value for the core tile ID is. */
return 0x02000000;
case 0x88: /* PROCID1 */
return 0xff000000;
case 0x64: /* DMAPSR0 */
case 0x68: /* DMAPSR1 */
case 0x6c: /* DMAPSR2 */
case 0x70: /* IOSEL */
case 0x74: /* PLDCTL */
case 0x80: /* BUSID */
case 0x8c: /* OSCRESET0 */
case 0x90: /* OSCRESET1 */
case 0x94: /* OSCRESET2 */
case 0x98: /* OSCRESET3 */
case 0x9c: /* OSCRESET4 */
case 0xc0: /* SYS_TEST_OSC0 */
case 0xc4: /* SYS_TEST_OSC1 */
case 0xc8: /* SYS_TEST_OSC2 */
case 0xcc: /* SYS_TEST_OSC3 */
case 0xd0: /* SYS_TEST_OSC4 */
return 0;
default:
printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
return 0;
}
}
static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
uint32_t val)
{
arm_sysctl_state *s = (arm_sysctl_state *)opaque;
offset -= s->base;
switch (offset) {
case 0x08: /* LED */
s->leds = val;
case 0x0c: /* OSC0 */
case 0x10: /* OSC1 */
case 0x14: /* OSC2 */
case 0x18: /* OSC3 */
case 0x1c: /* OSC4 */
/* ??? */
break;
case 0x20: /* LOCK */
if (val == LOCK_VALUE)
s->lockval = val;
else
s->lockval = val & 0x7fff;
break;
case 0x28: /* CFGDATA1 */
/* ??? Need to implement this. */
s->cfgdata1 = val;
break;
case 0x2c: /* CFGDATA2 */
/* ??? Need to implement this. */
s->cfgdata2 = val;
break;
case 0x30: /* FLAGSSET */
s->flags |= val;
break;
case 0x34: /* FLAGSCLR */
s->flags &= ~val;
break;
case 0x38: /* NVFLAGSSET */
s->nvflags |= val;
break;
case 0x3c: /* NVFLAGSCLR */
s->nvflags &= ~val;
break;
case 0x40: /* RESETCTL */
if (s->lockval == LOCK_VALUE) {
s->resetlevel = val;
if (val & 0x100)
cpu_abort(cpu_single_env, "Board reset\n");
}
break;
case 0x44: /* PCICTL */
/* nothing to do. */
break;
case 0x4c: /* FLASH */
case 0x50: /* CLCD */
case 0x54: /* CLCDSER */
case 0x64: /* DMAPSR0 */
case 0x68: /* DMAPSR1 */
case 0x6c: /* DMAPSR2 */
case 0x70: /* IOSEL */
case 0x74: /* PLDCTL */
case 0x80: /* BUSID */
case 0x84: /* PROCID0 */
case 0x88: /* PROCID1 */
case 0x8c: /* OSCRESET0 */
case 0x90: /* OSCRESET1 */
case 0x94: /* OSCRESET2 */
case 0x98: /* OSCRESET3 */
case 0x9c: /* OSCRESET4 */
break;
default:
printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
return;
}
}
static CPUReadMemoryFunc *arm_sysctl_readfn[] = {
arm_sysctl_read,
arm_sysctl_read,
arm_sysctl_read
};
static CPUWriteMemoryFunc *arm_sysctl_writefn[] = {
arm_sysctl_write,
arm_sysctl_write,
arm_sysctl_write
};
void arm_sysctl_init(uint32_t base, uint32_t sys_id)
{
arm_sysctl_state *s;
int iomemtype;
s = (arm_sysctl_state *)qemu_mallocz(sizeof(arm_sysctl_state));
if (!s)
return;
s->base = base;
s->sys_id = sys_id;
iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn,
arm_sysctl_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
/* ??? Save/restore. */
}

View File

@@ -107,29 +107,29 @@ static void arm_timer_update(arm_timer_state *s, int64_t now)
/* Return the current value of the timer. */
static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
{
int64_t elapsed;
int64_t left;
int64_t period;
if (s->count == 0)
return 0;
if ((s->control & TIMER_CTRL_ENABLE) == 0)
return s->count;
elapsed = now - s->loaded;
left = s->expires - now;
period = s->expires - s->loaded;
/* If the timer should have expired then return 0. This can happen
when the host timer signal doesnt occur immediately. It's better to
have a timer appear to sit at zero for a while than have it wrap
around before the guest interrupt is raised. */
/* ??? Could we trigger the interrupt here? */
if (elapsed > period)
if (left < 0)
return 0;
/* We need to calculate count * elapsed / period without overfowing.
Scale both elapsed and period so they fit in a 32-bit int. */
while (period != (int32_t)period) {
period >>= 1;
elapsed >>= 1;
left >>= 1;
}
return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed)
return ((uint64_t)s->count * (uint64_t)(int32_t)left)
/ (int32_t)period;
}

156
hw/cdrom.c Normal file
View File

@@ -0,0 +1,156 @@
/*
* QEMU ATAPI CD-ROM Emulator
*
* Copyright (c) 2006 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.
*/
/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved
here. */
#include <vl.h>
static void lba_to_msf(uint8_t *buf, int lba)
{
lba += 150;
buf[0] = (lba / 75) / 60;
buf[1] = (lba / 75) % 60;
buf[2] = lba % 75;
}
/* same toc as bochs. Return -1 if error or the toc length */
/* XXX: check this */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
{
uint8_t *q;
int len;
if (start_track > 1 && start_track != 0xaa)
return -1;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
if (start_track <= 1) {
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, control */
*q++ = 1; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, 0);
q += 3;
} else {
/* sector 0 */
cpu_to_be32wu((uint32_t *)q, 0);
q += 4;
}
}
/* lead out track */
*q++ = 0; /* reserved */
*q++ = 0x16; /* ADR, control */
*q++ = 0xaa; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_be32wu((uint32_t *)q, nb_sectors);
q += 4;
}
len = q - buf;
cpu_to_be16wu((uint16_t *)buf, len - 2);
return len;
}
/* mostly same info as PearPc */
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
{
uint8_t *q;
int len;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa0; /* lead-in */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* first track */
*q++ = 0x00; /* disk type */
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa1;
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* last track */
*q++ = 0x00;
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa2; /* lead-out */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_be32wu((uint32_t *)q, nb_sectors);
q += 4;
}
*q++ = 1; /* session number */
*q++ = 0x14; /* ADR, control */
*q++ = 0; /* track number */
*q++ = 1; /* point */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
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_be16wu((uint16_t *)buf, len - 2);
return len;
}

View File

@@ -1000,12 +1000,12 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
***************************************/
static void cirrus_get_offsets(VGAState *s1,
uint32_t *pline_offset,
uint32_t *pstart_addr)
uint32_t *pline_offset,
uint32_t *pstart_addr,
uint32_t *pline_compare)
{
CirrusVGAState * s = (CirrusVGAState *)s1;
uint32_t start_addr;
uint32_t line_offset;
uint32_t start_addr, line_offset, line_compare;
line_offset = s->cr[0x13]
| ((s->cr[0x1b] & 0x10) << 4);
@@ -1018,6 +1018,11 @@ static void cirrus_get_offsets(VGAState *s1,
| ((s->cr[0x1b] & 0x0c) << 15)
| ((s->cr[0x1d] & 0x80) << 12);
*pstart_addr = start_addr;
line_compare = s->cr[0x18] |
((s->cr[0x07] & 0x10) << 4) |
((s->cr[0x09] & 0x40) << 3);
*pline_compare = line_compare;
}
static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
@@ -2905,6 +2910,9 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque)
{
CirrusVGAState *s = opaque;
if (s->pci_dev)
pci_device_save(s->pci_dev, f);
qemu_put_be32s(f, &s->latch);
qemu_put_8s(f, &s->sr_index);
qemu_put_buffer(f, s->sr, 256);
@@ -2943,10 +2951,17 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque)
static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
{
CirrusVGAState *s = opaque;
int ret;
if (version_id != 1)
if (version_id > 2)
return -EINVAL;
if (s->pci_dev && version_id >= 2) {
ret = pci_device_load(s->pci_dev, f);
if (ret < 0)
return ret;
}
qemu_get_be32s(f, &s->latch);
qemu_get_8s(f, &s->sr_index);
qemu_get_buffer(f, s->sr, 256);
@@ -3100,7 +3115,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
s->cursor_invalidate = cirrus_cursor_invalidate;
s->cursor_draw_line = cirrus_cursor_draw_line;
register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s);
register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s);
}
/***************************************
@@ -3178,6 +3193,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
vga_common_init((VGAState *)s,
ds, vga_ram_base, vga_ram_offset, vga_ram_size);
cirrus_init_common(s, device_id, 1);
s->pci_dev = (PCIDevice *)d;
/* setup memory space */
/* memory #0 LFB */

183
hw/cs4231.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* QEMU Crystal CS4231 audio chip emulation
*
* Copyright (c) 2006 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 CS4231 */
//#define DEBUG_CS
/*
* In addition to Crystal CS4231 there is a DMA controller on Sparc.
*/
#define CS_MAXADDR 0x3f
#define CS_REGS 16
#define CS_DREGS 32
#define CS_MAXDREG (CS_DREGS - 1)
typedef struct CSState {
uint32_t regs[CS_REGS];
uint8_t dregs[CS_DREGS];
void *intctl;
} CSState;
#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
#define CS_VER 0xa0
#define CS_CDC_VER 0x8a
#ifdef DEBUG_CS
#define DPRINTF(fmt, args...) \
do { printf("CS: " fmt , ##args); } while (0)
#define pic_set_irq_new(intctl, irq, level) \
do { printf("CS: set_irq(%d): %d\n", (irq), (level)); \
pic_set_irq_new((intctl), (irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif
static void cs_reset(void *opaque)
{
CSState *s = opaque;
memset(s->regs, 0, CS_REGS * 4);
memset(s->dregs, 0, CS_DREGS);
s->dregs[12] = CS_CDC_VER;
s->dregs[25] = CS_VER;
}
static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr)
{
CSState *s = opaque;
uint32_t saddr, ret;
saddr = (addr & CS_MAXADDR) >> 2;
switch (saddr) {
case 1:
switch (CS_RAP(s)) {
case 3: // Write only
ret = 0;
break;
default:
ret = s->dregs[CS_RAP(s)];
break;
}
DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret);
break;
default:
ret = s->regs[saddr];
DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret);
break;
}
return ret;
}
static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
CSState *s = opaque;
uint32_t saddr;
saddr = (addr & CS_MAXADDR) >> 2;
DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val);
switch (saddr) {
case 1:
DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), s->dregs[CS_RAP(s)], val);
switch(CS_RAP(s)) {
case 11:
case 25: // Read only
break;
case 12:
val &= 0x40;
val |= CS_CDC_VER; // Codec version
s->dregs[CS_RAP(s)] = val;
break;
default:
s->dregs[CS_RAP(s)] = val;
break;
}
break;
case 2: // Read only
break;
case 4:
if (val & 1)
cs_reset(s);
val &= 0x7f;
s->regs[saddr] = val;
break;
default:
s->regs[saddr] = val;
break;
}
}
static CPUReadMemoryFunc *cs_mem_read[3] = {
cs_mem_readl,
cs_mem_readl,
cs_mem_readl,
};
static CPUWriteMemoryFunc *cs_mem_write[3] = {
cs_mem_writel,
cs_mem_writel,
cs_mem_writel,
};
static void cs_save(QEMUFile *f, void *opaque)
{
CSState *s = opaque;
unsigned int i;
for (i = 0; i < CS_REGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_put_buffer(f, s->dregs, CS_DREGS);
}
static int cs_load(QEMUFile *f, void *opaque, int version_id)
{
CSState *s = opaque;
unsigned int i;
if (version_id > 1)
return -EINVAL;
for (i = 0; i < CS_REGS; i++)
qemu_get_be32s(f, &s->regs[i]);
qemu_get_buffer(f, s->dregs, CS_DREGS);
return 0;
}
void cs_init(target_phys_addr_t base, int irq, void *intctl)
{
int cs_io_memory;
CSState *s;
s = qemu_mallocz(sizeof(CSState));
if (!s)
return;
cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s);
cpu_register_physical_memory(base, CS_MAXADDR, cs_io_memory);
register_savevm("cs4231", base, 1, cs_save, cs_load, s);
qemu_register_reset(cs_reset, s);
cs_reset(s);
}

View File

@@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
}
#if 0
#ifdef DEBUG_CUDA
printf("latch=%d counter=%lld delta_next=%lld\n",
printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
s->latch, d, next_time - d);
#endif
#endif

View File

@@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
as.freq = new_freq;
as.nchannels = 1 << (new_fmt & 1);
as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
if (i == ADC_CHANNEL) {
s->adc_voice =
@@ -432,8 +433,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
"es1370.adc",
s,
es1370_adc_callback,
&as,
0 /* little endian */
&as
);
}
else {
@@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
i ? "es1370.dac2" : "es1370.dac1",
s,
i ? es1370_dac2_callback : es1370_dac1_callback,
&as,
0 /* litle endian */
&as
);
}
}
@@ -479,9 +478,10 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
IO_WRITE_PROTO (es1370_writeb)
{
ES1370State *s = opaque;
addr = es1370_fixup (s, addr);
uint32_t shift, mask;
addr = es1370_fixup (s, addr);
switch (addr) {
case ES1370_REG_CONTROL:
case ES1370_REG_CONTROL + 1:

756
hw/esp.c
View File

@@ -1,5 +1,5 @@
/*
* QEMU ESP emulation
* QEMU ESP/NCR53C9x emulation
*
* Copyright (c) 2005-2006 Fabrice Bellard
*
@@ -26,43 +26,51 @@
/* debug ESP card */
//#define DEBUG_ESP
/*
* On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also
* produced as NCR89C100. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
* and
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
*/
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#define pic_set_irq(irq, level) \
do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
#define TI_BUFSZ 1024*1024 // XXX
#define DMA_VER 0xa0000000
#define DMA_INTR 1
#define DMA_INTREN 0x10
#define DMA_LOADED 0x04000000
typedef struct ESPState ESPState;
#define TI_BUFSZ 32
/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
#define ESP_MAX_DEVS 7
typedef int ESPDMAFunc(ESPState *s,
target_phys_addr_t phys_addr,
int transfer_size1);
typedef struct ESPState ESPState;
struct ESPState {
BlockDriverState **bd;
uint8_t rregs[ESP_MAXREG];
uint8_t wregs[ESP_MAXREG];
int irq;
uint32_t espdmaregs[ESPDMA_REGS];
uint32_t ti_size;
int32_t ti_size;
uint32_t ti_rptr, ti_wptr;
int ti_dir;
uint8_t ti_buf[TI_BUFSZ];
int sense;
int dma;
ESPDMAFunc *dma_cb;
int64_t offset, len;
int target;
SCSIDevice *scsi_dev[MAX_DISKS];
SCSIDevice *current_dev;
uint8_t cmdbuf[TI_BUFSZ];
int cmdlen;
int do_cmd;
/* The amount of data left in the current DMA transfer. */
uint32_t dma_left;
/* The size of the current DMA transfer. Zero if no transfer is in
progress. */
uint32_t dma_counter;
uint8_t *async_buf;
uint32_t async_len;
void *dma_opaque;
};
#define STAT_DO 0x00
@@ -73,6 +81,8 @@ struct ESPState {
#define STAT_MO 0x07
#define STAT_TC 0x10
#define STAT_PE 0x20
#define STAT_GE 0x40
#define STAT_IN 0x80
#define INTR_FC 0x08
@@ -83,410 +93,252 @@ struct ESPState {
#define SEQ_0 0x0
#define SEQ_CD 0x4
/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
static void lba_to_msf(uint8_t *buf, int lba)
static int get_cmd(ESPState *s, uint8_t *buf)
{
lba += 150;
buf[0] = (lba / 75) / 60;
buf[1] = (lba / 75) % 60;
buf[2] = lba % 75;
}
static inline void cpu_to_ube16(uint8_t *buf, int val)
{
buf[0] = val >> 8;
buf[1] = val;
}
static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
/* same toc as bochs. Return -1 if error or the toc length */
/* XXX: check this */
static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
{
uint8_t *q;
int len;
if (start_track > 1 && start_track != 0xaa)
return -1;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
if (start_track <= 1) {
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, control */
*q++ = 1; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, 0);
q += 3;
} else {
/* sector 0 */
cpu_to_ube32(q, 0);
q += 4;
}
}
/* lead out track */
*q++ = 0; /* reserved */
*q++ = 0x16; /* ADR, control */
*q++ = 0xaa; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_ube32(q, nb_sectors);
q += 4;
}
len = q - buf;
cpu_to_ube16(buf, len - 2);
return len;
}
/* mostly same info as PearPc */
static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf,
int session_num)
{
uint8_t *q;
int len;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa0; /* lead-in */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* first track */
*q++ = 0x00; /* disk type */
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa1;
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* last track */
*q++ = 0x00;
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa2; /* lead-out */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_ube32(q, nb_sectors);
q += 4;
}
*q++ = 1; /* session number */
*q++ = 0x14; /* ADR, control */
*q++ = 0; /* track number */
*q++ = 1; /* point */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
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);
return len;
}
static int esp_write_dma_cb(ESPState *s,
target_phys_addr_t phys_addr,
int transfer_size1)
{
DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
s->offset, s->len, s->ti_size, transfer_size1);
bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len);
s->offset = 0;
s->len = 0;
s->target = 0;
return 0;
}
static void handle_satn(ESPState *s)
{
uint8_t buf[32];
uint32_t dmaptr, dmalen;
unsigned int i;
int64_t nb_sectors;
uint32_t dmalen;
int target;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
dmalen = s->rregs[0] | (s->rregs[1] << 8);
target = s->wregs[4] & 7;
DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
cpu_physical_memory_read(dmaptr, buf, dmalen);
espdma_memory_read(s->dma_opaque, buf, dmalen);
} else {
buf[0] = 0;
memcpy(&buf[1], s->ti_buf, dmalen);
dmalen++;
}
for (i = 0; i < dmalen; i++) {
DPRINTF("Command %2.2x\n", buf[i]);
}
s->ti_dir = 0;
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
if (target >= 4 || !s->bd[target]) { // No such drive
if (s->current_dev) {
/* Started a new command before the old one finished. Cancel it. */
scsi_cancel_io(s->current_dev, 0);
s->async_len = 0;
}
if (target >= MAX_DISKS || !s->scsi_dev[target]) {
// No such drive
s->rregs[4] = STAT_IN;
s->rregs[5] = INTR_DC;
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
return;
espdma_raise_irq(s->dma_opaque);
return 0;
}
switch (buf[1]) {
case 0x0:
DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
break;
case 0x12:
DPRINTF("Inquiry (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 36);
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
s->ti_buf[0] = 5;
memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
} else {
s->ti_buf[0] = 0;
memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
}
memcpy(&s->ti_buf[8], "QEMU ", 8);
s->ti_buf[2] = 1;
s->ti_buf[3] = 2;
s->ti_buf[4] = 32;
s->ti_dir = 1;
s->ti_size = 36;
break;
case 0x1a:
DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
break;
case 0x25:
DPRINTF("Read Capacity (len %d)\n", buf[5]);
memset(s->ti_buf, 0, 8);
bdrv_get_geometry(s->bd[target], &nb_sectors);
s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
s->ti_buf[3] = nb_sectors & 0xff;
s->ti_buf[4] = 0;
s->ti_buf[5] = 0;
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
s->ti_buf[6] = 8; // sector size 2048
else
s->ti_buf[6] = 2; // sector size 512
s->ti_buf[7] = 0;
s->ti_dir = 1;
s->ti_size = 8;
break;
case 0x28:
{
int64_t offset, len;
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
len = ((buf[8] << 8) | buf[9]) * 4;
s->ti_size = len * 2048;
} else {
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
s->ti_size = len * 512;
}
DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
if (s->ti_size > TI_BUFSZ) {
DPRINTF("size too large %d\n", s->ti_size);
}
bdrv_read(s->bd[target], offset, s->ti_buf, len);
// XXX error handling
s->ti_dir = 1;
break;
}
case 0x2a:
{
int64_t offset, len;
if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
len = ((buf[8] << 8) | buf[9]) * 4;
s->ti_size = len * 2048;
} else {
offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
len = (buf[8] << 8) | buf[9];
s->ti_size = len * 512;
}
DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
if (s->ti_size > TI_BUFSZ) {
DPRINTF("size too large %d\n", s->ti_size);
}
s->dma_cb = esp_write_dma_cb;
s->offset = offset;
s->len = len;
s->target = target;
// XXX error handling
s->ti_dir = 0;
break;
}
case 0x43:
{
int start_track, format, msf, len;
msf = buf[2] & 2;
format = buf[3] & 0xf;
start_track = buf[7];
bdrv_get_geometry(s->bd[target], &nb_sectors);
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
switch(format) {
case 0:
len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
if (len < 0)
goto error_cmd;
s->ti_size = len;
break;
case 1:
/* multi session : only a single session defined */
memset(buf, 0, 12);
buf[1] = 0x0a;
buf[2] = 0x01;
buf[3] = 0x01;
s->ti_size = 12;
break;
case 2:
len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
if (len < 0)
goto error_cmd;
s->ti_size = len;
break;
default:
error_cmd:
DPRINTF("Read TOC error\n");
// XXX error handling
break;
}
s->ti_dir = 1;
break;
}
default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
break;
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
s->current_dev = s->scsi_dev[target];
return dmalen;
}
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
static void do_cmd(ESPState *s, uint8_t *buf)
{
uint32_t dmaptr, dmalen;
int32_t datalen;
int lun;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Transfer status len %d\n", dmalen);
DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
lun = buf[0] & 7;
datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
s->ti_size = datalen;
if (datalen != 0) {
s->rregs[4] = STAT_IN | STAT_TC;
s->dma_left = 0;
s->dma_counter = 0;
if (datalen > 0) {
s->rregs[4] |= STAT_DI;
scsi_read_data(s->current_dev, 0);
} else {
s->rregs[4] |= STAT_DO;
scsi_write_data(s->current_dev, 0);
}
}
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
espdma_raise_irq(s->dma_opaque);
}
static void handle_satn(ESPState *s)
{
uint8_t buf[32];
int len;
len = get_cmd(s, buf);
if (len)
do_cmd(s, buf);
}
static void handle_satn_stop(ESPState *s)
{
s->cmdlen = get_cmd(s, s->cmdbuf);
if (s->cmdlen) {
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
s->do_cmd = 1;
s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
espdma_raise_irq(s->dma_opaque);
}
}
static void write_response(ESPState *s)
{
DPRINTF("Transfer status (sense=%d)\n", s->sense);
s->ti_buf[0] = s->sense;
s->ti_buf[1] = 0;
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
cpu_physical_memory_write(dmaptr, buf, len);
espdma_memory_write(s->dma_opaque, s->ti_buf, 2);
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
} else {
memcpy(s->ti_buf, buf, len);
s->ti_size = dmalen;
s->ti_size = 2;
s->ti_rptr = 0;
s->ti_wptr = 0;
s->rregs[7] = dmalen;
s->rregs[7] = 2;
}
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
espdma_raise_irq(s->dma_opaque);
}
static const uint8_t okbuf[] = {0, 0};
static void esp_dma_done(ESPState *s)
{
s->rregs[4] |= STAT_IN | STAT_TC;
s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
s->rregs[7] = 0;
s->rregs[0] = 0;
s->rregs[1] = 0;
espdma_raise_irq(s->dma_opaque);
}
static void esp_do_dma(ESPState *s)
{
uint32_t len;
int to_device;
to_device = (s->ti_size < 0);
len = s->dma_left;
if (s->do_cmd) {
DPRINTF("command len %d + %d\n", s->cmdlen, len);
espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
s->ti_size = 0;
s->cmdlen = 0;
s->do_cmd = 0;
do_cmd(s, s->cmdbuf);
return;
}
if (s->async_len == 0) {
/* Defer until data is available. */
return;
}
if (len > s->async_len) {
len = s->async_len;
}
if (to_device) {
espdma_memory_read(s->dma_opaque, s->async_buf, len);
} else {
espdma_memory_write(s->dma_opaque, s->async_buf, len);
}
s->dma_left -= len;
s->async_buf += len;
s->async_len -= len;
if (to_device)
s->ti_size += len;
else
s->ti_size -= len;
if (s->async_len == 0) {
if (to_device) {
// ti_size is negative
scsi_write_data(s->current_dev, 0);
} else {
scsi_read_data(s->current_dev, 0);
/* If there is still data to be read from the device then
complete the DMA operation immeriately. Otherwise defer
until the scsi layer has completed. */
if (s->dma_left == 0 && s->ti_size > 0) {
esp_dma_done(s);
}
}
} else {
/* Partially filled a scsi buffer. Complete immediately. */
esp_dma_done(s);
}
}
static void esp_command_complete(void *opaque, int reason, uint32_t tag,
uint32_t arg)
{
ESPState *s = (ESPState *)opaque;
if (reason == SCSI_REASON_DONE) {
DPRINTF("SCSI Command complete\n");
if (s->ti_size != 0)
DPRINTF("SCSI command completed unexpectedly\n");
s->ti_size = 0;
s->dma_left = 0;
s->async_len = 0;
if (arg)
DPRINTF("Command failed\n");
s->sense = arg;
s->rregs[4] = STAT_ST;
esp_dma_done(s);
s->current_dev = NULL;
} else {
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
s->async_len = arg;
s->async_buf = scsi_get_buf(s->current_dev, 0);
if (s->dma_left) {
esp_do_dma(s);
} else if (s->dma_counter != 0 && s->ti_size <= 0) {
/* If this was the last part of a DMA transfer then the
completion interrupt is deferred to here. */
esp_dma_done(s);
}
}
}
static void handle_ti(ESPState *s)
{
uint32_t dmaptr, dmalen;
unsigned int i;
uint32_t dmalen, minlen;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
DPRINTF("Transfer Information len %d\n", dmalen);
dmalen = s->rregs[0] | (s->rregs[1] << 8);
if (dmalen==0) {
dmalen=0x10000;
}
s->dma_counter = dmalen;
if (s->do_cmd)
minlen = (dmalen < 32) ? dmalen : 32;
else if (s->ti_size < 0)
minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
else
minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
DPRINTF("Transfer Information len %d\n", minlen);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
for (i = 0; i < s->ti_size; i++) {
dmaptr = iommu_translate(s->espdmaregs[1] + i);
if (s->ti_dir)
cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
else
cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
}
if (s->dma_cb) {
s->dma_cb(s, s->espdmaregs[1], dmalen);
s->dma_cb = NULL;
}
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
s->espdmaregs[0] |= DMA_INTR;
} else {
s->ti_size = dmalen;
s->ti_rptr = 0;
s->ti_wptr = 0;
s->rregs[7] = dmalen;
}
pic_set_irq(s->irq, 1);
s->dma_left = minlen;
s->rregs[4] &= ~STAT_TC;
esp_do_dma(s);
} else if (s->do_cmd) {
DPRINTF("command len %d\n", s->cmdlen);
s->ti_size = 0;
s->cmdlen = 0;
s->do_cmd = 0;
do_cmd(s, s->cmdbuf);
return;
}
}
static void esp_reset(void *opaque)
void esp_reset(void *opaque)
{
ESPState *s = opaque;
memset(s->rregs, 0, ESP_MAXREG);
memset(s->wregs, 0, ESP_MAXREG);
s->rregs[0x0e] = 0x4; // Indicate fas100a
memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
s->ti_dir = 0;
s->dma = 0;
s->dma_cb = NULL;
s->do_cmd = 0;
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -501,8 +353,14 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
// FIFO
if (s->ti_size > 0) {
s->ti_size--;
s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
pic_set_irq(s->irq, 1);
if ((s->rregs[4] & 6) == 0) {
/* Data in/out. */
fprintf(stderr, "esp: PIO data read not implemented\n");
s->rregs[2] = 0;
} else {
s->rregs[2] = s->ti_buf[s->ti_rptr++];
}
espdma_raise_irq(s->dma_opaque);
}
if (s->ti_size == 0) {
s->ti_rptr = 0;
@@ -511,10 +369,9 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
break;
case 5:
// interrupt
// Clear status bits except TC
s->rregs[4] &= STAT_TC;
pic_set_irq(s->irq, 0);
s->espdmaregs[0] &= ~DMA_INTR;
// Clear interrupt/error status bits
s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
espdma_clear_irq(s->dma_opaque);
break;
default:
break;
@@ -532,18 +389,30 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
switch (saddr) {
case 0:
case 1:
s->rregs[saddr] = val;
s->rregs[4] &= ~STAT_TC;
break;
case 2:
// FIFO
s->ti_size++;
s->ti_buf[s->ti_wptr++] = val & 0xff;
if (s->do_cmd) {
s->cmdbuf[s->cmdlen++] = val & 0xff;
} else if ((s->rregs[4] & 6) == 0) {
uint8_t buf;
buf = val & 0xff;
s->ti_size--;
fprintf(stderr, "esp: PIO data write not implemented\n");
} else {
s->ti_size++;
s->ti_buf[s->ti_wptr++] = val & 0xff;
}
break;
case 3:
s->rregs[saddr] = val;
// Command
if (val & 0x80) {
s->dma = 1;
/* Reload DMA counter. */
s->rregs[0] = s->wregs[0];
s->rregs[1] = s->wregs[1];
} else {
s->dma = 0;
}
@@ -565,8 +434,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
DPRINTF("Bus reset (%2.2x)\n", val);
s->rregs[5] = INTR_RST;
if (!(s->wregs[8] & 0x40)) {
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
espdma_raise_irq(s->dma_opaque);
}
break;
case 0x10:
@@ -574,11 +442,11 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 0x11:
DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
dma_write(s, okbuf, 2);
write_response(s);
break;
case 0x12:
DPRINTF("Message Accepted (%2.2x)\n", val);
dma_write(s, okbuf, 2);
write_response(s);
s->rregs[5] = INTR_DC;
s->rregs[6] = 0;
break;
@@ -586,11 +454,12 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
DPRINTF("Set ATN (%2.2x)\n", val);
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
handle_satn(s);
handle_satn_stop(s);
break;
default:
DPRINTF("Unhandled ESP command (%2.2x)\n", val);
@@ -628,72 +497,15 @@ static CPUWriteMemoryFunc *esp_mem_write[3] = {
esp_mem_writeb,
};
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
return s->espdmaregs[saddr];
}
static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
ESPState *s = opaque;
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
switch (saddr) {
case 0:
if (!(val & DMA_INTREN))
pic_set_irq(s->irq, 0);
if (val & 0x80) {
esp_reset(s);
} else if (val & 0x40) {
val &= ~0x40;
} else if (val == 0)
val = 0x40;
val &= 0x0fffffff;
val |= DMA_VER;
break;
case 1:
s->espdmaregs[0] = DMA_LOADED;
break;
default:
break;
}
s->espdmaregs[saddr] = val;
}
static CPUReadMemoryFunc *espdma_mem_read[3] = {
espdma_mem_readl,
espdma_mem_readl,
espdma_mem_readl,
};
static CPUWriteMemoryFunc *espdma_mem_write[3] = {
espdma_mem_writel,
espdma_mem_writel,
espdma_mem_writel,
};
static void esp_save(QEMUFile *f, void *opaque)
{
ESPState *s = opaque;
unsigned int i;
qemu_put_buffer(f, s->rregs, ESP_MAXREG);
qemu_put_buffer(f, s->wregs, ESP_MAXREG);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_put_be32s(f, &s->espdmaregs[i]);
qemu_put_be32s(f, &s->ti_size);
qemu_put_be32s(f, &s->ti_rptr);
qemu_put_be32s(f, &s->ti_wptr);
qemu_put_be32s(f, &s->ti_dir);
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_put_be32s(f, &s->dma);
}
@@ -701,47 +513,63 @@ static void esp_save(QEMUFile *f, void *opaque)
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
ESPState *s = opaque;
unsigned int i;
if (version_id != 1)
return -EINVAL;
if (version_id != 2)
return -EINVAL; // Cannot emulate 1
qemu_get_buffer(f, s->rregs, ESP_MAXREG);
qemu_get_buffer(f, s->wregs, ESP_MAXREG);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_get_be32s(f, &s->espdmaregs[i]);
qemu_get_be32s(f, &s->ti_size);
qemu_get_be32s(f, &s->ti_rptr);
qemu_get_be32s(f, &s->ti_wptr);
qemu_get_be32s(f, &s->ti_dir);
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_get_be32s(f, &s->dma);
return 0;
}
void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
{
ESPState *s = (ESPState *)opaque;
if (id < 0) {
for (id = 0; id < ESP_MAX_DEVS; id++) {
if (s->scsi_dev[id] == NULL)
break;
}
}
if (id >= ESP_MAX_DEVS) {
DPRINTF("Bad Device ID %d\n", id);
return;
}
if (s->scsi_dev[id]) {
DPRINTF("Destroying device %d\n", id);
scsi_disk_destroy(s->scsi_dev[id]);
}
DPRINTF("Attaching block device %d\n", id);
/* Command queueing is not implemented. */
s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
}
void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
{
ESPState *s;
int esp_io_memory, espdma_io_memory;
int esp_io_memory;
s = qemu_mallocz(sizeof(ESPState));
if (!s)
return;
return NULL;
s->bd = bd;
s->irq = irq;
s->dma_opaque = dma_opaque;
esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
esp_reset(s);
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
}
return s;
}

View File

@@ -66,7 +66,6 @@ typedef enum fdrive_type_t {
typedef enum fdrive_flags_t {
FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
FDRIVE_REVALIDATE = 0x02, /* Revalidated */
} fdrive_flags_t;
typedef enum fdisk_flags_t {
@@ -236,7 +235,6 @@ static void fd_revalidate (fdrive_t *drv)
int nb_heads, max_track, last_sect, ro;
FLOPPY_DPRINTF("revalidate\n");
drv->drflags &= ~FDRIVE_REVALIDATE;
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
ro = bdrv_is_read_only(drv->bs);
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
@@ -291,7 +289,6 @@ static void fd_revalidate (fdrive_t *drv)
drv->max_track = 0;
drv->flags &= ~FDISK_DBL_SIDES;
}
drv->drflags |= FDRIVE_REVALIDATE;
}
/* Motor control */
@@ -488,19 +485,6 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
fdctrl_write_mem,
};
static void fd_change_cb (void *opaque)
{
fdrive_t *drv = opaque;
FLOPPY_DPRINTF("disk change\n");
fd_revalidate(drv);
#if 0
fd_recalibrate(drv);
fdctrl_reset_fifo(drv->fdctrl);
fdctrl_raise_irq(drv->fdctrl, 0x20);
#endif
}
fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
uint32_t io_base,
BlockDriverState **fds)
@@ -529,10 +513,6 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
}
for (i = 0; i < 2; i++) {
fd_init(&fdctrl->drives[i], fds[i]);
if (fds[i]) {
bdrv_set_change_cb(fds[i],
&fd_change_cb, &fdctrl->drives[i]);
}
}
fdctrl_reset(fdctrl, 0);
fdctrl->state = FD_CTRL_ACTIVE;
@@ -760,18 +740,28 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
// fdctrl.precomp = (value >> 2) & 0x07;
}
static int fdctrl_media_changed(fdrive_t *drv)
{
int ret;
if (!drv->bs)
return 0;
ret = bdrv_media_changed(drv->bs);
if (ret) {
fd_revalidate(drv);
}
return ret;
}
/* Digital input register : 0x07 (read-only) */
static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
{
uint32_t retval = 0;
if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
if (fdctrl_media_changed(drv0(fdctrl)) ||
fdctrl_media_changed(drv1(fdctrl)))
retval |= 0x80;
if (retval != 0)
FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
return retval;
}
@@ -898,7 +888,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
fdctrl->data_len = fdctrl->fifo[8];
} else {
int tmp;
fdctrl->data_len = 128 << fdctrl->fifo[5];
fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
tmp = (cur_drv->last_sect - ks + 1);
if (fdctrl->fifo[0] & 0x80)
tmp += cur_drv->last_sect;
@@ -1683,8 +1673,9 @@ enqueue:
#else
cur_drv->last_sect = fdctrl->fifo[3];
#endif
/* Bochs BIOS is buggy and don't send format informations
* for each sector. So, pretend all's done right now...
/* TODO: implement format using DMA expected by the Bochs BIOS
* and Linux fdformat (read 3 bytes per sector via DMA and fill
* the sector with the specified fill byte
*/
fdctrl->data_state &= ~FD_STATE_FORMAT;
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);

161
hw/grackle_pci.c Normal file
View File

@@ -0,0 +1,161 @@
/*
* QEMU Grackle (heathrow PPC) PCI host
*
* Copyright (c) 2006 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"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
typedef PCIHostState GrackleState;
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
GrackleState *s = opaque;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
s->config_reg = val;
}
static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
{
GrackleState *s = opaque;
uint32_t val;
val = s->config_reg;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
return val;
}
static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
&pci_grackle_config_writel,
&pci_grackle_config_writel,
&pci_grackle_config_writel,
};
static CPUReadMemoryFunc *pci_grackle_config_read[] = {
&pci_grackle_config_readl,
&pci_grackle_config_readl,
&pci_grackle_config_readl,
};
static CPUWriteMemoryFunc *pci_grackle_write[] = {
&pci_host_data_writeb,
&pci_host_data_writew,
&pci_host_data_writel,
};
static CPUReadMemoryFunc *pci_grackle_read[] = {
&pci_host_data_readb,
&pci_host_data_readw,
&pci_host_data_readl,
};
/* Don't know if this matches real hardware, but it agrees with OHW. */
static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
{
return (irq_num + (pci_dev->devfn >> 3)) & 3;
}
static void pci_grackle_set_irq(void *pic, int irq_num, int level)
{
heathrow_pic_set_irq(pic, irq_num + 8, level);
}
PCIBus *pci_grackle_init(uint32_t base, void *pic)
{
GrackleState *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data;
s = qemu_mallocz(sizeof(GrackleState));
s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq,
pic, 0, 0);
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->bus, "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->bus;
}

648
hw/gt64xxx.c Normal file
View File

@@ -0,0 +1,648 @@
/*
* QEMU GT64120 PCI host
*
* Copyright (c) 2006,2007 Aurelien Jarno
*
* 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"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
#define GT_REGS (0x1000 >> 2)
/* CPU Configuration */
#define GT_CPU (0x000 >> 2)
#define GT_MULTI (0x120 >> 2)
/* CPU Address Decode */
#define GT_SCS10LD (0x008 >> 2)
#define GT_SCS10HD (0x010 >> 2)
#define GT_SCS32LD (0x018 >> 2)
#define GT_SCS32HD (0x020 >> 2)
#define GT_CS20LD (0x028 >> 2)
#define GT_CS20HD (0x030 >> 2)
#define GT_CS3BOOTLD (0x038 >> 2)
#define GT_CS3BOOTHD (0x040 >> 2)
#define GT_PCI0IOLD (0x048 >> 2)
#define GT_PCI0IOHD (0x050 >> 2)
#define GT_PCI0M0LD (0x058 >> 2)
#define GT_PCI0M0HD (0x060 >> 2)
#define GT_ISD (0x068 >> 2)
#define GT_PCI0M1LD (0x080 >> 2)
#define GT_PCI0M1HD (0x088 >> 2)
#define GT_PCI1IOLD (0x090 >> 2)
#define GT_PCI1IOHD (0x098 >> 2)
#define GT_PCI1M0LD (0x0a0 >> 2)
#define GT_PCI1M0HD (0x0a8 >> 2)
#define GT_PCI1M1LD (0x0b0 >> 2)
#define GT_PCI1M1HD (0x0b8 >> 2)
#define GT_PCI1M1LD (0x0b0 >> 2)
#define GT_PCI1M1HD (0x0b8 >> 2)
#define GT_SCS10AR (0x0d0 >> 2)
#define GT_SCS32AR (0x0d8 >> 2)
#define GT_CS20R (0x0e0 >> 2)
#define GT_CS3BOOTR (0x0e8 >> 2)
#define GT_PCI0IOREMAP (0x0f0 >> 2)
#define GT_PCI0M0REMAP (0x0f8 >> 2)
#define GT_PCI0M1REMAP (0x100 >> 2)
#define GT_PCI1IOREMAP (0x108 >> 2)
#define GT_PCI1M0REMAP (0x110 >> 2)
#define GT_PCI1M1REMAP (0x118 >> 2)
/* CPU Error Report */
#define GT_CPUERR_ADDRLO (0x070 >> 2)
#define GT_CPUERR_ADDRHI (0x078 >> 2)
#define GT_CPUERR_DATALO (0x128 >> 2) /* GT-64120A only */
#define GT_CPUERR_DATAHI (0x130 >> 2) /* GT-64120A only */
#define GT_CPUERR_PARITY (0x138 >> 2) /* GT-64120A only */
/* CPU Sync Barrier */
#define GT_PCI0SYNC (0x0c0 >> 2)
#define GT_PCI1SYNC (0x0c8 >> 2)
/* SDRAM and Device Address Decode */
#define GT_SCS0LD (0x400 >> 2)
#define GT_SCS0HD (0x404 >> 2)
#define GT_SCS1LD (0x408 >> 2)
#define GT_SCS1HD (0x40c >> 2)
#define GT_SCS2LD (0x410 >> 2)
#define GT_SCS2HD (0x414 >> 2)
#define GT_SCS3LD (0x418 >> 2)
#define GT_SCS3HD (0x41c >> 2)
#define GT_CS0LD (0x420 >> 2)
#define GT_CS0HD (0x424 >> 2)
#define GT_CS1LD (0x428 >> 2)
#define GT_CS1HD (0x42c >> 2)
#define GT_CS2LD (0x430 >> 2)
#define GT_CS2HD (0x434 >> 2)
#define GT_CS3LD (0x438 >> 2)
#define GT_CS3HD (0x43c >> 2)
#define GT_BOOTLD (0x440 >> 2)
#define GT_BOOTHD (0x444 >> 2)
#define GT_ADERR (0x470 >> 2)
/* SDRAM Configuration */
#define GT_SDRAM_CFG (0x448 >> 2)
#define GT_SDRAM_OPMODE (0x474 >> 2)
#define GT_SDRAM_BM (0x478 >> 2)
#define GT_SDRAM_ADDRDECODE (0x47c >> 2)
/* SDRAM Parameters */
#define GT_SDRAM_B0 (0x44c >> 2)
#define GT_SDRAM_B1 (0x450 >> 2)
#define GT_SDRAM_B2 (0x454 >> 2)
#define GT_SDRAM_B3 (0x458 >> 2)
/* Device Parameters */
#define GT_DEV_B0 (0x45c >> 2)
#define GT_DEV_B1 (0x460 >> 2)
#define GT_DEV_B2 (0x464 >> 2)
#define GT_DEV_B3 (0x468 >> 2)
#define GT_DEV_BOOT (0x46c >> 2)
/* ECC */
#define GT_ECC_ERRDATALO (0x480 >> 2) /* GT-64120A only */
#define GT_ECC_ERRDATAHI (0x484 >> 2) /* GT-64120A only */
#define GT_ECC_MEM (0x488 >> 2) /* GT-64120A only */
#define GT_ECC_CALC (0x48c >> 2) /* GT-64120A only */
#define GT_ECC_ERRADDR (0x490 >> 2) /* GT-64120A only */
/* DMA Record */
#define GT_DMA0_CNT (0x800 >> 2)
#define GT_DMA1_CNT (0x804 >> 2)
#define GT_DMA2_CNT (0x808 >> 2)
#define GT_DMA3_CNT (0x80c >> 2)
#define GT_DMA0_SA (0x810 >> 2)
#define GT_DMA1_SA (0x814 >> 2)
#define GT_DMA2_SA (0x818 >> 2)
#define GT_DMA3_SA (0x81c >> 2)
#define GT_DMA0_DA (0x820 >> 2)
#define GT_DMA1_DA (0x824 >> 2)
#define GT_DMA2_DA (0x828 >> 2)
#define GT_DMA3_DA (0x82c >> 2)
#define GT_DMA0_NEXT (0x830 >> 2)
#define GT_DMA1_NEXT (0x834 >> 2)
#define GT_DMA2_NEXT (0x838 >> 2)
#define GT_DMA3_NEXT (0x83c >> 2)
#define GT_DMA0_CUR (0x870 >> 2)
#define GT_DMA1_CUR (0x874 >> 2)
#define GT_DMA2_CUR (0x878 >> 2)
#define GT_DMA3_CUR (0x87c >> 2)
/* DMA Channel Control */
#define GT_DMA0_CTRL (0x840 >> 2)
#define GT_DMA1_CTRL (0x844 >> 2)
#define GT_DMA2_CTRL (0x848 >> 2)
#define GT_DMA3_CTRL (0x84c >> 2)
/* DMA Arbiter */
#define GT_DMA_ARB (0x860 >> 2)
/* Timer/Counter */
#define GT_TC0 (0x850 >> 2)
#define GT_TC1 (0x854 >> 2)
#define GT_TC2 (0x858 >> 2)
#define GT_TC3 (0x85c >> 2)
#define GT_TC_CONTROL (0x864 >> 2)
/* PCI Internal */
#define GT_PCI0_CMD (0xc00 >> 2)
#define GT_PCI0_TOR (0xc04 >> 2)
#define GT_PCI0_BS_SCS10 (0xc08 >> 2)
#define GT_PCI0_BS_SCS32 (0xc0c >> 2)
#define GT_PCI0_BS_CS20 (0xc10 >> 2)
#define GT_PCI0_BS_CS3BT (0xc14 >> 2)
#define GT_PCI1_IACK (0xc30 >> 2)
#define GT_PCI0_IACK (0xc34 >> 2)
#define GT_PCI0_BARE (0xc3c >> 2)
#define GT_PCI0_PREFMBR (0xc40 >> 2)
#define GT_PCI0_SCS10_BAR (0xc48 >> 2)
#define GT_PCI0_SCS32_BAR (0xc4c >> 2)
#define GT_PCI0_CS20_BAR (0xc50 >> 2)
#define GT_PCI0_CS3BT_BAR (0xc54 >> 2)
#define GT_PCI0_SSCS10_BAR (0xc58 >> 2)
#define GT_PCI0_SSCS32_BAR (0xc5c >> 2)
#define GT_PCI0_SCS3BT_BAR (0xc64 >> 2)
#define GT_PCI1_CMD (0xc80 >> 2)
#define GT_PCI1_TOR (0xc84 >> 2)
#define GT_PCI1_BS_SCS10 (0xc88 >> 2)
#define GT_PCI1_BS_SCS32 (0xc8c >> 2)
#define GT_PCI1_BS_CS20 (0xc90 >> 2)
#define GT_PCI1_BS_CS3BT (0xc94 >> 2)
#define GT_PCI1_BARE (0xcbc >> 2)
#define GT_PCI1_PREFMBR (0xcc0 >> 2)
#define GT_PCI1_SCS10_BAR (0xcc8 >> 2)
#define GT_PCI1_SCS32_BAR (0xccc >> 2)
#define GT_PCI1_CS20_BAR (0xcd0 >> 2)
#define GT_PCI1_CS3BT_BAR (0xcd4 >> 2)
#define GT_PCI1_SSCS10_BAR (0xcd8 >> 2)
#define GT_PCI1_SSCS32_BAR (0xcdc >> 2)
#define GT_PCI1_SCS3BT_BAR (0xce4 >> 2)
#define GT_PCI1_CFGADDR (0xcf0 >> 2)
#define GT_PCI1_CFGDATA (0xcf4 >> 2)
#define GT_PCI0_CFGADDR (0xcf8 >> 2)
#define GT_PCI0_CFGDATA (0xcfc >> 2)
/* Interrupts */
#define GT_INTRCAUSE (0xc18 >> 2)
#define GT_INTRMASK (0xc1c >> 2)
#define GT_PCI0_ICMASK (0xc24 >> 2)
#define GT_PCI0_SERR0MASK (0xc28 >> 2)
#define GT_CPU_INTSEL (0xc70 >> 2)
#define GT_PCI0_INTSEL (0xc74 >> 2)
#define GT_HINTRCAUSE (0xc98 >> 2)
#define GT_HINTRMASK (0xc9c >> 2)
#define GT_PCI0_HICMASK (0xca4 >> 2)
#define GT_PCI1_SERR1MASK (0xca8 >> 2)
typedef PCIHostState GT64120PCIState;
typedef struct GT64120State {
GT64120PCIState *pci;
uint32_t regs[GT_REGS];
} GT64120State;
static void gt64120_pci_mapping(GT64120State *s)
{
target_phys_addr_t start, length;
/* Update IO mapping */
if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
{
start = s->regs[GT_PCI0IOLD] << 21;
length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
isa_mmio_init(start, length);
}
}
static void gt64120_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
GT64120State *s = opaque;
uint32_t saddr;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
saddr = (addr & 0xfff) >> 2;
switch (saddr) {
/* CPU Configuration */
case GT_CPU:
s->regs[GT_CPU] = val;
break;
case GT_MULTI:
/* Read-only register as only one GT64xxx is present on the CPU bus */
break;
/* CPU Address Decode */
case GT_PCI0IOLD:
s->regs[GT_PCI0IOLD] = val & 0x00007fff;
s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI0M0LD:
s->regs[GT_PCI0M0LD] = val & 0x00007fff;
s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI0M1LD:
s->regs[GT_PCI0M1LD] = val & 0x00007fff;
s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI1IOLD:
s->regs[GT_PCI1IOLD] = val & 0x00007fff;
s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI1M0LD:
s->regs[GT_PCI1M0LD] = val & 0x00007fff;
s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI1M1LD:
s->regs[GT_PCI1M1LD] = val & 0x00007fff;
s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
case GT_PCI0IOHD:
case GT_PCI0M0HD:
case GT_PCI0M1HD:
case GT_PCI1IOHD:
case GT_PCI1M0HD:
case GT_PCI1M1HD:
s->regs[saddr] = val & 0x0000007f;
gt64120_pci_mapping(s);
break;
case GT_PCI0IOREMAP:
case GT_PCI0M0REMAP:
case GT_PCI0M1REMAP:
case GT_PCI1IOREMAP:
case GT_PCI1M0REMAP:
case GT_PCI1M1REMAP:
s->regs[saddr] = val & 0x000007ff;
gt64120_pci_mapping(s);
break;
/* CPU Error Report */
case GT_CPUERR_ADDRLO:
case GT_CPUERR_ADDRHI:
case GT_CPUERR_DATALO:
case GT_CPUERR_DATAHI:
case GT_CPUERR_PARITY:
/* Read-only registers, do nothing */
break;
/* CPU Sync Barrier */
case GT_PCI0SYNC:
case GT_PCI1SYNC:
/* Read-only registers, do nothing */
break;
/* ECC */
case GT_ECC_ERRDATALO:
case GT_ECC_ERRDATAHI:
case GT_ECC_MEM:
case GT_ECC_CALC:
case GT_ECC_ERRADDR:
/* Read-only registers, do nothing */
break;
/* PCI Internal */
case GT_PCI0_CMD:
case GT_PCI1_CMD:
s->regs[saddr] = val & 0x0401fc0f;
break;
case GT_PCI0_CFGADDR:
s->pci->config_reg = val & 0x80fffffc;
break;
case GT_PCI0_CFGDATA:
pci_host_data_writel(s->pci, 0, val);
break;
/* SDRAM Parameters */
case GT_SDRAM_B0:
case GT_SDRAM_B1:
case GT_SDRAM_B2:
case GT_SDRAM_B3:
/* We don't simulate electrical parameters of the SDRAM.
Accept, but ignore the values. */
s->regs[saddr] = val;
break;
default:
#if 0
printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr);
#endif
break;
}
}
static uint32_t gt64120_readl (void *opaque,
target_phys_addr_t addr)
{
GT64120State *s = opaque;
uint32_t val;
uint32_t saddr;
val = 0;
saddr = (addr & 0xfff) >> 2;
switch (saddr) {
/* CPU Configuration */
case GT_MULTI:
/* Only one GT64xxx is present on the CPU bus, return
the initial value */
val = s->regs[saddr];
break;
/* CPU Error Report */
case GT_CPUERR_ADDRLO:
case GT_CPUERR_ADDRHI:
case GT_CPUERR_DATALO:
case GT_CPUERR_DATAHI:
case GT_CPUERR_PARITY:
/* Emulated memory has no error, always return the initial
values */
val = s->regs[saddr];
break;
/* CPU Sync Barrier */
case GT_PCI0SYNC:
case GT_PCI1SYNC:
/* Reading those register should empty all FIFO on the PCI
bus, which are not emulated. The return value should be
a random value that should be ignored. */
val = 0xc000ffee;
break;
/* ECC */
case GT_ECC_ERRDATALO:
case GT_ECC_ERRDATAHI:
case GT_ECC_MEM:
case GT_ECC_CALC:
case GT_ECC_ERRADDR:
/* Emulated memory has no error, always return the initial
values */
val = s->regs[saddr];
break;
case GT_CPU:
case GT_PCI0IOLD:
case GT_PCI0M0LD:
case GT_PCI0M1LD:
case GT_PCI1IOLD:
case GT_PCI1M0LD:
case GT_PCI1M1LD:
case GT_PCI0IOHD:
case GT_PCI0M0HD:
case GT_PCI0M1HD:
case GT_PCI1IOHD:
case GT_PCI1M0HD:
case GT_PCI1M1HD:
case GT_PCI0_CMD:
case GT_PCI1_CMD:
case GT_PCI0IOREMAP:
case GT_PCI0M0REMAP:
case GT_PCI0M1REMAP:
case GT_PCI1IOREMAP:
case GT_PCI1M0REMAP:
case GT_PCI1M1REMAP:
val = s->regs[saddr];
break;
case GT_PCI0_IACK:
/* Read the IRQ number */
val = pic_read_irq(isa_pic);
break;
/* SDRAM Parameters */
case GT_SDRAM_B0:
case GT_SDRAM_B1:
case GT_SDRAM_B2:
case GT_SDRAM_B3:
/* We don't simulate electrical parameters of the SDRAM.
Just return the last written value. */
val = s->regs[saddr];
break;
/* PCI Internal */
case GT_PCI0_CFGADDR:
val = s->pci->config_reg;
break;
case GT_PCI0_CFGDATA:
val = pci_host_data_readl(s->pci, 0);
break;
default:
val = s->regs[saddr];
#if 0
printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr);
#endif
break;
}
#ifdef TARGET_WORDS_BIGENDIAN
return bswap32(val);
#else
return val;
#endif
}
static CPUWriteMemoryFunc *gt64120_write[] = {
&gt64120_writel,
&gt64120_writel,
&gt64120_writel,
};
static CPUReadMemoryFunc *gt64120_read[] = {
&gt64120_readl,
&gt64120_readl,
&gt64120_readl,
};
static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot;
slot = (pci_dev->devfn >> 3);
switch (slot) {
/* PIIX4 USB */
case 10:
return 3;
/* AMD 79C973 Ethernet */
case 11:
return 0;
/* Crystal 4281 Sound */
case 12:
return 0;
/* PCI slot 1 to 4 */
case 18 ... 21:
return ((slot - 18) + irq_num) & 0x03;
/* Unknown device, don't do any translation */
default:
return irq_num;
}
}
extern PCIDevice *piix4_dev;
static int pci_irq_levels[4];
static void pci_gt64120_set_irq(void *pic, int irq_num, int level)
{
int i, pic_irq, pic_level;
pci_irq_levels[irq_num] = level;
/* now we change the pic irq level according to the piix irq mappings */
/* XXX: optimize */
pic_irq = piix4_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;
for (i = 0; i < 4; i++) {
if (pic_irq == piix4_dev->config[0x60 + i])
pic_level |= pci_irq_levels[i];
}
pic_set_irq(pic_irq, pic_level);
}
}
void gt64120_reset(void *opaque)
{
GT64120State *s = opaque;
/* CPU Configuration */
#ifdef TARGET_WORDS_BIGENDIAN
s->regs[GT_CPU] = 0x00000000;
#else
s->regs[GT_CPU] = 0x00000800;
#endif
s->regs[GT_MULTI] = 0x00000000;
/* CPU Address decode FIXME: not complete*/
s->regs[GT_PCI0IOLD] = 0x00000080;
s->regs[GT_PCI0IOHD] = 0x0000000f;
s->regs[GT_PCI0M0LD] = 0x00000090;
s->regs[GT_PCI0M0HD] = 0x0000001f;
s->regs[GT_PCI0M1LD] = 0x00000790;
s->regs[GT_PCI0M1HD] = 0x0000001f;
s->regs[GT_PCI1IOLD] = 0x00000100;
s->regs[GT_PCI1IOHD] = 0x0000000f;
s->regs[GT_PCI1M0LD] = 0x00000110;
s->regs[GT_PCI1M0HD] = 0x0000001f;
s->regs[GT_PCI1M1LD] = 0x00000120;
s->regs[GT_PCI1M1HD] = 0x0000002f;
s->regs[GT_PCI0IOREMAP] = 0x00000080;
s->regs[GT_PCI0M0REMAP] = 0x00000090;
s->regs[GT_PCI0M1REMAP] = 0x00000790;
s->regs[GT_PCI1IOREMAP] = 0x00000100;
s->regs[GT_PCI1M0REMAP] = 0x00000110;
s->regs[GT_PCI1M1REMAP] = 0x00000120;
/* CPU Error Report */
s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
s->regs[GT_CPUERR_DATALO] = 0xffffffff;
s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
s->regs[GT_CPUERR_PARITY] = 0x000000ff;
/* ECC */
s->regs[GT_ECC_ERRDATALO] = 0x00000000;
s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
s->regs[GT_ECC_MEM] = 0x00000000;
s->regs[GT_ECC_CALC] = 0x00000000;
s->regs[GT_ECC_ERRADDR] = 0x00000000;
/* SDRAM Parameters */
s->regs[GT_SDRAM_B0] = 0x00000005;
s->regs[GT_SDRAM_B1] = 0x00000005;
s->regs[GT_SDRAM_B2] = 0x00000005;
s->regs[GT_SDRAM_B3] = 0x00000005;
/* PCI Internal FIXME: not complete*/
#ifdef TARGET_WORDS_BIGENDIAN
s->regs[GT_PCI0_CMD] = 0x00000000;
s->regs[GT_PCI1_CMD] = 0x00000000;
#else
s->regs[GT_PCI0_CMD] = 0x00010001;
s->regs[GT_PCI1_CMD] = 0x00010001;
#endif
s->regs[GT_PCI0_IACK] = 0x00000000;
s->regs[GT_PCI1_IACK] = 0x00000000;
gt64120_pci_mapping(s);
}
PCIBus *pci_gt64120_init(void *pic)
{
GT64120State *s;
PCIDevice *d;
int gt64120;
s = qemu_mallocz(sizeof(GT64120State));
s->pci = qemu_mallocz(sizeof(GT64120PCIState));
gt64120_reset(s);
s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
pic, 144, 4);
gt64120 = cpu_register_io_memory(0, gt64120_read,
gt64120_write, s);
cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120);
d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
0, NULL, NULL);
d->config[0x00] = 0xab; // vendor_id
d->config[0x01] = 0x11;
d->config[0x02] = 0x46; // device_id
d->config[0x03] = 0x20;
d->config[0x04] = 0x06;
d->config[0x05] = 0x00;
d->config[0x06] = 0x80;
d->config[0x07] = 0xa2;
d->config[0x08] = 0x10;
d->config[0x09] = 0x00;
d->config[0x0A] = 0x80;
d->config[0x0B] = 0x05;
d->config[0x0C] = 0x08;
d->config[0x0D] = 0x40;
d->config[0x0E] = 0x00;
d->config[0x0F] = 0x00;
d->config[0x17] = 0x08;
d->config[0x1B] = 0x1c;
d->config[0x1F] = 0x1f;
d->config[0x23] = 0x14;
d->config[0x27] = 0x14;
d->config[0x3D] = 0x01;
return s->pci->bus;
}

View File

@@ -161,6 +161,13 @@ void pic_update_irq(PicState2 *s)
#endif
s->irq_request(s->irq_request_opaque, 1);
}
/* all targets should do this rather than acking the IRQ in the cpu */
#if defined(TARGET_MIPS)
else {
s->irq_request(s->irq_request_opaque, 0);
}
#endif
}
#ifdef DEBUG_IRQ_LATENCY
@@ -531,7 +538,7 @@ void irq_info(void)
for (i = 0; i < 16; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
term_printf("%2d: %" PRId64 "\n", i, count);
}
#endif
}

876
hw/ide.c

File diff suppressed because it is too large Load Diff

View File

@@ -325,7 +325,7 @@ static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
case 5: /* INT_SOFTCLR */
case 11: /* FRQ_ENABLECLR */
default:
printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
return 0;
}
}
@@ -362,7 +362,7 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset,
case 8: /* FRQ_STATUS */
case 9: /* FRQ_RAWSTAT */
default:
printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
return;
}
icp_pic_update(s);
@@ -509,7 +509,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
}
pl110_init(ds, 0xc0000000, pic, 22, 0);
arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
initrd_filename, 0x113);
}

View File

@@ -186,21 +186,54 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
iommu_mem_writew,
};
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr)
{
IOMMUState *s = opaque;
uint32_t iopte, pa, tmppte;
uint32_t iopte;
iopte = s->regs[1] << 4;
addr &= ~s->iostart;
iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
pa = ldl_phys(iopte);
return ldl_phys(iopte);
}
static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa)
{
uint32_t tmppte;
tmppte = pa;
pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte);
return pa;
}
void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int is_write)
{
int l, flags;
target_ulong page, phys_addr;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
flags = iommu_page_get_flags(opaque, page);
if (!(flags & IOPTE_VALID))
return;
phys_addr = iommu_translate_pa(opaque, addr, flags);
if (is_write) {
if (!(flags & IOPTE_WRITE))
return;
cpu_physical_memory_write(phys_addr, buf, len);
} else {
cpu_physical_memory_read(phys_addr, buf, len);
}
len -= l;
buf += l;
addr += l;
}
}
static void iommu_save(QEMUFile *f, void *opaque)
{
IOMMUState *s = opaque;

102
hw/isa_mmio.c Normal file
View File

@@ -0,0 +1,102 @@
/*
* Memory mapped access to ISA IO space.
*
* Copyright (c) 2006 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"
static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outb(NULL, addr & 0xffff, val);
}
static void isa_mmio_writew (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap16(val);
#endif
cpu_outw(NULL, addr & 0xffff, val);
}
static void isa_mmio_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
cpu_outl(NULL, addr & 0xffff, val);
}
static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inb(NULL, addr & 0xffff);
return val;
}
static uint32_t isa_mmio_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap16(val);
#endif
return val;
}
static uint32_t isa_mmio_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
return val;
}
static CPUWriteMemoryFunc *isa_mmio_write[] = {
&isa_mmio_writeb,
&isa_mmio_writew,
&isa_mmio_writel,
};
static CPUReadMemoryFunc *isa_mmio_read[] = {
&isa_mmio_readb,
&isa_mmio_readw,
&isa_mmio_readl,
};
static int isa_mmio_iomemtype = 0;
void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
{
if (!isa_mmio_iomemtype) {
isa_mmio_iomemtype = cpu_register_io_memory(0, isa_mmio_read,
isa_mmio_write, NULL);
}
cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
}

View File

@@ -1,462 +0,0 @@
/*
* QEMU Lance emulation
*
* Copyright (c) 2003-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 LANCE card */
//#define DEBUG_LANCE
#ifdef DEBUG_LANCE
#define DPRINTF(fmt, args...) \
do { printf("LANCE: " fmt , ##args); } while (0)
#else
#define DPRINTF(fmt, args...)
#endif
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
#define LANCE_LOG_RX_BUFFERS 4
#endif
#define LE_CSR0 0
#define LE_CSR1 1
#define LE_CSR2 2
#define LE_CSR3 3
#define LE_NREGS (LE_CSR3 + 1)
#define LE_MAXREG LE_CSR3
#define LE_RDP 0
#define LE_RAP 1
#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
#define LE_C0_MERR 0x0800 /* ME: Memory error */
#define LE_C0_RINT 0x0400 /* Received interrupt */
#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
#define LE_C0_INTR 0x0080 /* Interrupt or error */
#define LE_C0_INEA 0x0040 /* Interrupt enable */
#define LE_C0_RXON 0x0020 /* Receiver on */
#define LE_C0_TXON 0x0010 /* Transmitter on */
#define LE_C0_TDMD 0x0008 /* Transmitter demand */
#define LE_C0_STOP 0x0004 /* Stop the card */
#define LE_C0_STRT 0x0002 /* Start the card */
#define LE_C0_INIT 0x0001 /* Init the card */
#define LE_C3_BSWP 0x4 /* SWAP */
#define LE_C3_ACON 0x2 /* ALE Control */
#define LE_C3_BCON 0x1 /* Byte control */
/* Receive message descriptor 1 */
#define LE_R1_OWN 0x80 /* Who owns the entry */
#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
#define LE_R1_FRA 0x20 /* FRA: Frame error */
#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
#define LE_R1_CRC 0x08 /* CRC error */
#define LE_R1_BUF 0x04 /* BUF: Buffer error */
#define LE_R1_SOP 0x02 /* Start of packet */
#define LE_R1_EOP 0x01 /* End of packet */
#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T1_OWN 0x80 /* Lance owns the packet */
#define LE_T1_ERR 0x40 /* Error summary */
#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
#define LE_T1_EONE 0x08 /* Error: one retry needed */
#define LE_T1_EDEF 0x04 /* Error: deferred */
#define LE_T1_SOP 0x02 /* Start of packet */
#define LE_T1_EOP 0x01 /* End of packet */
#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
#define LE_T3_BUF 0x8000 /* Buffer error */
#define LE_T3_UFL 0x4000 /* Error underflow */
#define LE_T3_LCOL 0x1000 /* Error late collision */
#define LE_T3_CLOS 0x0800 /* Error carrier loss */
#define LE_T3_RTY 0x0400 /* Error retry */
#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
#define PKT_BUF_SZ 1544
#define RX_BUFF_SIZE PKT_BUF_SZ
#define TX_BUFF_SIZE PKT_BUF_SZ
struct lance_rx_desc {
unsigned short rmd0; /* low address of packet */
unsigned char rmd1_bits; /* descriptor bits */
unsigned char rmd1_hadr; /* high address of packet */
short length; /* This length is 2s complement (negative)!
* Buffer length
*/
unsigned short mblength; /* This is the actual number of bytes received */
};
struct lance_tx_desc {
unsigned short tmd0; /* low address of packet */
unsigned char tmd1_bits; /* descriptor bits */
unsigned char tmd1_hadr; /* high address of packet */
short length; /* Length is 2s complement (negative)! */
unsigned short misc;
};
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
unsigned short mode; /* Pre-set mode (reg. 15) */
unsigned char phys_addr[6]; /* Physical ethernet address */
unsigned filter[2]; /* Multicast filter. */
/* Receive and transmit ring base, along with extra bits. */
unsigned short rx_ptr; /* receive descriptor addr */
unsigned short rx_len; /* receive len and high addr */
unsigned short tx_ptr; /* transmit descriptor addr */
unsigned short tx_len; /* transmit len and high addr */
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
char pad[2]; /* align rx_buf for copy_and_sum(). */
char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
};
#define LEDMA_REGS 4
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
typedef struct LANCEState {
VLANClientState *vc;
uint8_t macaddr[6]; /* init mac address */
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_NREGS];
uint8_t phys[6]; /* mac address */
int irq;
unsigned int rxptr, txptr;
uint32_t ledmaregs[LEDMA_REGS];
} LANCEState;
static void lance_send(void *opaque);
static void lance_reset(void *opaque)
{
LANCEState *s = opaque;
memcpy(s->phys, s->macaddr, 6);
s->rxptr = 0;
s->txptr = 0;
memset(s->regs, 0, LE_NREGS * 2);
s->regs[LE_CSR0] = LE_C0_STOP;
memset(s->ledmaregs, 0, LEDMA_REGS * 4);
}
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
return s->regs[s->addr];
case LE_RAP:
DPRINTF("read areg = %4.4x\n", s->addr);
return s->addr;
default:
DPRINTF("read unknown(%d)\n", saddr>>1);
break;
}
return 0;
}
static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
uint16_t reg;
saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
switch(s->addr) {
case LE_CSR0:
if (val & LE_C0_STOP) {
s->regs[LE_CSR0] = LE_C0_STOP;
break;
}
reg = s->regs[LE_CSR0];
// 1 = clear for some bits
reg &= ~(val & 0x7f00);
// generated bits
reg &= ~(LE_C0_ERR | LE_C0_INTR);
if (reg & 0x7100)
reg |= LE_C0_ERR;
if (reg & 0x7f00)
reg |= LE_C0_INTR;
// direct bit
reg &= ~LE_C0_INEA;
reg |= val & LE_C0_INEA;
// exclusive bits
if (val & LE_C0_INIT) {
reg |= LE_C0_IDON | LE_C0_INIT;
reg &= ~LE_C0_STOP;
}
else if (val & LE_C0_STRT) {
reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
reg &= ~LE_C0_STOP;
}
s->regs[LE_CSR0] = reg;
break;
case LE_CSR1:
s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
s->regs[s->addr] = val;
break;
case LE_CSR2:
s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
s->regs[s->addr] = val;
break;
case LE_CSR3:
s->regs[s->addr] = val;
break;
}
break;
case LE_RAP:
DPRINTF("write areg = %4.4x\n", val);
if (val < LE_NREGS)
s->addr = val;
break;
default:
DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val);
break;
}
lance_send(s);
}
static CPUReadMemoryFunc *lance_mem_read[3] = {
lance_mem_readw,
lance_mem_readw,
lance_mem_readw,
};
static CPUWriteMemoryFunc *lance_mem_write[3] = {
lance_mem_writew,
lance_mem_writew,
lance_mem_writew,
};
#define MIN_BUF_SIZE 60
static int lance_can_receive(void *opaque)
{
return 1;
}
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_rxptr;
uint16_t temp16;
uint8_t temp8;
DPRINTF("receive size %d\n", size);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
old_rxptr = s->rxptr;
for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_R1_OWN)) {
s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
temp16 = size + 4;
bswap16s(&temp16);
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2);
cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
temp8 = LE_R1_POK;
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
if (s->regs[LE_CSR0] & LE_C0_INEA)
pic_set_irq(s->irq, 1);
DPRINTF("got packet, len %d\n", size);
return;
}
}
}
static void lance_send(void *opaque)
{
LANCEState *s = opaque;
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_txptr;
uint16_t temp16;
uint8_t temp8;
char pkt_buf[PKT_BUF_SZ];
DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
return;
ib = (void *) iommu_translate(dmaptr);
DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
old_txptr = s->txptr;
for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2);
bswap16s(&temp16);
temp16 = (~temp16) + 1;
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
DPRINTF("sending packet, len %d\n", temp16);
qemu_send_packet(s->vc, pkt_buf, temp16);
temp8 = LE_T1_POK;
cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
}
}
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
}
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
return s->ledmaregs[saddr];
}
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LANCEState *s = opaque;
uint32_t saddr;
saddr = (addr & LEDMA_MAXADDR) >> 2;
s->ledmaregs[saddr] = val;
}
static CPUReadMemoryFunc *ledma_mem_read[3] = {
ledma_mem_readl,
ledma_mem_readl,
ledma_mem_readl,
};
static CPUWriteMemoryFunc *ledma_mem_write[3] = {
ledma_mem_writel,
ledma_mem_writel,
ledma_mem_writel,
};
static void lance_save(QEMUFile *f, void *opaque)
{
LANCEState *s = opaque;
int i;
qemu_put_be32s(f, &s->leptr);
qemu_put_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_put_be16s(f, &s->regs[i]);
qemu_put_buffer(f, s->phys, 6);
qemu_put_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_put_be32s(f, &s->ledmaregs[i]);
}
static int lance_load(QEMUFile *f, void *opaque, int version_id)
{
LANCEState *s = opaque;
int i;
if (version_id != 1)
return -EINVAL;
qemu_get_be32s(f, &s->leptr);
qemu_get_be16s(f, &s->addr);
for (i = 0; i < LE_NREGS; i ++)
qemu_get_be16s(f, &s->regs[i]);
qemu_get_buffer(f, s->phys, 6);
qemu_get_be32s(f, &s->irq);
for (i = 0; i < LEDMA_REGS; i ++)
qemu_get_be32s(f, &s->ledmaregs[i]);
return 0;
}
void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
int lance_io_memory, ledma_io_memory;
s = qemu_mallocz(sizeof(LANCEState));
if (!s)
return;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
memcpy(s->macaddr, nd->macaddr, 6);
lance_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
s->macaddr[0],
s->macaddr[1],
s->macaddr[2],
s->macaddr[3],
s->macaddr[4],
s->macaddr[5]);
register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
qemu_register_reset(lance_reset, s);
}

1864
hw/lsi53c895a.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
tm.tm_year = fromBCD(val);
if (NVRAM->type == 8)
tm.tm_year = fromBCD(val) + 68; // Base year is 1968
else
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
@@ -421,7 +424,10 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
retval = toBCD(tm.tm_year);
if (NVRAM->type == 8)
retval = toBCD(tm.tm_year - 68); // Base year is 1968
else
retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */

View File

@@ -380,6 +380,29 @@ void rtc_set_date(RTCState *s, const struct tm *tm)
rtc_copy_date(s);
}
/* PC cmos mappings */
#define REG_IBM_CENTURY_BYTE 0x32
#define REG_IBM_PS2_CENTURY_BYTE 0x37
void rtc_set_date_from_host(RTCState *s)
{
time_t ti;
struct tm *tm;
int val;
/* set the CMOS date */
time(&ti);
if (rtc_utc)
tm = gmtime(&ti);
else
tm = localtime(&ti);
rtc_set_date(s, tm);
val = to_bcd(s, (tm->tm_year / 100) + 19);
rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
}
static void rtc_save(QEMUFile *f, void *opaque)
{
RTCState *s = opaque;
@@ -444,6 +467,8 @@ RTCState *rtc_init(int base, int irq)
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
rtc_set_date_from_host(s);
s->periodic_timer = qemu_new_timer(vm_clock,
rtc_periodic_timer, s);
s->second_timer = qemu_new_timer(vm_clock,

39
hw/mips_int.c Normal file
View File

@@ -0,0 +1,39 @@
#include "vl.h"
#include "cpu.h"
/* Raise IRQ to CPU if necessary. It must be called every time the active
IRQ may change */
void cpu_mips_update_irq(CPUState *env)
{
if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM)) {
if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) {
cpu_interrupt(env, CPU_INTERRUPT_HARD);
}
} else {
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
}
void cpu_mips_irq_request(void *opaque, int irq, int level)
{
CPUState *env = first_cpu;
uint32_t mask;
if (irq >= 16)
return;
mask = 1 << (irq + CP0Ca_IP);
if (level) {
env->CP0_Cause |= mask;
} else {
env->CP0_Cause &= ~mask;
}
cpu_mips_update_irq(env);
}

590
hw/mips_malta.c Normal file
View File

@@ -0,0 +1,590 @@
/*
* QEMU Malta board support
*
* Copyright (c) 2006 Aurelien Jarno
*
* 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"
#ifdef TARGET_WORDS_BIGENDIAN
#define BIOS_FILENAME "mips_bios.bin"
#else
#define BIOS_FILENAME "mipsel_bios.bin"
#endif
#ifdef MIPS_HAS_MIPS64
#define INITRD_LOAD_ADDR (int64_t)0x80800000
#else
#define INITRD_LOAD_ADDR (int32_t)0x80800000
#endif
#define ENVP_ADDR (int32_t)0x80002000
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
#define ENVP_NB_ENTRIES 16
#define ENVP_ENTRY_SIZE 256
extern FILE *logfile;
typedef struct {
uint32_t leds;
uint32_t brk;
uint32_t gpout;
uint32_t i2coe;
uint32_t i2cout;
uint32_t i2csel;
CharDriverState *display;
char display_text[9];
} MaltaFPGAState;
static PITState *pit;
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
static void pic_irq_request(void *opaque, int level)
{
cpu_mips_irq_request(opaque, 2, level);
}
/* Malta FPGA */
static void malta_fpga_update_display(void *opaque)
{
char leds_text[9];
int i;
MaltaFPGAState *s = opaque;
for (i = 7 ; i >= 0 ; i--) {
if (s->leds & (1 << i))
leds_text[i] = '#';
else
leds_text[i] = ' ';
}
leds_text[8] = '\0';
qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
}
static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
{
MaltaFPGAState *s = opaque;
uint32_t val = 0;
uint32_t saddr;
saddr = (addr & 0xfffff);
switch (saddr) {
/* SWITCH Register */
case 0x00200:
val = 0x00000000; /* All switches closed */
break;
/* STATUS Register */
case 0x00208:
#ifdef TARGET_WORDS_BIGENDIAN
val = 0x00000012;
#else
val = 0x00000010;
#endif
break;
/* JMPRS Register */
case 0x00210:
val = 0x00;
break;
/* LEDBAR Register */
case 0x00408:
val = s->leds;
break;
/* BRKRES Register */
case 0x00508:
val = s->brk;
break;
/* GPOUT Register */
case 0x00a00:
val = s->gpout;
break;
/* XXX: implement a real I2C controller */
/* GPINP Register */
case 0x00a08:
/* IN = OUT until a real I2C control is implemented */
if (s->i2csel)
val = s->i2cout;
else
val = 0x00;
break;
/* I2CINP Register */
case 0x00b00:
val = 0x00000003;
break;
/* I2COE Register */
case 0x00b08:
val = s->i2coe;
break;
/* I2COUT Register */
case 0x00b10:
val = s->i2cout;
break;
/* I2CSEL Register */
case 0x00b18:
val = s->i2cout;
break;
default:
#if 0
printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n",
addr);
#endif
break;
}
return val;
}
static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
MaltaFPGAState *s = opaque;
uint32_t saddr;
saddr = (addr & 0xfffff);
switch (saddr) {
/* SWITCH Register */
case 0x00200:
break;
/* JMPRS Register */
case 0x00210:
break;
/* LEDBAR Register */
/* XXX: implement a 8-LED array */
case 0x00408:
s->leds = val & 0xff;
break;
/* ASCIIWORD Register */
case 0x00410:
snprintf(s->display_text, 9, "%08X", val);
malta_fpga_update_display(s);
break;
/* ASCIIPOS0 to ASCIIPOS7 Registers */
case 0x00418:
case 0x00420:
case 0x00428:
case 0x00430:
case 0x00438:
case 0x00440:
case 0x00448:
case 0x00450:
s->display_text[(saddr - 0x00418) >> 3] = (char) val;
malta_fpga_update_display(s);
break;
/* SOFTRES Register */
case 0x00500:
if (val == 0x42)
qemu_system_reset_request ();
break;
/* BRKRES Register */
case 0x00508:
s->brk = val & 0xff;
break;
/* GPOUT Register */
case 0x00a00:
s->gpout = val & 0xff;
break;
/* I2COE Register */
case 0x00b08:
s->i2coe = val & 0x03;
break;
/* I2COUT Register */
case 0x00b10:
s->i2cout = val & 0x03;
break;
/* I2CSEL Register */
case 0x00b18:
s->i2cout = val & 0x01;
break;
default:
#if 0
printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n",
addr);
#endif
break;
}
}
static CPUReadMemoryFunc *malta_fpga_read[] = {
malta_fpga_readl,
malta_fpga_readl,
malta_fpga_readl
};
static CPUWriteMemoryFunc *malta_fpga_write[] = {
malta_fpga_writel,
malta_fpga_writel,
malta_fpga_writel
};
void malta_fpga_reset(void *opaque)
{
MaltaFPGAState *s = opaque;
s->leds = 0x00;
s->brk = 0x0a;
s->gpout = 0x00;
s->i2coe = 0x0;
s->i2cout = 0x3;
s->i2csel = 0x1;
s->display_text[8] = '\0';
snprintf(s->display_text, 9, " ");
malta_fpga_update_display(s);
}
MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
{
MaltaFPGAState *s;
int malta;
s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
malta = cpu_register_io_memory(0, malta_fpga_read,
malta_fpga_write, s);
cpu_register_physical_memory(base, 0x100000, malta);
s->display = qemu_chr_open("vc");
qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
qemu_chr_printf(s->display, "+--------+\r\n");
qemu_chr_printf(s->display, "+ +\r\n");
qemu_chr_printf(s->display, "+--------+\r\n");
qemu_chr_printf(s->display, "\n");
qemu_chr_printf(s->display, "Malta ASCII\r\n");
qemu_chr_printf(s->display, "+--------+\r\n");
qemu_chr_printf(s->display, "+ +\r\n");
qemu_chr_printf(s->display, "+--------+\r\n");
malta_fpga_reset(s);
qemu_register_reset(malta_fpga_reset, s);
return s;
}
/* Audio support */
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
struct soundhw *c;
int audio_enabled = 0;
for (c = soundhw; !audio_enabled && c->name; ++c) {
audio_enabled = c->enabled;
}
if (audio_enabled) {
AudioState *s;
s = AUD_init ();
if (s) {
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
exit(1);
}
else {
if (pci_bus) {
c->init.init_pci (pci_bus, s);
}
}
}
}
}
}
}
#endif
/* Network support */
static void network_init (PCIBus *pci_bus)
{
int i;
NICInfo *nd;
for(i = 0; i < nb_nics; i++) {
nd = &nd_table[i];
if (!nd->model) {
nd->model = "pcnet";
}
if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
/* The malta board has a PCNet card using PCI SLOT 11 */
pci_nic_init(pci_bus, nd, 88);
} else {
pci_nic_init(pci_bus, nd, -1);
}
}
}
/* ROM and pseudo bootloader
The following code implements a very very simple bootloader. It first
loads the registers a0 to a3 to the values expected by the OS, and
then jump at the kernel address.
The bootloader should pass the locations of the kernel arguments and
environment variables tables. Those tables contain the 32-bit address
of NULL terminated strings. The environment variables table should be
terminated by a NULL address.
For a simpler implementation, the number of kernel arguments is fixed
to two (the name of the kernel and the command line), and the two
tables are actually the same one.
The registers a0 to a3 should contain the following values:
a0 - number of kernel arguments
a1 - 32-bit address of the kernel arguments table
a2 - 32-bit address of the environment variables table
a3 - RAM size in bytes
*/
static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
{
uint32_t *p;
/* Small bootloader */
p = (uint32_t *) (phys_ram_base + bios_offset);
stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */
stl_raw(p++, 0x00000000); /* nop */
/* Second part of the bootloader */
p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
stl_raw(p++, 0x3c040000); /* lui a0, 0 */
stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */
stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */;
stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */
stl_raw(p++, 0x03e00008); /* jr ra */
stl_raw(p++, 0x00000000); /* nop */
}
static void prom_set(int index, const char *string, ...)
{
va_list ap;
int32_t *p;
int32_t table_addr;
char *s;
if (index >= ENVP_NB_ENTRIES)
return;
p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
p += index;
if (string == NULL) {
stl_raw(p, 0);
return;
}
table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
stl_raw(p, table_addr);
va_start(ap, string);
vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
va_end(ap);
}
/* Kernel */
static int64_t load_kernel (CPUState *env)
{
int64_t kernel_addr = 0;
int index = 0;
long initrd_size;
if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
env->kernel_filename);
exit(1);
}
/* load initrd */
initrd_size = 0;
if (env->initrd_filename) {
initrd_size = load_image(env->initrd_filename,
phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
env->initrd_filename);
exit(1);
}
}
/* Store command line. */
prom_set(index++, env->kernel_filename);
if (initrd_size > 0)
prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
else
prom_set(index++, env->kernel_cmdline);
/* Setup minimum environment variables */
prom_set(index++, "memsize");
prom_set(index++, "%i", env->ram_size);
prom_set(index++, "modetty0");
prom_set(index++, "38400n8r");
prom_set(index++, NULL);
return kernel_addr;
}
static void main_cpu_reset(void *opaque)
{
CPUState *env = opaque;
cpu_reset(env);
/* The bootload does not need to be rewritten as it is located in a
read only location. The kernel location and the arguments table
location does not change. */
if (env->kernel_filename)
load_kernel (env);
}
void mips_malta_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];
unsigned long bios_offset;
int64_t kernel_addr;
PCIBus *pci_bus;
CPUState *env;
RTCState *rtc_state;
/* fdctrl_t *floppy_controller; */
MaltaFPGAState *malta_fpga;
int ret;
env = cpu_init();
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* Map the bios at two physical locations, as on the real board */
bios_offset = ram_size + vga_ram_size;
cpu_register_physical_memory(0x1e000000LL,
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_register_physical_memory(0x1fc00000LL,
BIOS_SIZE, bios_offset | IO_MEM_ROM);
/* Load a BIOS image except if a kernel image has been specified. In
the later case, just write a small bootloader to the flash
location. */
if (kernel_filename) {
env->ram_size = ram_size;
env->kernel_filename = kernel_filename;
env->kernel_cmdline = kernel_cmdline;
env->initrd_filename = initrd_filename;
kernel_addr = load_kernel(env);
write_bootloader(env, bios_offset, kernel_addr);
} else {
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: Warning, could not load MIPS bios '%s'\n",
buf);
exit(1);
}
}
/* Board ID = 0x420 (Malta Board with CoreLV)
XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
map to the board ID. */
stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
/* Init internal devices */
cpu_mips_clock_init(env);
cpu_mips_irqctrl_init();
/* FPGA */
malta_fpga = malta_fpga_init(0x1f000000LL);
/* Interrupt controller */
isa_pic = pic_init(pic_irq_request, env);
/* Northbridge */
pci_bus = pci_gt64120_init(isa_pic);
/* Southbridge */
piix4_init(pci_bus, 80);
pci_piix3_ide_init(pci_bus, bs_table, 81);
usb_uhci_init(pci_bus, 82);
piix4_pm_init(pci_bus, 83);
pit = pit_init(0x40, 0);
DMA_init(0);
/* Super I/O */
kbd_init();
rtc_state = rtc_init(0x70, 8);
serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
parallel_init(0x378, 7, parallel_hds[0]);
/* XXX: The floppy controller does not work correctly, something is
probably wrong.
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
/* Sound card */
#ifdef HAS_AUDIO
audio_init(pci_bus);
#endif
/* Network card */
network_init(pci_bus);
}
QEMUMachine mips_malta_machine = {
"malta",
"MIPS Malta Core LV",
mips_malta_init,
};

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