From 0298141998ea3e19fd86b5a7122aab2fd1ebad51 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 9 Mar 2011 18:21:09 +0100 Subject: [PATCH 001/386] extract I/O handler lists to iohandler.c Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> --- Makefile.objs | 2 +- iohandler.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-common.h | 3 ++ vl.c | 106 ++--------------------------------------- 4 files changed, 138 insertions(+), 102 deletions(-) create mode 100644 iohandler.c diff --git a/Makefile.objs b/Makefile.objs index f8cf199e14..42301fdf0c 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -98,7 +98,7 @@ common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o common-obj-y += qemu-char.o savevm.o #aio.o common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o -common-obj-y += block-migration.o +common-obj-y += block-migration.o iohandler.o common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o diff --git a/iohandler.c b/iohandler.c new file mode 100644 index 0000000000..2e30fe3bcb --- /dev/null +++ b/iohandler.c @@ -0,0 +1,129 @@ +/* + * QEMU System Emulator - managing I/O handler + * + * Copyright (c) 2003-2008 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 "config-host.h" +#include "qemu-common.h" +#include "qemu-char.h" +#include "qemu-queue.h" + +typedef struct IOHandlerRecord { + int fd; + IOCanReadHandler *fd_read_poll; + IOHandler *fd_read; + IOHandler *fd_write; + int deleted; + void *opaque; + QLIST_ENTRY(IOHandlerRecord) next; +} IOHandlerRecord; + +static QLIST_HEAD(, IOHandlerRecord) io_handlers = + QLIST_HEAD_INITIALIZER(io_handlers); + + +/* XXX: fd_read_poll should be suppressed, but an API change is + necessary in the character devices to suppress fd_can_read(). */ +int qemu_set_fd_handler2(int fd, + IOCanReadHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) +{ + IOHandlerRecord *ioh; + + if (!fd_read && !fd_write) { + QLIST_FOREACH(ioh, &io_handlers, next) { + if (ioh->fd == fd) { + ioh->deleted = 1; + break; + } + } + } else { + QLIST_FOREACH(ioh, &io_handlers, next) { + if (ioh->fd == fd) + goto found; + } + ioh = qemu_mallocz(sizeof(IOHandlerRecord)); + QLIST_INSERT_HEAD(&io_handlers, ioh, next); + found: + ioh->fd = fd; + ioh->fd_read_poll = fd_read_poll; + ioh->fd_read = fd_read; + ioh->fd_write = fd_write; + ioh->opaque = opaque; + ioh->deleted = 0; + } + return 0; +} + +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) +{ + return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); +} + +void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + IOHandlerRecord *ioh; + + QLIST_FOREACH(ioh, &io_handlers, next) { + if (ioh->deleted) + continue; + if (ioh->fd_read && + (!ioh->fd_read_poll || + ioh->fd_read_poll(ioh->opaque) != 0)) { + FD_SET(ioh->fd, readfds); + if (ioh->fd > *pnfds) + *pnfds = ioh->fd; + } + if (ioh->fd_write) { + FD_SET(ioh->fd, writefds); + if (ioh->fd > *pnfds) + *pnfds = ioh->fd; + } + } +} + +void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret) +{ + if (ret > 0) { + IOHandlerRecord *pioh, *ioh; + + QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { + if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) { + ioh->fd_read(ioh->opaque); + } + if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) { + ioh->fd_write(ioh->opaque); + } + + /* Do this last in case read/write handlers marked it for deletion */ + if (ioh->deleted) { + QLIST_REMOVE(ioh, next); + qemu_free(ioh); + } + } + } +} diff --git a/qemu-common.h b/qemu-common.h index 7a96dd14e8..665c89380b 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -227,6 +227,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); typedef int IOCanReadHandler(void *opaque); typedef void IOHandler(void *opaque); +void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); +void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc); + struct ParallelIOArg { void *buffer; int count; diff --git a/vl.c b/vl.c index 192a240b52..d3d81e08fb 100644 --- a/vl.c +++ b/vl.c @@ -1022,68 +1022,6 @@ void pcmcia_info(Monitor *mon) "Empty"); } -/***********************************************************/ -/* I/O handling */ - -typedef struct IOHandlerRecord { - int fd; - IOCanReadHandler *fd_read_poll; - IOHandler *fd_read; - IOHandler *fd_write; - int deleted; - void *opaque; - /* temporary data */ - struct pollfd *ufd; - QLIST_ENTRY(IOHandlerRecord) next; -} IOHandlerRecord; - -static QLIST_HEAD(, IOHandlerRecord) io_handlers = - QLIST_HEAD_INITIALIZER(io_handlers); - - -/* XXX: fd_read_poll should be suppressed, but an API change is - necessary in the character devices to suppress fd_can_read(). */ -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - IOHandlerRecord *ioh; - - if (!fd_read && !fd_write) { - QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->fd == fd) { - ioh->deleted = 1; - break; - } - } - } else { - QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->fd == fd) - goto found; - } - ioh = qemu_mallocz(sizeof(IOHandlerRecord)); - QLIST_INSERT_HEAD(&io_handlers, ioh, next); - found: - ioh->fd = fd; - ioh->fd_read_poll = fd_read_poll; - ioh->fd_read = fd_read; - ioh->fd_write = fd_write; - ioh->opaque = opaque; - ioh->deleted = 0; - } - return 0; -} - -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) -{ - return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); -} - /***********************************************************/ /* machine registration */ @@ -1343,7 +1281,6 @@ void qemu_system_vmstop_request(int reason) void main_loop_wait(int nonblocking) { - IOHandlerRecord *ioh; fd_set rfds, wfds, xfds; int ret, nfds; struct timeval tv; @@ -1358,56 +1295,23 @@ void main_loop_wait(int nonblocking) os_host_main_loop_wait(&timeout); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); - QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->deleted) - continue; - if (ioh->fd_read && - (!ioh->fd_read_poll || - ioh->fd_read_poll(ioh->opaque) != 0)) { - FD_SET(ioh->fd, &rfds); - if (ioh->fd > nfds) - nfds = ioh->fd; - } - if (ioh->fd_write) { - FD_SET(ioh->fd, &wfds); - if (ioh->fd > nfds) - nfds = ioh->fd; - } - } - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - + qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); slirp_select_fill(&nfds, &rfds, &wfds, &xfds); qemu_mutex_unlock_iothread(); ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); qemu_mutex_lock_iothread(); - if (ret > 0) { - IOHandlerRecord *pioh; - - QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { - if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { - ioh->fd_read(ioh->opaque); - } - if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { - ioh->fd_write(ioh->opaque); - } - - /* Do this last in case read/write handlers marked it for deletion */ - if (ioh->deleted) { - QLIST_REMOVE(ioh, next); - qemu_free(ioh); - } - } - } + qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); qemu_run_all_timers(); From 4d54ec7898bd951007cb6122d5315584bd41d0c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 9 Mar 2011 18:21:10 +0100 Subject: [PATCH 002/386] add a service to reap zombies, use it in SLIRP SLIRP -smb support wants to fork a process and forget about reaping it. To please it, add a generic service to register a process id and let QEMU reap it. In the future it could be enhanced to pass a status, but this would be unused. With this in place, the SIGCHLD signal handler would not stomp on pclose anymore. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> --- iohandler.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ os-posix.c | 9 -------- qemu-common.h | 1 + slirp/misc.c | 5 +++- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/iohandler.c b/iohandler.c index 2e30fe3bcb..2b824218e5 100644 --- a/iohandler.c +++ b/iohandler.c @@ -27,6 +27,10 @@ #include "qemu-char.h" #include "qemu-queue.h" +#ifndef _WIN32 +#include <sys/wait.h> +#endif + typedef struct IOHandlerRecord { int fd; IOCanReadHandler *fd_read_poll; @@ -127,3 +131,63 @@ void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int re } } } + +/* reaping of zombies. right now we're not passing the status to + anyone, but it would be possible to add a callback. */ +#ifndef _WIN32 +typedef struct ChildProcessRecord { + int pid; + QLIST_ENTRY(ChildProcessRecord) next; +} ChildProcessRecord; + +static QLIST_HEAD(, ChildProcessRecord) child_watches = + QLIST_HEAD_INITIALIZER(child_watches); + +static QEMUBH *sigchld_bh; + +static void sigchld_handler(int signal) +{ + qemu_bh_schedule(sigchld_bh); +} + +static void sigchld_bh_handler(void *opaque) +{ + ChildProcessRecord *rec, *next; + + QLIST_FOREACH_SAFE(rec, &child_watches, next, next) { + if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) { + QLIST_REMOVE(rec, next); + qemu_free(rec); + } + } +} + +static void qemu_init_child_watch(void) +{ + struct sigaction act; + sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL); + + act.sa_handler = sigchld_handler; + act.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &act, NULL); +} + +int qemu_add_child_watch(pid_t pid) +{ + ChildProcessRecord *rec; + + if (!sigchld_bh) { + qemu_init_child_watch(); + } + + QLIST_FOREACH(rec, &child_watches, next) { + if (rec->pid == pid) { + return 1; + } + } + rec = qemu_mallocz(sizeof(ChildProcessRecord)); + rec->pid = pid; + QLIST_INSERT_HEAD(&child_watches, rec, next); + return 0; +} +#endif diff --git a/os-posix.c b/os-posix.c index eb49e2f177..320419793a 100644 --- a/os-posix.c +++ b/os-posix.c @@ -67,11 +67,6 @@ static void termsig_handler(int signal, siginfo_t *info, void *c) qemu_system_killed(info->si_signo, info->si_pid); } -static void sigchld_handler(int signal) -{ - waitpid(-1, NULL, WNOHANG); -} - void os_setup_signal_handling(void) { struct sigaction act; @@ -82,10 +77,6 @@ void os_setup_signal_handling(void) sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGTERM, &act, NULL); - - act.sa_handler = sigchld_handler; - act.sa_flags = SA_NOCLDSTOP; - sigaction(SIGCHLD, &act, NULL); } /* Find a likely location for support files using the location of the binary. diff --git a/qemu-common.h b/qemu-common.h index 665c89380b..8ecb48820a 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -214,6 +214,7 @@ ssize_t qemu_write_full(int fd, const void *buf, size_t count) void qemu_set_cloexec(int fd); #ifndef _WIN32 +int qemu_add_child_watch(pid_t pid); int qemu_eventfd(int pipefd[2]); int qemu_pipe(int pipefd[2]); #endif diff --git a/slirp/misc.c b/slirp/misc.c index 19dbec491f..08eba6adc0 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -119,6 +119,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) char *bptr; const char *curarg; int c, i, ret; + pid_t pid; DEBUG_CALL("fork_exec"); DEBUG_ARG("so = %lx", (long)so); @@ -142,7 +143,8 @@ fork_exec(struct socket *so, const char *ex, int do_pty) } } - switch(fork()) { + pid = fork(); + switch(pid) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); close(s); @@ -206,6 +208,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) exit(1); default: + qemu_add_child_watch(pid); if (do_pty == 2) { close(s); so->s = master; From fcda98630b121a63c9de0705df02e59f4dc2fecc Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:00:13 +0100 Subject: [PATCH 003/386] lm32: rename raise opcode to scall To be consistent with the new reference manual. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-lm32/lm32-decode.h | 2 +- target-lm32/translate.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target-lm32/lm32-decode.h b/target-lm32/lm32-decode.h index f745b39626..42205d931e 100644 --- a/target-lm32/lm32-decode.h +++ b/target-lm32/lm32-decode.h @@ -60,7 +60,7 @@ #define DEC_NOR {B8(00000001), B8(00011111)} #define DEC_OR {B8(00001110), B8(00011111)} #define DEC_ORHI {B8(00011110), B8(00111111)} -#define DEC_RAISE {B8(00101011), B8(00111111)} +#define DEC_SCALL {B8(00101011), B8(00111111)} #define DEC_RCSR {B8(00100100), B8(00111111)} #define DEC_SB {B8(00001100), B8(00111111)} #define DEC_SEXTB {B8(00101100), B8(00111111)} diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 0b0e405fe7..aa08a142e2 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -583,7 +583,7 @@ static void dec_orhi(DisasContext *dc) tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16)); } -static void dec_raise(DisasContext *dc) +static void dec_scall(DisasContext *dc) { TCGv t0; int l1; @@ -1002,7 +1002,7 @@ static const DecoderInfo decinfo[] = { {DEC_NOR, dec_nor}, {DEC_OR, dec_or}, {DEC_ORHI, dec_orhi}, - {DEC_RAISE, dec_raise}, + {DEC_SCALL, dec_scall}, {DEC_RCSR, dec_rcsr}, {DEC_SB, dec_sb}, {DEC_SEXTB, dec_sextb}, From a5086f95421e43c7b9e1b28a111aae0be4848117 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:01:04 +0100 Subject: [PATCH 004/386] lm32: use lookup table for opcodes Instead of a for loop use a faster lookup table. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-lm32/lm32-decode.h | 78 -------------------------------------- target-lm32/translate.c | 80 +++++++++------------------------------ 2 files changed, 18 insertions(+), 140 deletions(-) delete mode 100644 target-lm32/lm32-decode.h diff --git a/target-lm32/lm32-decode.h b/target-lm32/lm32-decode.h deleted file mode 100644 index 42205d931e..0000000000 --- a/target-lm32/lm32-decode.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * LatticeMico32 instruction decoding macros. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -/* Convenient binary macros */ -#define HEX__(n) 0x##n##LU -#define B8__(x) (((x&0x0000000FLU) ? 1 : 0) \ - + ((x&0x000000F0LU) ? 2 : 0) \ - + ((x&0x00000F00LU) ? 4 : 0) \ - + ((x&0x0000F000LU) ? 8 : 0) \ - + ((x&0x000F0000LU) ? 16 : 0) \ - + ((x&0x00F00000LU) ? 32 : 0) \ - + ((x&0x0F000000LU) ? 64 : 0) \ - + ((x&0xF0000000LU) ? 128 : 0)) -#define B8(d) ((unsigned char)B8__(HEX__(d))) - -/* Decode logic, value and mask. */ -#define DEC_ADD {B8(00001101), B8(00011111)} -#define DEC_AND {B8(00001000), B8(00011111)} -#define DEC_ANDHI {B8(00011000), B8(00111111)} -#define DEC_B {B8(00110000), B8(00111111)} -#define DEC_BI {B8(00111000), B8(00111111)} -#define DEC_BE {B8(00010001), B8(00111111)} -#define DEC_BG {B8(00010010), B8(00111111)} -#define DEC_BGE {B8(00010011), B8(00111111)} -#define DEC_BGEU {B8(00010100), B8(00111111)} -#define DEC_BGU {B8(00010101), B8(00111111)} -#define DEC_BNE {B8(00010111), B8(00111111)} -#define DEC_CALL {B8(00110110), B8(00111111)} -#define DEC_CALLI {B8(00111110), B8(00111111)} -#define DEC_CMPE {B8(00011001), B8(00011111)} -#define DEC_CMPG {B8(00011010), B8(00011111)} -#define DEC_CMPGE {B8(00011011), B8(00011111)} -#define DEC_CMPGEU {B8(00011100), B8(00011111)} -#define DEC_CMPGU {B8(00011101), B8(00011111)} -#define DEC_CMPNE {B8(00011111), B8(00011111)} -#define DEC_DIVU {B8(00100011), B8(00111111)} -#define DEC_LB {B8(00000100), B8(00111111)} -#define DEC_LBU {B8(00010000), B8(00111111)} -#define DEC_LH {B8(00000111), B8(00111111)} -#define DEC_LHU {B8(00001011), B8(00111111)} -#define DEC_LW {B8(00001010), B8(00111111)} -#define DEC_MODU {B8(00110001), B8(00111111)} -#define DEC_MUL {B8(00000010), B8(00011111)} -#define DEC_NOR {B8(00000001), B8(00011111)} -#define DEC_OR {B8(00001110), B8(00011111)} -#define DEC_ORHI {B8(00011110), B8(00111111)} -#define DEC_SCALL {B8(00101011), B8(00111111)} -#define DEC_RCSR {B8(00100100), B8(00111111)} -#define DEC_SB {B8(00001100), B8(00111111)} -#define DEC_SEXTB {B8(00101100), B8(00111111)} -#define DEC_SEXTH {B8(00110111), B8(00111111)} -#define DEC_SH {B8(00000011), B8(00111111)} -#define DEC_SL {B8(00001111), B8(00011111)} -#define DEC_SR {B8(00000101), B8(00011111)} -#define DEC_SRU {B8(00000000), B8(00011111)} -#define DEC_SUB {B8(00110010), B8(00111111)} -#define DEC_SW {B8(00010110), B8(00111111)} -#define DEC_USER {B8(00110011), B8(00111111)} -#define DEC_WCSR {B8(00110100), B8(00111111)} -#define DEC_XNOR {B8(00001001), B8(00011111)} -#define DEC_XOR {B8(00000110), B8(00011111)} - diff --git a/target-lm32/translate.c b/target-lm32/translate.c index aa08a142e2..666d5f4dc3 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -29,7 +29,6 @@ #include "disas.h" #include "helper.h" #include "tcg-op.h" -#include "lm32-decode.h" #include "qemu-common.h" #include "hw/lm32_pic.h" @@ -963,66 +962,28 @@ static void dec_xor(DisasContext *dc) } } -typedef struct { - struct { - uint32_t bits; - uint32_t mask; - }; - void (*dec)(DisasContext *dc); -} DecoderInfo; +static void dec_ill(DisasContext *dc) +{ + cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode); +} +typedef void (*DecoderInfo)(DisasContext *dc); static const DecoderInfo decinfo[] = { - {DEC_ADD, dec_add}, - {DEC_AND, dec_and}, - {DEC_ANDHI, dec_andhi}, - {DEC_B, dec_b}, - {DEC_BI, dec_bi}, - {DEC_BE, dec_be}, - {DEC_BG, dec_bg}, - {DEC_BGE, dec_bge}, - {DEC_BGEU, dec_bgeu}, - {DEC_BGU, dec_bgu}, - {DEC_BNE, dec_bne}, - {DEC_CALL, dec_call}, - {DEC_CALLI, dec_calli}, - {DEC_CMPE, dec_cmpe}, - {DEC_CMPG, dec_cmpg}, - {DEC_CMPGE, dec_cmpge}, - {DEC_CMPGEU, dec_cmpgeu}, - {DEC_CMPGU, dec_cmpgu}, - {DEC_CMPNE, dec_cmpne}, - {DEC_DIVU, dec_divu}, - {DEC_LB, dec_lb}, - {DEC_LBU, dec_lbu}, - {DEC_LH, dec_lh}, - {DEC_LHU, dec_lhu}, - {DEC_LW, dec_lw}, - {DEC_MODU, dec_modu}, - {DEC_MUL, dec_mul}, - {DEC_NOR, dec_nor}, - {DEC_OR, dec_or}, - {DEC_ORHI, dec_orhi}, - {DEC_SCALL, dec_scall}, - {DEC_RCSR, dec_rcsr}, - {DEC_SB, dec_sb}, - {DEC_SEXTB, dec_sextb}, - {DEC_SEXTH, dec_sexth}, - {DEC_SH, dec_sh}, - {DEC_SL, dec_sl}, - {DEC_SR, dec_sr}, - {DEC_SRU, dec_sru}, - {DEC_SUB, dec_sub}, - {DEC_SW, dec_sw}, - {DEC_USER, dec_user}, - {DEC_WCSR, dec_wcsr}, - {DEC_XNOR, dec_xnor}, - {DEC_XOR, dec_xor}, + dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh, + dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl, + dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne, + dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi, + dec_cmpne, + dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill, + dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl, + dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth, + dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli, + dec_cmpne }; static inline void decode(DisasContext *dc) { uint32_t ir; - int i; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { tcg_gen_debug_insn_start(dc->pc); @@ -1061,15 +1022,10 @@ static inline void decode(DisasContext *dc) dc->format = OP_FMT_RI; } - /* Large switch for all insns. */ - for (i = 0; i < ARRAY_SIZE(decinfo); i++) { - if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { - decinfo[i].dec(dc); - return; - } - } + assert(ARRAY_SIZE(decinfo) == 64); + assert(dc->opcode < 64); - cpu_abort(dc->env, "unknown opcode 0x%02x\n", dc->opcode); + decinfo[dc->opcode](dc); } static void check_breakpoint(CPUState *env, DisasContext *dc) From 17d9b3af5b7f93e43d7fbdcb6f14cad54de9f1ae Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Tue, 22 Mar 2011 07:41:29 +0100 Subject: [PATCH 005/386] target-ppc: ext32u instead of andi with constant Cc: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3d265e3b11..49eab284a4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6975,7 +6975,7 @@ static inline void gen_evmergelo(DisasContext *ctx) #if defined(TARGET_PPC64) TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL); + tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); tcg_temp_free(t0); @@ -6994,7 +6994,7 @@ static inline void gen_evmergehilo(DisasContext *ctx) #if defined(TARGET_PPC64) TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL); + tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); tcg_temp_free(t0); @@ -7083,14 +7083,14 @@ static inline void gen_evsel(DisasContext *ctx) tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2); tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3); #if defined(TARGET_PPC64) - tcg_gen_andi_tl(t2, cpu_gpr[rA(ctx->opcode)], 0x00000000FFFFFFFFULL); + tcg_gen_ext32u_tl(t2, cpu_gpr[rA(ctx->opcode)]); #else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); #endif tcg_gen_br(l4); gen_set_label(l3); #if defined(TARGET_PPC64) - tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFULL); + tcg_gen_ext32u_tl(t2, cpu_gpr[rB(ctx->opcode)]); #else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); #endif From 81762d6dd0d430d87024f2c83e9c4dcc4329fb7d Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:08 +1100 Subject: [PATCH 006/386] Clean up PowerPC SLB handling code Currently the SLB information when emulating a PowerPC 970 is storeed in a structure with the unhelpfully named fields 'tmp' and 'tmp64'. While the layout in these fields does match the description of the SLB in the architecture document, it is not convenient either for looking up the SLB, or for emulating the slbmte instruction. This patch, therefore, reorganizes the SLB entry structure to be divided in the the "ESID related" and "VSID related" fields as they are divided in instructions accessing the SLB. In addition to making the code smaller and more readable, this will make it easier to implement for the 1TB segments used in more recent PowerPC chips. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 29 ++++++- target-ppc/helper.c | 188 ++++++++++++----------------------------- target-ppc/helper.h | 1 - target-ppc/op_helper.c | 9 +- 4 files changed, 85 insertions(+), 142 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index deb8d7c9c5..124bbbf650 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -43,6 +43,8 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 64 #endif +#define TARGET_PAGE_BITS_16M 24 + #else /* defined (TARGET_PPC64) */ /* PowerPC 32 definitions */ #define TARGET_LONG_BITS 32 @@ -359,10 +361,31 @@ union ppc_tlb_t { typedef struct ppc_slb_t ppc_slb_t; struct ppc_slb_t { - uint64_t tmp64; - uint32_t tmp; + uint64_t esid; + uint64_t vsid; }; +/* Bits in the SLB ESID word */ +#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL +#define SLB_ESID_V 0x0000000008000000ULL /* valid */ + +/* Bits in the SLB VSID word */ +#define SLB_VSID_SHIFT 12 +#define SLB_VSID_SSIZE_SHIFT 62 +#define SLB_VSID_B 0xc000000000000000ULL +#define SLB_VSID_B_256M 0x0000000000000000ULL +#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL +#define SLB_VSID_KS 0x0000000000000800ULL +#define SLB_VSID_KP 0x0000000000000400ULL +#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */ +#define SLB_VSID_L 0x0000000000000100ULL +#define SLB_VSID_C 0x0000000000000080ULL /* class */ +#define SLB_VSID_LP 0x0000000000000030ULL +#define SLB_VSID_ATTR 0x0000000000000FFFULL + +#define SEGMENT_SHIFT_256M 28 +#define SEGMENT_MASK_256M (~((1ULL << SEGMENT_SHIFT_256M) - 1)) + /*****************************************************************************/ /* Machine state register bits definition */ #define MSR_SF 63 /* Sixty-four-bit mode hflags */ @@ -755,7 +778,7 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); void ppc_store_asr (CPUPPCState *env, target_ulong value); target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr); target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr); -void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); +int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); #endif /* defined(TARGET_PPC64) */ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4b491012d7..2094ca36f9 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -672,85 +672,36 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw, } #if defined(TARGET_PPC64) -static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr) -{ - ppc_slb_t *retval = &env->slb[nr]; - -#if 0 // XXX implement bridge mode? - if (env->spr[SPR_ASR] & 1) { - target_phys_addr_t sr_base; - - sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000; - sr_base += (12 * nr); - - retval->tmp64 = ldq_phys(sr_base); - retval->tmp = ldl_phys(sr_base + 8); - } -#endif - - return retval; -} - -static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb) -{ - ppc_slb_t *entry = &env->slb[nr]; - - if (slb == entry) - return; - - entry->tmp64 = slb->tmp64; - entry->tmp = slb->tmp; -} - -static inline int slb_is_valid(ppc_slb_t *slb) -{ - return (int)(slb->tmp64 & 0x0000000008000000ULL); -} - -static inline void slb_invalidate(ppc_slb_t *slb) -{ - slb->tmp64 &= ~0x0000000008000000ULL; -} - static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr, target_ulong *vsid, target_ulong *page_mask, int *attr, int *target_page_bits) { - target_ulong mask; - int n, ret; + uint64_t esid; + int n; - ret = -5; LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); - mask = 0x0000000000000000ULL; /* Avoid gcc warning */ - for (n = 0; n < env->slb_nr; n++) { - ppc_slb_t *slb = slb_get_entry(env, n); - LOG_SLB("%s: seg %d %016" PRIx64 " %08" - PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp); - if (slb_is_valid(slb)) { - /* SLB entry is valid */ - mask = 0xFFFFFFFFF0000000ULL; - if (slb->tmp & 0x8) { - /* 16 MB PTEs */ - if (target_page_bits) - *target_page_bits = 24; - } else { - /* 4 KB PTEs */ - if (target_page_bits) - *target_page_bits = TARGET_PAGE_BITS; - } - if ((eaddr & mask) == (slb->tmp64 & mask)) { - /* SLB match */ - *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; - *page_mask = ~mask; - *attr = slb->tmp & 0xFF; - ret = n; - break; + esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; + + for (n = 0; n < env->slb_nr; n++) { + ppc_slb_t *slb = &env->slb[n]; + + LOG_SLB("%s: slot %d %016" PRIx64 " %016" + PRIx64 "\n", __func__, n, slb->esid, slb->vsid); + if (slb->esid == esid) { + *vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + *page_mask = ~SEGMENT_MASK_256M; + *attr = slb->vsid & SLB_VSID_ATTR; + if (target_page_bits) { + *target_page_bits = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M + : TARGET_PAGE_BITS; } + return n; } } - return ret; + return -5; } void ppc_slb_invalidate_all (CPUPPCState *env) @@ -760,11 +711,10 @@ void ppc_slb_invalidate_all (CPUPPCState *env) do_invalidate = 0; /* XXX: Warning: slbia never invalidates the first segment */ for (n = 1; n < env->slb_nr; n++) { - ppc_slb_t *slb = slb_get_entry(env, n); + ppc_slb_t *slb = &env->slb[n]; - if (slb_is_valid(slb)) { - slb_invalidate(slb); - slb_set_entry(env, n, slb); + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; /* XXX: given the fact that segment size is 256 MB or 1TB, * and we still don't have a tlb_flush_mask(env, n, mask) * in Qemu, we just invalidate all TLBs @@ -781,68 +731,44 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) target_ulong vsid, page_mask; int attr; int n; - - n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); - if (n >= 0) { - ppc_slb_t *slb = slb_get_entry(env, n); - - if (slb_is_valid(slb)) { - slb_invalidate(slb); - slb_set_entry(env, n, slb); - /* XXX: given the fact that segment size is 256 MB or 1TB, - * and we still don't have a tlb_flush_mask(env, n, mask) - * in Qemu, we just invalidate all TLBs - */ - tlb_flush(env, 1); - } - } -} - -target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) -{ - target_ulong rt; - ppc_slb_t *slb = slb_get_entry(env, slb_nr); - - if (slb_is_valid(slb)) { - /* SLB entry is valid */ - /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */ - rt = slb->tmp >> 8; /* 65:88 => 40:63 */ - rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */ - /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */ - rt |= ((slb->tmp >> 4) & 0xF) << 27; - } else { - rt = 0; - } - LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d " - TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt); - - return rt; -} - -void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) -{ ppc_slb_t *slb; - uint64_t vsid; - uint64_t esid; - int flags, valid, slb_nr; + n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); + if (n < 0) { + return; + } - vsid = rs >> 12; - flags = ((rs >> 8) & 0xf); + slb = &env->slb[n]; - esid = rb >> 28; - valid = (rb & (1 << 27)); - slb_nr = rb & 0xfff; + if (slb->esid & SLB_ESID_V) { + slb->esid &= ~SLB_ESID_V; - slb = slb_get_entry(env, slb_nr); - slb->tmp64 = (esid << 28) | valid | (vsid >> 24); - slb->tmp = (vsid << 8) | (flags << 3); + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in Qemu, we just invalidate all TLBs + */ + tlb_flush(env, 1); + } +} + +int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) +{ + int slot = rb & 0xfff; + uint64_t esid = rb & ~0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + slb->esid = esid; + slb->vsid = rs; LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 - " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64, - slb->tmp); + " %016" PRIx64 "\n", __func__, slot, rb, rs, + slb->esid, slb->vsid); - slb_set_entry(env, slb_nr, slb); + return 0; } #endif /* defined(TARGET_PPC64) */ @@ -860,24 +786,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, { target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; target_ulong sr, vsid, vsid_mask, pgidx, page_mask; -#if defined(TARGET_PPC64) - int attr; -#endif int ds, vsid_sh, sdr_sh, pr, target_page_bits; int ret, ret2; pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { + int attr; + LOG_MMU("Check SLBs\n"); ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr, &target_page_bits); if (ret < 0) return ret; - ctx->key = ((attr & 0x40) && (pr != 0)) || - ((attr & 0x80) && (pr == 0)) ? 1 : 0; + ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS)); ds = 0; - ctx->nx = attr & 0x10 ? 1 : 0; + ctx->nx = !!(attr & SLB_VSID_N); ctx->eaddr = eaddr; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 2bf9283486..d512cb00e2 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -340,7 +340,6 @@ DEF_HELPER_1(74xx_tlbi, void, tl) DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void) DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_1(load_slb, TCG_CALL_CONST, tl, tl) DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl) DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void) DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 17e070ae75..bf41627b21 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3746,14 +3746,11 @@ void helper_store_sr (target_ulong sr_num, target_ulong val) /* SLB management */ #if defined(TARGET_PPC64) -target_ulong helper_load_slb (target_ulong slb_nr) -{ - return ppc_load_slb(env, slb_nr); -} - void helper_store_slb (target_ulong rb, target_ulong rs) { - ppc_store_slb(env, rb, rs); + if (ppc_store_slb(env, rb, rs) < 0) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + } } void helper_slbia (void) From c48974903051ceb7cfbda23c22c159ea4b482d93 Mon Sep 17 00:00:00 2001 From: David Gibson <dwg@au1.ibm.com> Date: Fri, 1 Apr 2011 15:15:09 +1100 Subject: [PATCH 007/386] Allow qemu_devtree_setprop() to take arbitrary values Currently qemu_devtree_setprop() expects the new property value to be given as a uint32_t *. While property values consisting of u32s are common, in general they can have any bytestring value. Therefore, this patch alters the function to take a void * instead, allowing callers to easily give anything as the property value. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de> --- device_tree.c | 2 +- device_tree.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device_tree.c b/device_tree.c index 426a63155c..21be070759 100644 --- a/device_tree.c +++ b/device_tree.c @@ -74,7 +74,7 @@ fail: } int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, uint32_t *val_array, int size) + const char *property, void *val_array, int size) { int offset; diff --git a/device_tree.h b/device_tree.h index f05c4e7311..cecd98f042 100644 --- a/device_tree.h +++ b/device_tree.h @@ -17,7 +17,7 @@ void *load_device_tree(const char *filename_path, int *sizep); int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, uint32_t *val_array, int size); + const char *property, void *val_array, int size); int qemu_devtree_setprop_cell(void *fdt, const char *node_path, const char *property, uint32_t val); int qemu_devtree_setprop_string(void *fdt, const char *node_path, From d569956eaff4be808419f1f259a5c388d8789db4 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:10 +1100 Subject: [PATCH 008/386] Add a hook to allow hypercalls to be emulated on PowerPC PowerPC and POWER chips since the POWER4 and 970 have a special hypervisor mode, and a corresponding form of the system call instruction which traps to the hypervisor. qemu currently has stub implementations of hypervisor mode. That is, the outline is there to allow qemu to run a PowerPC hypervisor under emulation. There are a number of details missing so this won't actually work at present, but the idea is there. What there is no provision at all, is for qemu to instead emulate the hypervisor itself. That is to have hypercalls trap into qemu and their result be emulated from qemu, rather than running hypervisor code within the emulated system. Hypervisor hardware aware KVM implementations are in the works and it would be useful for debugging and development to also allow full emulation of the same para-virtualized guests as such a KVM. Therefore, this patch adds a hook which will allow a machine to set up emulation of hypervisor calls. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 124bbbf650..36ca342286 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1646,4 +1646,6 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) #endif } +extern void (*cpu_ppc_hypercall)(CPUState *); + #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 2094ca36f9..452a35cb48 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -70,6 +70,10 @@ # define LOG_EXCP(...) do { } while (0) #endif +/*****************************************************************************/ +/* PowerPC Hypercall emulation */ + +void (*cpu_ppc_hypercall)(CPUState *); /*****************************************************************************/ /* PowerPC MMU emulation */ @@ -2152,6 +2156,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp) case POWERPC_EXCP_SYSCALL: /* System call exception */ dump_syscall(env); lev = env->error_code; + if ((lev == 1) && cpu_ppc_hypercall) { + cpu_ppc_hypercall(env); + return; + } if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) new_msr |= (target_ulong)MSR_HVB; goto store_next; From efdef95fee7e150ac065e7b33ffbebd09a5ac83c Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:11 +1100 Subject: [PATCH 009/386] Implement PowerPC slbmfee and slbmfev instructions For a 64-bit PowerPC target, qemu correctly implements translation through the segment lookaside buffer. Likewise it supports the slbmte instruction which is used to load entries into the SLB. However, it does not emulate the slbmfee and slbmfev instructions which read SLB entries back into registers. Because these are only occasionally used in guests (mostly for debugging) we get away with it. However, given the recent SLB cleanups, it becomes quite easy to implement these, and thereby allow, amongst other things, a guest Linux to use xmon's command to dump the SLB. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 26 ++++++++++++++++++++++++++ target-ppc/helper.h | 2 ++ target-ppc/op_helper.c | 20 ++++++++++++++++++++ target-ppc/translate.c | 31 ++++++++++++++++++++++++++++++- 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 36ca342286..f293f85976 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -779,6 +779,8 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value); target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr); target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr); int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); +int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt); +int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt); #endif /* defined(TARGET_PPC64) */ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 452a35cb48..b9621d2dd0 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -774,6 +774,32 @@ int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) return 0; } + +int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->esid; + return 0; +} + +int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt) +{ + int slot = rb & 0xfff; + ppc_slb_t *slb = &env->slb[slot]; + + if (slot >= env->slb_nr) { + return -1; + } + + *rt = slb->vsid; + return 0; +} #endif /* defined(TARGET_PPC64) */ /* Perform segment based translation */ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d512cb00e2..1a69cf876c 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -341,6 +341,8 @@ DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void) DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl) +DEF_HELPER_1(load_slb_esid, tl, tl) +DEF_HELPER_1(load_slb_vsid, tl, tl) DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void) DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl) #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index bf41627b21..bdb1f1732a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3753,6 +3753,26 @@ void helper_store_slb (target_ulong rb, target_ulong rs) } } +target_ulong helper_load_slb_esid (target_ulong rb) +{ + target_ulong rt; + + if (ppc_load_slb_esid(env, rb, &rt) < 0) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + } + return rt; +} + +target_ulong helper_load_slb_vsid (target_ulong rb) +{ + target_ulong rt; + + if (ppc_load_slb_vsid(env, rb, &rt) < 0) { + helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL); + } + return rt; +} + void helper_slbia (void) { ppc_slb_invalidate_all(env); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 49eab284a4..4252508327 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4227,6 +4227,33 @@ static void gen_slbmte(DisasContext *ctx) #endif } +static void gen_slbmfee(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); +#else + if (unlikely(!ctx->mem_idx)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return; + } + gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); +#endif +} + +static void gen_slbmfev(DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); +#else + if (unlikely(!ctx->mem_idx)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return; + } + gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], + cpu_gpr[rB(ctx->opcode)]); +#endif +} #endif /* defined(TARGET_PPC64) */ /*** Lookaside buffer management ***/ @@ -8300,7 +8327,9 @@ GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001, GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B), GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B), -GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x00000000, PPC_SEGMENT_64B), +GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B), +GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B), +GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), #endif GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE), From 3a7f009abc010827815f10805e3558aa64c98e59 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:12 +1100 Subject: [PATCH 010/386] Implement missing parts of the logic for the POWER PURR The PURR (Processor Utilization Resource Register) is a register found on recent POWER CPUs. The guts of implementing it at least enough to get by are already present in qemu, however some of the helper functions needed to actually wire it up are missing. This patch adds the necessary glue, so that the PURR can be wired up when we implement newer POWER CPU targets which include it. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/helper.h | 1 + target-ppc/op_helper.c | 7 +++++++ target-ppc/translate_init.c | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 1a69cf876c..2b4744d331 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -376,6 +376,7 @@ DEF_HELPER_0(load_601_rtcu, tl) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) DEF_HELPER_1(store_asr, void, tl) +DEF_HELPER_0(load_purr, tl) #endif DEF_HELPER_1(store_sdr1, void, tl) DEF_HELPER_1(store_tbl, void, tl) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index bdb1f1732a..aa2e8ba415 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -86,6 +86,13 @@ target_ulong helper_load_atbu (void) return cpu_ppc_load_atbu(env); } +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +target_ulong helper_load_purr (void) +{ + return (target_ulong)cpu_ppc_load_purr(env); +} +#endif + target_ulong helper_load_601_rtcl (void) { return cpu_ppc601_load_rtcl(env); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7c08b1cb09..bca85d5073 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -251,6 +251,14 @@ static void spr_write_atbu (void *opaque, int sprn, int gprn) { gen_helper_store_atbu(cpu_gpr[gprn]); } + +#if defined(TARGET_PPC64) +__attribute__ (( unused )) +static void spr_read_purr (void *opaque, int gprn, int sprn) +{ + gen_helper_load_purr(cpu_gpr[gprn]); +} +#endif #endif #if !defined(CONFIG_USER_ONLY) From eaabeef2688cdc7da462e9389fce64b1178de8ce Mon Sep 17 00:00:00 2001 From: David Gibson <dwg@au1.ibm.com> Date: Fri, 1 Apr 2011 15:15:13 +1100 Subject: [PATCH 011/386] Correct ppc popcntb logic, implement popcntw and popcntd qemu already includes support for the popcntb instruction introduced in POWER5 (although it doesn't actually allow you to choose POWER5). However, the logic is slightly incorrect: it will generate results truncated to 32-bits when the CPU is in 32-bit mode. This is not normal for powerpc - generally arithmetic instructions on a 64-bit powerpc cpu will generate full 64 bit results, it's just that only the low 32 bits will be significant for condition codes. This patch corrects this nit, which actually simplifies the code slightly. In addition, this patch implements the popcntw and popcntd instructions added in POWER7, in preparation for allowing POWER7 as an emulated CPU. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 2 ++ target-ppc/helper.h | 3 ++- target-ppc/op_helper.c | 55 ++++++++++++++++++++++++++++++++++++++---- target-ppc/translate.c | 22 ++++++++++++----- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f293f85976..37dde390a8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1505,6 +1505,8 @@ enum { PPC_DCRX = 0x2000000000000000ULL, /* user-mode DCR access, implemented in PowerPC 460 */ PPC_DCRUX = 0x4000000000000000ULL, + /* popcntw and popcntd instructions */ + PPC_POPCNTWD = 0x8000000000000000ULL, }; /*****************************************************************************/ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 2b4744d331..7c02be9cfd 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -38,10 +38,11 @@ DEF_HELPER_2(mulldo, i64, i64, i64) DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_2(sraw, tl, tl, tl) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) -DEF_HELPER_FLAGS_1(popcntb_64, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) DEF_HELPER_2(srad, tl, tl, tl) #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index aa2e8ba415..b1b883d0a7 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -499,6 +499,50 @@ target_ulong helper_srad (target_ulong value, target_ulong shift) } #endif +#if defined(TARGET_PPC64) +target_ulong helper_popcntb (target_ulong val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & + 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & + 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & + 0x0f0f0f0f0f0f0f0fULL); + return val; +} + +target_ulong helper_popcntw (target_ulong val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & + 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & + 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & + 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & + 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & + 0x0000ffff0000ffffULL); + return val; +} + +target_ulong helper_popcntd (target_ulong val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & + 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & + 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & + 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & + 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & + 0x0000ffff0000ffffULL); + val = (val & 0x00000000ffffffffULL) + ((val >> 32) & + 0x00000000ffffffffULL); + return val; +} +#else target_ulong helper_popcntb (target_ulong val) { val = (val & 0x55555555) + ((val >> 1) & 0x55555555); @@ -507,12 +551,13 @@ target_ulong helper_popcntb (target_ulong val) return val; } -#if defined(TARGET_PPC64) -target_ulong helper_popcntb_64 (target_ulong val) +target_ulong helper_popcntw (target_ulong val) { - val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); - val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); - val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); + val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); return val; } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4252508327..88681359c7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1483,14 +1483,22 @@ static void gen_xoris(DisasContext *ctx) /* popcntb : PowerPC 2.03 specification */ static void gen_popcntb(DisasContext *ctx) { -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); - else -#endif - gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); + gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); } +static void gen_popcntw(DisasContext *ctx) +{ + gen_helper_popcntw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); +} + +#if defined(TARGET_PPC64) +/* popcntd: PowerPC 2.06 specification */ +static void gen_popcntd(DisasContext *ctx) +{ + gen_helper_popcntd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); +} +#endif + #if defined(TARGET_PPC64) /* extsw & extsw. */ GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B); @@ -8226,7 +8234,9 @@ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB), +GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD), #if defined(TARGET_PPC64) +GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B), #endif GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), From 8500e3a91292f253002783da267f3b08aead86c1 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:14 +1100 Subject: [PATCH 012/386] Clean up slb_lookup() function The slb_lookup() function, used in the ppc translation path returns a number of slb entry fields in reference parameters. However, only one of the two callers of slb_lookup() actually wants this information. This patch, therefore, makes slb_lookup() return a simple pointer to the located SLB entry (or NULL), and the caller which needs the fields can extract them itself. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/helper.c | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b9621d2dd0..7ca33cbc75 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -676,9 +676,7 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw, } #if defined(TARGET_PPC64) -static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr, - target_ulong *vsid, target_ulong *page_mask, - int *attr, int *target_page_bits) +static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) { uint64_t esid; int n; @@ -693,19 +691,11 @@ static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr, LOG_SLB("%s: slot %d %016" PRIx64 " %016" PRIx64 "\n", __func__, n, slb->esid, slb->vsid); if (slb->esid == esid) { - *vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; - *page_mask = ~SEGMENT_MASK_256M; - *attr = slb->vsid & SLB_VSID_ATTR; - if (target_page_bits) { - *target_page_bits = (slb->vsid & SLB_VSID_L) - ? TARGET_PAGE_BITS_16M - : TARGET_PAGE_BITS; - } - return n; + return slb; } } - return -5; + return NULL; } void ppc_slb_invalidate_all (CPUPPCState *env) @@ -732,18 +722,13 @@ void ppc_slb_invalidate_all (CPUPPCState *env) void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) { - target_ulong vsid, page_mask; - int attr; - int n; ppc_slb_t *slb; - n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); - if (n < 0) { + slb = slb_lookup(env, T0); + if (!slb) { return; } - slb = &env->slb[n]; - if (slb->esid & SLB_ESID_V) { slb->esid &= ~SLB_ESID_V; @@ -822,16 +807,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { - int attr; + ppc_slb_t *slb; LOG_MMU("Check SLBs\n"); - ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr, - &target_page_bits); - if (ret < 0) - return ret; - ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS)); + slb = slb_lookup(env, eaddr); + if (!slb) { + return -5; + } + + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + page_mask = ~SEGMENT_MASK_256M; + target_page_bits = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; + ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) + : (slb->vsid & SLB_VSID_KS)); ds = 0; - ctx->nx = !!(attr & SLB_VSID_N); + ctx->nx = !!(slb->vsid & SLB_VSID_N); ctx->eaddr = eaddr; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; From bb593904c18e22ea0671dfa1b02e24982f2bf0ea Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:15 +1100 Subject: [PATCH 013/386] Parse SDR1 on mtspr instead of at translate time On ppc machines with hash table MMUs, the special purpose register SDR1 contains both the base address of the encoded size (hashed) page tables. At present, we interpret the SDR1 value within the address translation path. But because the encodings of the size for 32-bit and 64-bit are different this makes for a confusing branch on the MMU type with a bunch of curly shifts and masks in the middle of the translate path. This patch cleans things up by moving the interpretation on SDR1 into the helper function handling the write to the register. This leaves a simple pre-sanitized base address and mask for the hash table in the CPUState structure which is easier to work with in the translation path. This makes the translation path more readable. It addresses the FIXME comment currently in the mtsdr1 helper, by validating the SDR1 value during interpretation. Finally it opens the way for emulating a pSeries-style partition where the hash table used for translation is not mapped into the guests's RAM. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- monitor.c | 2 +- target-ppc/cpu.h | 11 ++++- target-ppc/helper.c | 80 +++++++++++++++++++++---------------- target-ppc/kvm.c | 2 +- target-ppc/machine.c | 6 ++- target-ppc/translate.c | 2 +- target-ppc/translate_init.c | 7 +--- 7 files changed, 63 insertions(+), 47 deletions(-) diff --git a/monitor.c b/monitor.c index 76a82074ae..f1a08dc486 100644 --- a/monitor.c +++ b/monitor.c @@ -3462,7 +3462,7 @@ static const MonitorDef monitor_defs[] = { { "asr", offsetof(CPUState, asr) }, #endif /* Segment registers */ - { "sdr1", offsetof(CPUState, sdr1) }, + { "sdr1", offsetof(CPUState, spr[SPR_SDR1]) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, { "sr2", offsetof(CPUState, sr[2]) }, diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 37dde390a8..ead4566f4f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -359,6 +359,14 @@ union ppc_tlb_t { }; #endif +#define SDR_32_HTABORG 0xFFFF0000UL +#define SDR_32_HTABMASK 0x000001FFUL + +#if defined(TARGET_PPC64) +#define SDR_64_HTABORG 0xFFFFFFFFFFFC0000ULL +#define SDR_64_HTABSIZE 0x000000000000001FULL +#endif /* defined(TARGET_PPC64 */ + typedef struct ppc_slb_t ppc_slb_t; struct ppc_slb_t { uint64_t esid; @@ -642,7 +650,8 @@ struct CPUPPCState { int slb_nr; #endif /* segment registers */ - target_ulong sdr1; + target_phys_addr_t htab_base; + target_phys_addr_t htab_mask; target_ulong sr[32]; /* BATs */ int nb_BATs; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 7ca33cbc75..68d2d9c0e2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -788,20 +788,19 @@ int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt) #endif /* defined(TARGET_PPC64) */ /* Perform segment based translation */ -static inline target_phys_addr_t get_pgaddr(target_phys_addr_t sdr1, - int sdr_sh, - target_phys_addr_t hash, - target_phys_addr_t mask) +static inline target_phys_addr_t get_pgaddr(target_phys_addr_t htab_base, + target_phys_addr_t htab_mask, + target_phys_addr_t hash) { - return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask); + return htab_base | (hash & htab_mask); } static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type) { - target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; + target_phys_addr_t hash; target_ulong sr, vsid, vsid_mask, pgidx, page_mask; - int ds, vsid_sh, sdr_sh, pr, target_page_bits; + int ds, vsid_sh, pr, target_page_bits; int ret, ret2; pr = msr_pr; @@ -826,8 +825,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ctx->eaddr = eaddr; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; - sdr_sh = 18; - sdr_mask = 0x3FF80; } else #endif /* defined(TARGET_PPC64) */ { @@ -840,8 +837,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, vsid = sr & 0x00FFFFFF; vsid_mask = 0x01FFFFC0; vsid_sh = 6; - sdr_sh = 16; - sdr_mask = 0xFFC0; target_page_bits = TARGET_PAGE_BITS; LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx @@ -857,29 +852,26 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ /* Primary table address */ - sdr = env->sdr1; pgidx = (eaddr & page_mask) >> target_page_bits; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { - htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); /* XXX: this is false for 1 TB segments */ hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; } else #endif { - htab_mask = sdr & 0x000001FF; hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; } - mask = (htab_mask << sdr_sh) | sdr_mask; - LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx - " mask " TARGET_FMT_plx " " TARGET_FMT_lx "\n", - sdr, sdr_sh, hash, mask, page_mask); - ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + ctx->pg_addr[0] = get_pgaddr(env->htab_base, env->htab_mask, hash); /* Secondary table address */ hash = (~hash) & vsid_mask; - LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx - " mask " TARGET_FMT_plx "\n", sdr, sdr_sh, hash, mask); - ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + ctx->pg_addr[1] = get_pgaddr(env->htab_base, env->htab_mask, hash); #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ @@ -901,19 +893,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, /* Software TLB search */ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); } else { - LOG_MMU("0 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " " - "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx - " pg_addr=" TARGET_FMT_plx "\n", - sdr, vsid, pgidx, hash, ctx->pg_addr[0]); + LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, pgidx, hash, + ctx->pg_addr[0]); /* Primary table lookup */ ret = find_pte(env, ctx, 0, rw, type, target_page_bits); if (ret < 0) { /* Secondary table lookup */ if (eaddr != 0xEFFFFFFF) - LOG_MMU("1 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " " - "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx - " pg_addr=" TARGET_FMT_plx "\n", sdr, vsid, - pgidx, hash, ctx->pg_addr[1]); + LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx " pg_addr=" + TARGET_FMT_plx "\n", env->htab_base, + env->htab_mask, vsid, pgidx, hash, + ctx->pg_addr[1]); ret2 = find_pte(env, ctx, 1, rw, type, target_page_bits); if (ret2 != -1) @@ -1919,11 +1914,26 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value) void ppc_store_sdr1 (CPUPPCState *env, target_ulong value) { LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); - if (env->sdr1 != value) { - /* XXX: for PowerPC 64, should check that the HTABSIZE value - * is <= 28 - */ - env->sdr1 = value; + if (env->spr[SPR_SDR1] != value) { + env->spr[SPR_SDR1] = value; +#if defined(TARGET_PPC64) + if (env->mmu_model & POWERPC_MMU_64) { + target_ulong htabsize = value & SDR_64_HTABSIZE; + + if (htabsize > 28) { + fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx + " stored in SDR1\n", htabsize); + htabsize = 28; + } + env->htab_mask = (1ULL << (htabsize + 18)) - 1; + env->htab_base = value & SDR_64_HTABORG; + } else +#endif /* defined(TARGET_PPC64) */ + { + /* FIXME: Should check for valid HTABMASK values */ + env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF; + env->htab_base = value & SDR_32_HTABORG; + } tlb_flush(env, 1); } } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 0e2e67b34d..2cfb24bb1d 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -169,7 +169,7 @@ int kvm_arch_get_registers(CPUState *env) #ifdef KVM_CAP_PPC_SEGSTATE if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_SEGSTATE)) { - env->sdr1 = sregs.u.s.sdr1; + ppc_store_sdr1(env, sregs.u.s.sdr1); /* Sync SLB */ #ifdef TARGET_PPC64 diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 67de951959..0c1986e528 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->asr); qemu_put_sbe32s(f, &env->slb_nr); #endif - qemu_put_betls(f, &env->sdr1); + qemu_put_betls(f, &env->spr[SPR_SDR1]); for (i = 0; i < 32; i++) qemu_put_betls(f, &env->sr[i]); for (i = 0; i < 2; i++) @@ -93,6 +93,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) { CPUState *env = (CPUState *)opaque; unsigned int i, j; + target_ulong sdr1; for (i = 0; i < 32; i++) qemu_get_betls(f, &env->gpr[i]); @@ -124,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->asr); qemu_get_sbe32s(f, &env->slb_nr); #endif - qemu_get_betls(f, &env->sdr1); + qemu_get_betls(f, &sdr1); for (i = 0; i < 32; i++) qemu_get_betls(f, &env->sr[i]); for (i = 0; i < 2; i++) @@ -152,6 +153,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #endif for (i = 0; i < 1024; i++) qemu_get_betls(f, &env->spr[i]); + ppc_store_sdr1(env, sdr1); qemu_get_be32s(f, &env->vscr); qemu_get_be64s(f, &env->spe_acc); qemu_get_be32s(f, &env->spe_fscr); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 88681359c7..090795b600 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9126,7 +9126,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, #if !defined(CONFIG_USER_ONLY) cpu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1], - env->sdr1); + env->spr[SPR_SDR1]); #endif #undef RGPL diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index bca85d5073..63664248a4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -343,11 +343,6 @@ static void spr_write_dbatl_h (void *opaque, int sprn, int gprn) } /* SDR1 */ -static void spr_read_sdr1 (void *opaque, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, sdr1)); -} - static void spr_write_sdr1 (void *opaque, int sprn, int gprn) { gen_helper_store_sdr1(cpu_gpr[gprn]); @@ -671,7 +666,7 @@ static void gen_spr_ne_601 (CPUPPCState *env) /* Memory management */ spr_register(env, SPR_SDR1, "SDR1", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_sdr1, &spr_write_sdr1, + &spr_read_generic, &spr_write_sdr1, 0x00000000); } From fda6a0ecc61926ea1af6a85ab47a4ae47a6fe0a7 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:16 +1100 Subject: [PATCH 014/386] Use "hash" more consistently in ppc mmu code Currently, get_segment() has a variable called hash. However it doesn't (quite) get the hash value for the ppc hashed page table. Instead it gets the hash shifted - effectively the offset of the hash bucket within the hash page table. As well, as being different to the normal use of plain "hash" in the architecture documentation, this usage necessitates some awkward 32/64 dependent masks and shifts which clutter up the path in get_segment(). This patch alters the code to use raw hash values through get_segment() including storing raw hashes instead of pte group offsets in the ctx structure. This cleans up the path noticeably. This does necessitate 32/64 dependent shifts when the hash values are taken out of the ctx structure and used, but those paths already have 32/64 bit variants so this is less awkward than it was in get_segment(). Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 5 ++- target-ppc/helper.c | 97 ++++++++++++++++++++++----------------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ead4566f4f..cee1057aeb 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -367,6 +367,9 @@ union ppc_tlb_t { #define SDR_64_HTABSIZE 0x000000000000001FULL #endif /* defined(TARGET_PPC64 */ +#define HASH_PTE_SIZE_32 8 +#define HASH_PTE_SIZE_64 16 + typedef struct ppc_slb_t ppc_slb_t; struct ppc_slb_t { uint64_t esid; @@ -744,7 +747,7 @@ struct mmu_ctx_t { target_phys_addr_t raddr; /* Real address */ target_phys_addr_t eaddr; /* Effective address */ int prot; /* Protection bits */ - target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ + target_phys_addr_t hash[2]; /* Pagetable hash values */ target_ulong ptem; /* Virtual segment ID | API */ int key; /* Access key */ int nx; /* Non-execute area */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 68d2d9c0e2..0efa2a8c3a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -567,21 +567,30 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual, return ret; } -/* PTE table lookup */ -static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw, - int type, int target_page_bits) +static inline target_phys_addr_t get_pteg_offset(CPUState *env, + target_phys_addr_t hash, + int pte_size) { - target_ulong base, pte0, pte1; + return (hash * pte_size * 8) & env->htab_mask; +} + +/* PTE table lookup */ +static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, + int rw, int type, int target_page_bits) +{ + target_phys_addr_t pteg_off; + target_ulong pte0, pte1; int i, good = -1; int ret, r; ret = -1; /* No entry found */ - base = ctx->pg_addr[h]; + pteg_off = get_pteg_offset(env, ctx->hash[h], + is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); for (i = 0; i < 8; i++) { #if defined(TARGET_PPC64) if (is_64b) { - pte0 = ldq_phys(base + (i * 16)); - pte1 = ldq_phys(base + (i * 16) + 8); + pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); + pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); /* We have a TLB that saves 4K pages, so let's * split a huge page to 4k chunks */ @@ -592,17 +601,17 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw, r = pte64_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - base + (i * 16), pte0, pte1, (int)(pte0 & 1), h, + pteg_base + (i * 16), pte0, pte1, (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1), ctx->ptem); } else #endif { - pte0 = ldl_phys(base + (i * 8)); - pte1 = ldl_phys(base + (i * 8) + 4); + pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); + pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); r = pte32_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, + pteg_base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); } switch (r) { @@ -638,11 +647,13 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw, if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { #if defined(TARGET_PPC64) if (is_64b) { - stq_phys_notdirty(base + (good * 16) + 8, pte1); + stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8, + pte1); } else #endif { - stl_phys_notdirty(base + (good * 8) + 4, pte1); + stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4, + pte1); } } } @@ -650,17 +661,17 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw, return ret; } -static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type, - int target_page_bits) +static inline int find_pte32(CPUState *env, mmu_ctx_t *ctx, int h, int rw, + int type, int target_page_bits) { - return _find_pte(ctx, 0, h, rw, type, target_page_bits); + return _find_pte(env, ctx, 0, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) -static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type, - int target_page_bits) +static inline int find_pte64(CPUState *env, mmu_ctx_t *ctx, int h, int rw, + int type, int target_page_bits) { - return _find_pte(ctx, 1, h, rw, type, target_page_bits); + return _find_pte(env, ctx, 1, h, rw, type, target_page_bits); } #endif @@ -669,10 +680,10 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw, { #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) - return find_pte64(ctx, h, rw, type, target_page_bits); + return find_pte64(env, ctx, h, rw, type, target_page_bits); #endif - return find_pte32(ctx, h, rw, type, target_page_bits); + return find_pte32(env, ctx, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) @@ -788,19 +799,12 @@ int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt) #endif /* defined(TARGET_PPC64) */ /* Perform segment based translation */ -static inline target_phys_addr_t get_pgaddr(target_phys_addr_t htab_base, - target_phys_addr_t htab_mask, - target_phys_addr_t hash) -{ - return htab_base | (hash & htab_mask); -} - static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type) { target_phys_addr_t hash; - target_ulong sr, vsid, vsid_mask, pgidx, page_mask; - int ds, vsid_sh, pr, target_page_bits; + target_ulong sr, vsid, pgidx, page_mask; + int ds, pr, target_page_bits; int ret, ret2; pr = msr_pr; @@ -823,8 +827,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ds = 0; ctx->nx = !!(slb->vsid & SLB_VSID_N); ctx->eaddr = eaddr; - vsid_mask = 0x00003FFFFFFFFF80ULL; - vsid_sh = 7; } else #endif /* defined(TARGET_PPC64) */ { @@ -835,8 +837,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; - vsid_mask = 0x01FFFFC0; - vsid_sh = 6; target_page_bits = TARGET_PAGE_BITS; LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx @@ -851,27 +851,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ - /* Primary table address */ pgidx = (eaddr & page_mask) >> target_page_bits; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* XXX: this is false for 1 TB segments */ - hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; + hash = vsid ^ pgidx; } else #endif { - hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; + hash = vsid ^ pgidx; } LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx " hash " TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, hash); - ctx->pg_addr[0] = get_pgaddr(env->htab_base, env->htab_mask, hash); - /* Secondary table address */ - hash = (~hash) & vsid_mask; - LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx - " hash " TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, hash); - ctx->pg_addr[1] = get_pgaddr(env->htab_base, env->htab_mask, hash); + ctx->hash[0] = hash; + ctx->hash[1] = ~hash; + #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ @@ -895,9 +890,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, } else { LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx - " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, vsid, pgidx, hash, - ctx->pg_addr[0]); + " hash=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, pgidx, + ctx->hash[0]); /* Primary table lookup */ ret = find_pte(env, ctx, 0, rw, type, target_page_bits); if (ret < 0) { @@ -908,7 +903,7 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, pgidx, hash, - ctx->pg_addr[1]); + ctx->hash[1]); ret2 = find_pte(env, ctx, 1, rw, type, target_page_bits); if (ret2 != -1) @@ -1460,8 +1455,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; tlb_miss: env->error_code |= ctx.key << 19; - env->spr[SPR_HASH1] = ctx.pg_addr[0]; - env->spr[SPR_HASH2] = ctx.pg_addr[1]; + env->spr[SPR_HASH1] = env->htab_base + + get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); + env->spr[SPR_HASH2] = env->htab_base + + get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); break; case POWERPC_MMU_SOFT_74xx: if (rw == 1) { From 256cebe5d17477cd1443f47a9bd5ca35ca0dbc9c Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:17 +1100 Subject: [PATCH 015/386] Better factor the ppc hash translation path Currently the path handling hash page table translation in get_segment() has a mix of common and 32 or 64 bit specific code. However the division is not done terribly well which results in a lot of messy code flipping between common and divided paths. This patch improves the organization, consolidating several divided paths into one. This in turn allows simplification of some code in get_segment(), removing a number of ugly interim variables. This new factorization will also make it easier to add support for the 1T segments added in newer CPUs. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 1 + target-ppc/helper.c | 67 +++++++++++++-------------------------------- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index cee1057aeb..fd2dfcd92c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -386,6 +386,7 @@ struct ppc_slb_t { #define SLB_VSID_B 0xc000000000000000ULL #define SLB_VSID_B_256M 0x0000000000000000ULL #define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL +#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID) #define SLB_VSID_KS 0x0000000000000800ULL #define SLB_VSID_KP 0x0000000000000400ULL #define SLB_VSID_N 0x0000000000000200ULL /* no-execute */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 0efa2a8c3a..ae8001cd35 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -661,29 +661,15 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, return ret; } -static inline int find_pte32(CPUState *env, mmu_ctx_t *ctx, int h, int rw, - int type, int target_page_bits) -{ - return _find_pte(env, ctx, 0, h, rw, type, target_page_bits); -} - -#if defined(TARGET_PPC64) -static inline int find_pte64(CPUState *env, mmu_ctx_t *ctx, int h, int rw, - int type, int target_page_bits) -{ - return _find_pte(env, ctx, 1, h, rw, type, target_page_bits); -} -#endif - static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw, int type, int target_page_bits) { #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) - return find_pte64(env, ctx, h, rw, type, target_page_bits); + return _find_pte(env, ctx, 1, h, rw, type, target_page_bits); #endif - return find_pte32(env, ctx, h, rw, type, target_page_bits); + return _find_pte(env, ctx, 0, h, rw, type, target_page_bits); } #if defined(TARGET_PPC64) @@ -803,14 +789,16 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type) { target_phys_addr_t hash; - target_ulong sr, vsid, pgidx, page_mask; + target_ulong vsid; int ds, pr, target_page_bits; int ret, ret2; pr = msr_pr; + ctx->eaddr = eaddr; #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { ppc_slb_t *slb; + target_ulong pageaddr; LOG_MMU("Check SLBs\n"); slb = slb_lookup(env, eaddr); @@ -819,19 +807,24 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, } vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; - page_mask = ~SEGMENT_MASK_256M; target_page_bits = (slb->vsid & SLB_VSID_L) ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) : (slb->vsid & SLB_VSID_KS)); ds = 0; ctx->nx = !!(slb->vsid & SLB_VSID_N); - ctx->eaddr = eaddr; + + pageaddr = eaddr & ((1ULL << 28) - (1ULL << target_page_bits)); + /* XXX: this is false for 1 TB segments */ + hash = vsid ^ (pageaddr >> target_page_bits); + /* Only 5 bits of the page index are used in the AVPN */ + ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | ((pageaddr >> 16) & 0x0F80); } else #endif /* defined(TARGET_PPC64) */ { + target_ulong sr, pgidx; + sr = env->sr[eaddr >> 28]; - page_mask = 0x0FFFFFFF; ctx->key = (((sr & 0x20000000) && (pr != 0)) || ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; @@ -843,6 +836,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, rw, type); + pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits; + hash = vsid ^ pgidx; + ctx->ptem = (vsid << 7) | (pgidx >> 10); } LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid); @@ -851,36 +847,12 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ - pgidx = (eaddr & page_mask) >> target_page_bits; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - /* XXX: this is false for 1 TB segments */ - hash = vsid ^ pgidx; - } else -#endif - { - hash = vsid ^ pgidx; - } LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx " hash " TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, hash); ctx->hash[0] = hash; ctx->hash[1] = ~hash; -#if defined(TARGET_PPC64) - if (env->mmu_model & POWERPC_MMU_64) { - /* Only 5 bits of the page index are used in the AVPN */ - if (target_page_bits > 23) { - ctx->ptem = (vsid << 12) | - ((pgidx << (target_page_bits - 16)) & 0xF80); - } else { - ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); - } - } else -#endif - { - ctx->ptem = (vsid << 7) | (pgidx >> 10); - } /* Initialize real address with an invalid value */ ctx->raddr = (target_phys_addr_t)-1ULL; if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || @@ -889,9 +861,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); } else { LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx - " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx " hash=" TARGET_FMT_plx "\n", - env->htab_base, env->htab_mask, vsid, pgidx, + env->htab_base, env->htab_mask, vsid, ctx->ptem, ctx->hash[0]); /* Primary table lookup */ ret = find_pte(env, ctx, 0, rw, type, target_page_bits); @@ -902,8 +874,7 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n", env->htab_base, - env->htab_mask, vsid, pgidx, hash, - ctx->hash[1]); + env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); ret2 = find_pte(env, ctx, 1, rw, type, target_page_bits); if (ret2 != -1) From cdaee00633cfac7338d8dd0ba3e8766d5bdb1cec Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:18 +1100 Subject: [PATCH 016/386] Support 1T segments on ppc Traditionally, the "segments" used for the two-stage translation used on powerpc MMUs were 256MB in size. This was the only option on all hash page table based 32-bit powerpc cpus, and on the earlier 64-bit hash page table based cpus. However, newer 64-bit cpus also permit 1TB segments This patch adds support for 1TB segment translation to the qemu code. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/cpu.h | 7 +++++++ target-ppc/helper.c | 50 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index fd2dfcd92c..10341b307f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -114,6 +114,7 @@ enum powerpc_mmu_t { POWERPC_MMU_601 = 0x0000000A, #if defined(TARGET_PPC64) #define POWERPC_MMU_64 0x00010000 +#define POWERPC_MMU_1TSEG 0x00020000 /* 64 bits PowerPC MMU */ POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, /* 620 variant (no segment exceptions) */ @@ -382,9 +383,11 @@ struct ppc_slb_t { /* Bits in the SLB VSID word */ #define SLB_VSID_SHIFT 12 +#define SLB_VSID_SHIFT_1T 24 #define SLB_VSID_SSIZE_SHIFT 62 #define SLB_VSID_B 0xc000000000000000ULL #define SLB_VSID_B_256M 0x0000000000000000ULL +#define SLB_VSID_B_1T 0x4000000000000000ULL #define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL #define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID) #define SLB_VSID_KS 0x0000000000000800ULL @@ -398,6 +401,10 @@ struct ppc_slb_t { #define SEGMENT_SHIFT_256M 28 #define SEGMENT_MASK_256M (~((1ULL << SEGMENT_SHIFT_256M) - 1)) +#define SEGMENT_SHIFT_1T 40 +#define SEGMENT_MASK_1T (~((1ULL << SEGMENT_SHIFT_1T) - 1)) + + /*****************************************************************************/ /* Machine state register bits definition */ #define MSR_SF 63 /* Sixty-four-bit mode hflags */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index ae8001cd35..6712fce8ac 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -675,19 +675,26 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw, #if defined(TARGET_PPC64) static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) { - uint64_t esid; + uint64_t esid_256M, esid_1T; int n; LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); - esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; + esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; + esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V; for (n = 0; n < env->slb_nr; n++) { ppc_slb_t *slb = &env->slb[n]; LOG_SLB("%s: slot %d %016" PRIx64 " %016" PRIx64 "\n", __func__, n, slb->esid, slb->vsid); - if (slb->esid == esid) { + /* We check for 1T matches on all MMUs here - if the MMU + * doesn't have 1T segment support, we will have prevented 1T + * entries from being inserted in the slbmte code. */ + if (((slb->esid == esid_256M) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M)) + || ((slb->esid == esid_1T) && + ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) { return slb; } } @@ -740,14 +747,20 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) { int slot = rb & 0xfff; - uint64_t esid = rb & ~0xfff; ppc_slb_t *slb = &env->slb[slot]; - if (slot >= env->slb_nr) { - return -1; + if (rb & (0x1000 - env->slb_nr)) { + return -1; /* Reserved bits set or slot too high */ + } + if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) { + return -1; /* Bad segment size */ + } + if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) { + return -1; /* 1T segment on MMU that doesn't support it */ } - slb->esid = esid; + /* Mask out the slot number as we store the entry */ + slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V); slb->vsid = rs; LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 @@ -799,6 +812,7 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, if (env->mmu_model & POWERPC_MMU_64) { ppc_slb_t *slb; target_ulong pageaddr; + int segment_bits; LOG_MMU("Check SLBs\n"); slb = slb_lookup(env, eaddr); @@ -806,7 +820,14 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, return -5; } - vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + if (slb->vsid & SLB_VSID_B) { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; + segment_bits = 40; + } else { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + segment_bits = 28; + } + target_page_bits = (slb->vsid & SLB_VSID_L) ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) @@ -814,11 +835,16 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ds = 0; ctx->nx = !!(slb->vsid & SLB_VSID_N); - pageaddr = eaddr & ((1ULL << 28) - (1ULL << target_page_bits)); - /* XXX: this is false for 1 TB segments */ - hash = vsid ^ (pageaddr >> target_page_bits); + pageaddr = eaddr & ((1ULL << segment_bits) + - (1ULL << target_page_bits)); + if (slb->vsid & SLB_VSID_B) { + hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits); + } else { + hash = vsid ^ (pageaddr >> target_page_bits); + } /* Only 5 bits of the page index are used in the AVPN */ - ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | ((pageaddr >> 16) & 0x0F80); + ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | + ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80)); } else #endif /* defined(TARGET_PPC64) */ { From 9d52e9079da4f28abd788faf39e64fbf4b305561 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:19 +1100 Subject: [PATCH 017/386] Add POWER7 support for ppc This adds emulation support for the recent POWER7 cpu to qemu. It's far from perfect - it's missing a number of POWER7 features so far, including any support for VSX or decimal floating point instructions. However, it's close enough to boot a kernel with the POWER7 PVR. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/ppc.c | 35 ++++++++++++ hw/ppc.h | 1 + target-ppc/cpu.h | 16 ++++++ target-ppc/helper.c | 6 ++ target-ppc/translate_init.c | 107 ++++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+) diff --git a/hw/ppc.c b/hw/ppc.c index b55a84883e..dabb816510 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -247,6 +247,41 @@ void ppc970_irq_init (CPUState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, PPC970_INPUT_NB); } + +/* POWER7 internal IRQ controller */ +static void power7_set_irq (void *opaque, int pin, int level) +{ + CPUState *env = opaque; + int cur_level; + + LOG_IRQ("%s: env %p pin %d level %d\n", __func__, + env, pin, level); + cur_level = (env->irq_input_state >> pin) & 1; + + switch (pin) { + case POWER7_INPUT_INT: + /* Level sensitive - active high */ + LOG_IRQ("%s: set the external IRQ state to %d\n", + __func__, level); + ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + break; + default: + /* Unknown pin - do nothing */ + LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin); + return; + } + if (level) { + env->irq_input_state |= 1 << pin; + } else { + env->irq_input_state &= ~(1 << pin); + } +} + +void ppcPOWER7_irq_init (CPUState *env) +{ + env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env, + POWER7_INPUT_NB); +} #endif /* defined(TARGET_PPC64) */ /* PowerPC 40x internal IRQ controller */ diff --git a/hw/ppc.h b/hw/ppc.h index 34f54cf5da..3ccf13479b 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -36,6 +36,7 @@ void ppc40x_irq_init (CPUState *env); void ppce500_irq_init (CPUState *env); void ppc6xx_irq_init (CPUState *env); void ppc970_irq_init (CPUState *env); +void ppcPOWER7_irq_init (CPUState *env); /* PPC machines for OpenBIOS */ enum { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 10341b307f..25d0658c47 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -119,6 +119,8 @@ enum powerpc_mmu_t { POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, /* 620 variant (no segment exceptions) */ POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, + /* Architecture 2.06 variant */ + POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003, #endif /* defined(TARGET_PPC64) */ }; @@ -154,6 +156,8 @@ enum powerpc_excp_t { #if defined(TARGET_PPC64) /* PowerPC 970 exception model */ POWERPC_EXCP_970, + /* POWER7 exception model */ + POWERPC_EXCP_POWER7, #endif /* defined(TARGET_PPC64) */ }; @@ -289,6 +293,8 @@ enum powerpc_input_t { PPC_FLAGS_INPUT_405, /* PowerPC 970 bus */ PPC_FLAGS_INPUT_970, + /* PowerPC POWER7 bus */ + PPC_FLAGS_INPUT_POWER7, /* PowerPC 401 bus */ PPC_FLAGS_INPUT_401, /* Freescale RCPU bus */ @@ -1001,6 +1007,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #define SPR_HSPRG1 (0x131) #define SPR_HDSISR (0x132) #define SPR_HDAR (0x133) +#define SPR_SPURR (0x134) #define SPR_BOOKE_DBCR0 (0x134) #define SPR_IBCR (0x135) #define SPR_PURR (0x135) @@ -1625,6 +1632,15 @@ enum { PPC970_INPUT_THINT = 6, PPC970_INPUT_NB, }; + +enum { + /* POWER7 input pins */ + POWER7_INPUT_INT = 0, + /* POWER7 probably has other inputs, but we don't care about them + * for any existing machine. We can wire these up when we need + * them */ + POWER7_INPUT_NB, +}; #endif /* Hardware exceptions definitions */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6712fce8ac..278bee4f17 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1200,6 +1200,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; ctx->prot |= PAGE_WRITE; @@ -1277,6 +1278,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ @@ -1376,6 +1378,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; @@ -1485,6 +1488,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; @@ -1808,6 +1812,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); break; @@ -1875,6 +1880,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 63664248a4..e2a83c5a38 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -61,6 +61,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); PPC_IRQ_INIT_FN(40x); PPC_IRQ_INIT_FN(6xx); PPC_IRQ_INIT_FN(970); +PPC_IRQ_INIT_FN(POWER7); PPC_IRQ_INIT_FN(e500); /* Generic callbacks: @@ -3131,6 +3132,35 @@ static void init_excp_970 (CPUPPCState *env) env->hreset_vector = 0x0000000000000100ULL; #endif } + +static void init_excp_POWER7 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; + env->hreset_excp_prefix = 0; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif +} #endif /*****************************************************************************/ @@ -6312,6 +6342,78 @@ static void init_proc_970MP (CPUPPCState *env) vscr_init(env, 0x00010000); } +#if defined(TARGET_PPC64) +/* POWER7 */ +#define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_SEGMENT_64B | PPC_SLBI | \ + PPC_POPCNTB | PPC_POPCNTWD) +#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) +#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) +#define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) +#define POWERPC_INPUT_POWER7 (PPC_FLAGS_INPUT_POWER7) +#define POWERPC_BFDM_POWER7 (bfd_mach_ppc64) +#define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) +#define check_pow_POWER7 check_pow_nocheck + +static void init_proc_POWER7 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); +#if !defined(CONFIG_USER_ONLY) + /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ + spr_register(env, SPR_PURR, "PURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPURR, "SPURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + 0x00000000); +#endif /* !CONFIG_USER_ONLY */ + /* Memory management */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_CTRL, "SPR_CTRLT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x80800000); + spr_register(env, SPR_UCTRL, "SPR_CTRLF", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x80800000); + spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#if !defined(CONFIG_USER_ONLY) + env->slb_nr = 32; +#endif + init_excp_POWER7(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; + /* Allocate hardware IRQ controller */ + ppcPOWER7_irq_init(env); + /* Can't find information on what this should be on reset. This + * value is the one used by 74xx processors. */ + vscr_init(env, 0x00010000); +} +#endif /* TARGET_PPC64 */ + /* PowerPC 620 */ #define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -7034,6 +7136,8 @@ enum { CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, +#define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 + CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_970 = 0x00390202, #define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, @@ -8836,6 +8940,9 @@ static const ppc_def_t ppc_defs[] = { /* POWER6A */ POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), #endif + /* POWER7 */ + POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), + POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ From 9fdf0c2995d04a74a22ea4609b2931eef209e53d Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:20 +1100 Subject: [PATCH 018/386] Start implementing pSeries logical partition machine This patch adds a "pseries" machine to qemu. This aims to emulate a logical partition on an IBM pSeries machine, compliant to the "PowerPC Architecture Platform Requirements" (PAPR) document. This initial version is quite limited, it implements a basic machine and PAPR hypercall emulation. So far only one hypercall is present - H_PUT_TERM_CHAR - so that a (write-only) console is available. Multiple CPUs are permitted, with SMP entry handled kexec() style. The machine so far more resembles an old POWER4 style "full system partition" rather than a modern LPAR, in that the guest manages the page tables directly, rather than via hypercalls. The machine requires qemu to be configured with --enable-fdt. The machine can (so far) only be booted with -kernel - i.e. no partition firmware is provided. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile.target | 4 + hw/spapr.c | 313 +++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr.h | 257 ++++++++++++++++++++++++++++++++++++++ hw/spapr_hcall.c | 41 +++++++ 4 files changed, 615 insertions(+) create mode 100644 hw/spapr.c create mode 100644 hw/spapr.h create mode 100644 hw/spapr_hcall.c diff --git a/Makefile.target b/Makefile.target index 62b102a7f8..ccf090ba4f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -231,6 +231,10 @@ obj-ppc-y += ppc_prep.o obj-ppc-y += ppc_oldworld.o # NewWorld PowerMac obj-ppc-y += ppc_newworld.o +# IBM pSeries (sPAPR)i +ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) +obj-ppc-y += spapr.o spapr_hcall.o +endif # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o diff --git a/hw/spapr.c b/hw/spapr.c new file mode 100644 index 0000000000..410213afc8 --- /dev/null +++ b/hw/spapr.c @@ -0,0 +1,313 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2010 David Gibson, IBM Corporation. + * + * 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 "sysemu.h" +#include "qemu-char.h" +#include "hw.h" +#include "elf.h" + +#include "hw/boards.h" +#include "hw/ppc.h" +#include "hw/loader.h" + +#include "hw/spapr.h" + +#include <libfdt.h> + +#define KERNEL_LOAD_ADDR 0x00000000 +#define INITRD_LOAD_ADDR 0x02800000 +#define FDT_MAX_SIZE 0x10000 + +#define TIMEBASE_FREQ 512000000ULL + +#define MAX_CPUS 32 + +sPAPREnvironment *spapr; + +static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, + const char *cpu_model, CPUState *envs[], + sPAPREnvironment *spapr, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) +{ + void *fdt; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; + uint32_t start_prop = cpu_to_be32(initrd_base); + uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); + int i; + char *modelname; + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + fdt = qemu_mallocz(FDT_MAX_SIZE); + _FDT((fdt_create(fdt, FDT_MAX_SIZE))); + + _FDT((fdt_finish_reservemap(fdt))); + + /* Root node */ + _FDT((fdt_begin_node(fdt, ""))); + _FDT((fdt_property_string(fdt, "device_type", "chrp"))); + _FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR"))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); + + /* /chosen */ + _FDT((fdt_begin_node(fdt, "chosen"))); + + _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); + _FDT((fdt_property(fdt, "linux,initrd-start", + &start_prop, sizeof(start_prop)))); + _FDT((fdt_property(fdt, "linux,initrd-end", + &end_prop, sizeof(end_prop)))); + + _FDT((fdt_end_node(fdt))); + + /* memory node */ + _FDT((fdt_begin_node(fdt, "memory@0"))); + + _FDT((fdt_property_string(fdt, "device_type", "memory"))); + _FDT((fdt_property(fdt, "reg", + mem_reg_property, sizeof(mem_reg_property)))); + + _FDT((fdt_end_node(fdt))); + + /* cpus */ + _FDT((fdt_begin_node(fdt, "cpus"))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + + modelname = qemu_strdup(cpu_model); + + for (i = 0; i < strlen(modelname); i++) { + modelname[i] = toupper(modelname[i]); + } + + for (i = 0; i < smp_cpus; i++) { + CPUState *env = envs[i]; + char *nodename; + uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), + 0xffffffff, 0xffffffff}; + + if (asprintf(&nodename, "%s@%x", modelname, i) < 0) { + fprintf(stderr, "Allocation failure\n"); + exit(1); + } + + _FDT((fdt_begin_node(fdt, nodename))); + + free(nodename); + + _FDT((fdt_property_cell(fdt, "reg", i))); + _FDT((fdt_property_string(fdt, "device_type", "cpu"))); + + _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); + _FDT((fdt_property_cell(fdt, "dcache-block-size", + env->dcache_line_size))); + _FDT((fdt_property_cell(fdt, "icache-block-size", + env->icache_line_size))); + _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ))); + /* Hardcode CPU frequency for now. It's kind of arbitrary on + * full emu, for kvm we should copy it from the host */ + _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000))); + _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); + _FDT((fdt_property_string(fdt, "status", "okay"))); + _FDT((fdt_property(fdt, "64-bit", NULL, 0))); + + if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) { + _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", + segs, sizeof(segs)))); + } + + _FDT((fdt_end_node(fdt))); + } + + qemu_free(modelname); + + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_end_node(fdt))); /* close root node */ + _FDT((fdt_finish(fdt))); + + *fdt_size = fdt_totalsize(fdt); + + return fdt; +} + +static uint64_t translate_kernel_address(void *opaque, uint64_t addr) +{ + return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; +} + +static void emulate_spapr_hypercall(CPUState *env) +{ + env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); +} + +/* FIXME: hack until we implement the proper VIO console */ +static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + uint8_t buf[16]; + + stq_p(buf, args[2]); + stq_p(buf + 8, args[3]); + + qemu_chr_write(serial_hds[0], buf, args[1]); + + return 0; +} + + +/* pSeries LPAR / sPAPR hardware init */ +static void ppc_spapr_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + CPUState *envs[MAX_CPUS]; + void *fdt; + int i; + ram_addr_t ram_offset; + target_phys_addr_t fdt_addr; + uint32_t kernel_base, initrd_base; + long kernel_size, initrd_size; + int fdt_size; + + spapr = qemu_malloc(sizeof(*spapr)); + cpu_ppc_hypercall = emulate_spapr_hypercall; + + /* We place the device tree just below either the top of RAM, or + * 2GB, so that it can be processed with 32-bit code if + * necessary */ + fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "POWER7"; + } + for (i = 0; i < smp_cpus; i++) { + CPUState *env = cpu_init(cpu_model); + + if (!env) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, TIMEBASE_FREQ); + qemu_register_reset((QEMUResetHandler *)&cpu_reset, env); + + env->hreset_vector = 0x60; + env->hreset_excp_prefix = 0; + env->gpr[3] = i; + + envs[i] = env; + } + + /* allocate RAM */ + ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size); + cpu_register_physical_memory(0, ram_size, ram_offset); + + spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); + + if (kernel_filename) { + uint64_t lowaddr = 0; + + kernel_base = KERNEL_LOAD_ADDR; + + kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, + NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, kernel_base, + ram_size - kernel_base); + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + ram_size - initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + + } else { + fprintf(stderr, "pSeries machine needs -kernel for now"); + exit(1); + } + + /* Prepare the device tree */ + fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, + initrd_base, initrd_size, kernel_cmdline); + assert(fdt != NULL); + + cpu_physical_memory_write(fdt_addr, fdt, fdt_size); + + qemu_free(fdt); + + envs[0]->gpr[3] = fdt_addr; + envs[0]->gpr[5] = 0; + envs[0]->hreset_vector = kernel_base; +} + +static QEMUMachine spapr_machine = { + .name = "pseries", + .desc = "pSeries Logical Partition (PAPR compliant)", + .init = ppc_spapr_init, + .max_cpus = MAX_CPUS, + .no_vga = 1, + .no_parallel = 1, +}; + +static void spapr_machine_init(void) +{ + qemu_register_machine(&spapr_machine); +} + +machine_init(spapr_machine_init); diff --git a/hw/spapr.h b/hw/spapr.h new file mode 100644 index 0000000000..685944b0f4 --- /dev/null +++ b/hw/spapr.h @@ -0,0 +1,257 @@ +#if !defined(__HW_SPAPR_H__) +#define __HW_SPAPR_H__ + +typedef struct sPAPREnvironment { +} sPAPREnvironment; + +#define H_SUCCESS 0 +#define H_BUSY 1 /* Hardware busy -- retry later */ +#define H_CLOSED 2 /* Resource closed */ +#define H_NOT_AVAILABLE 3 +#define H_CONSTRAINED 4 /* Resource request constrained to max allowed */ +#define H_PARTIAL 5 +#define H_IN_PROGRESS 14 /* Kind of like busy */ +#define H_PAGE_REGISTERED 15 +#define H_PARTIAL_STORE 16 +#define H_PENDING 17 /* returned from H_POLL_PENDING */ +#define H_CONTINUE 18 /* Returned from H_Join on success */ +#define H_LONG_BUSY_START_RANGE 9900 /* Start of long busy range */ +#define H_LONG_BUSY_ORDER_1_MSEC 9900 /* Long busy, hint that 1msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_10_MSEC 9901 /* Long busy, hint that 10msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_100_MSEC 9902 /* Long busy, hint that 100msec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_1_SEC 9903 /* Long busy, hint that 1sec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_10_SEC 9904 /* Long busy, hint that 10sec \ + is a good time to retry */ +#define H_LONG_BUSY_ORDER_100_SEC 9905 /* Long busy, hint that 100sec \ + is a good time to retry */ +#define H_LONG_BUSY_END_RANGE 9905 /* End of long busy range */ +#define H_HARDWARE -1 /* Hardware error */ +#define H_FUNCTION -2 /* Function not supported */ +#define H_PRIVILEGE -3 /* Caller not privileged */ +#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting */ +#define H_BAD_MODE -5 /* Illegal msr value */ +#define H_PTEG_FULL -6 /* PTEG is full */ +#define H_NOT_FOUND -7 /* PTE was not found" */ +#define H_RESERVED_DABR -8 /* DABR address is reserved by the hypervisor on this processor" */ +#define H_NO_MEM -9 +#define H_AUTHORITY -10 +#define H_PERMISSION -11 +#define H_DROPPED -12 +#define H_SOURCE_PARM -13 +#define H_DEST_PARM -14 +#define H_REMOTE_PARM -15 +#define H_RESOURCE -16 +#define H_ADAPTER_PARM -17 +#define H_RH_PARM -18 +#define H_RCQ_PARM -19 +#define H_SCQ_PARM -20 +#define H_EQ_PARM -21 +#define H_RT_PARM -22 +#define H_ST_PARM -23 +#define H_SIGT_PARM -24 +#define H_TOKEN_PARM -25 +#define H_MLENGTH_PARM -27 +#define H_MEM_PARM -28 +#define H_MEM_ACCESS_PARM -29 +#define H_ATTR_PARM -30 +#define H_PORT_PARM -31 +#define H_MCG_PARM -32 +#define H_VL_PARM -33 +#define H_TSIZE_PARM -34 +#define H_TRACE_PARM -35 + +#define H_MASK_PARM -37 +#define H_MCG_FULL -38 +#define H_ALIAS_EXIST -39 +#define H_P_COUNTER -40 +#define H_TABLE_FULL -41 +#define H_ALT_TABLE -42 +#define H_MR_CONDITION -43 +#define H_NOT_ENOUGH_RESOURCES -44 +#define H_R_STATE -45 +#define H_RESCINDEND -46 +#define H_MULTI_THREADS_ACTIVE -9005 + + +/* Long Busy is a condition that can be returned by the firmware + * when a call cannot be completed now, but the identical call + * should be retried later. This prevents calls blocking in the + * firmware for long periods of time. Annoyingly the firmware can return + * a range of return codes, hinting at how long we should wait before + * retrying. If you don't care for the hint, the macro below is a good + * way to check for the long_busy return codes + */ +#define H_IS_LONG_BUSY(x) ((x >= H_LONG_BUSY_START_RANGE) \ + && (x <= H_LONG_BUSY_END_RANGE)) + +/* Flags */ +#define H_LARGE_PAGE (1ULL<<(63-16)) +#define H_EXACT (1ULL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */ +#define H_R_XLATE (1ULL<<(63-25)) /* include a valid logical page num in the pte if the valid bit is set */ +#define H_READ_4 (1ULL<<(63-26)) /* Return 4 PTEs */ +#define H_PAGE_STATE_CHANGE (1ULL<<(63-28)) +#define H_PAGE_UNUSED ((1ULL<<(63-29)) | (1ULL<<(63-30))) +#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED) +#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31))) +#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE +#define H_AVPN (1ULL<<(63-32)) /* An avpn is provided as a sanity test */ +#define H_ANDCOND (1ULL<<(63-33)) +#define H_ICACHE_INVALIDATE (1ULL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ +#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ +#define H_ZERO_PAGE (1ULL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ +#define H_COPY_PAGE (1ULL<<(63-49)) +#define H_N (1ULL<<(63-61)) +#define H_PP1 (1ULL<<(63-62)) +#define H_PP2 (1ULL<<(63-63)) + +/* VASI States */ +#define H_VASI_INVALID 0 +#define H_VASI_ENABLED 1 +#define H_VASI_ABORTED 2 +#define H_VASI_SUSPENDING 3 +#define H_VASI_SUSPENDED 4 +#define H_VASI_RESUMED 5 +#define H_VASI_COMPLETED 6 + +/* DABRX flags */ +#define H_DABRX_HYPERVISOR (1ULL<<(63-61)) +#define H_DABRX_KERNEL (1ULL<<(63-62)) +#define H_DABRX_USER (1ULL<<(63-63)) + +/* Each control block has to be on a 4K bondary */ +#define H_CB_ALIGNMENT 4096 + +/* pSeries hypervisor opcodes */ +#define H_REMOVE 0x04 +#define H_ENTER 0x08 +#define H_READ 0x0c +#define H_CLEAR_MOD 0x10 +#define H_CLEAR_REF 0x14 +#define H_PROTECT 0x18 +#define H_GET_TCE 0x1c +#define H_PUT_TCE 0x20 +#define H_SET_SPRG0 0x24 +#define H_SET_DABR 0x28 +#define H_PAGE_INIT 0x2c +#define H_SET_ASR 0x30 +#define H_ASR_ON 0x34 +#define H_ASR_OFF 0x38 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_LOGICAL_CACHE_LOAD 0x44 +#define H_LOGICAL_CACHE_STORE 0x48 +#define H_LOGICAL_ICBI 0x4c +#define H_LOGICAL_DCBF 0x50 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REAL_TO_LOGICAL 0x5c +#define H_HYPERVISOR_DATA 0x60 +#define H_EOI 0x64 +#define H_CPPR 0x68 +#define H_IPI 0x6c +#define H_IPOLL 0x70 +#define H_XIRR 0x74 +#define H_PERFMON 0x7c +#define H_MIGRATE_DMA 0x78 +#define H_REGISTER_VPA 0xDC +#define H_CEDE 0xE0 +#define H_CONFER 0xE4 +#define H_PROD 0xE8 +#define H_GET_PPP 0xEC +#define H_SET_PPP 0xF0 +#define H_PURR 0xF4 +#define H_PIC 0xF8 +#define H_REG_CRQ 0xFC +#define H_FREE_CRQ 0x100 +#define H_VIO_SIGNAL 0x104 +#define H_SEND_CRQ 0x108 +#define H_COPY_RDMA 0x110 +#define H_REGISTER_LOGICAL_LAN 0x114 +#define H_FREE_LOGICAL_LAN 0x118 +#define H_ADD_LOGICAL_LAN_BUFFER 0x11C +#define H_SEND_LOGICAL_LAN 0x120 +#define H_BULK_REMOVE 0x124 +#define H_MULTICAST_CTRL 0x130 +#define H_SET_XDABR 0x134 +#define H_STUFF_TCE 0x138 +#define H_PUT_TCE_INDIRECT 0x13C +#define H_CHANGE_LOGICAL_LAN_MAC 0x14C +#define H_VTERM_PARTNER_INFO 0x150 +#define H_REGISTER_VTERM 0x154 +#define H_FREE_VTERM 0x158 +#define H_RESET_EVENTS 0x15C +#define H_ALLOC_RESOURCE 0x160 +#define H_FREE_RESOURCE 0x164 +#define H_MODIFY_QP 0x168 +#define H_QUERY_QP 0x16C +#define H_REREGISTER_PMR 0x170 +#define H_REGISTER_SMR 0x174 +#define H_QUERY_MR 0x178 +#define H_QUERY_MW 0x17C +#define H_QUERY_HCA 0x180 +#define H_QUERY_PORT 0x184 +#define H_MODIFY_PORT 0x188 +#define H_DEFINE_AQP1 0x18C +#define H_GET_TRACE_BUFFER 0x190 +#define H_DEFINE_AQP0 0x194 +#define H_RESIZE_MR 0x198 +#define H_ATTACH_MCQP 0x19C +#define H_DETACH_MCQP 0x1A0 +#define H_CREATE_RPT 0x1A4 +#define H_REMOVE_RPT 0x1A8 +#define H_REGISTER_RPAGES 0x1AC +#define H_DISABLE_AND_GETC 0x1B0 +#define H_ERROR_DATA 0x1B4 +#define H_GET_HCA_INFO 0x1B8 +#define H_GET_PERF_COUNT 0x1BC +#define H_MANAGE_TRACE 0x1C0 +#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 +#define H_QUERY_INT_STATE 0x1E4 +#define H_POLL_PENDING 0x1D8 +#define H_ILLAN_ATTRIBUTES 0x244 +#define H_MODIFY_HEA_QP 0x250 +#define H_QUERY_HEA_QP 0x254 +#define H_QUERY_HEA 0x258 +#define H_QUERY_HEA_PORT 0x25C +#define H_MODIFY_HEA_PORT 0x260 +#define H_REG_BCMC 0x264 +#define H_DEREG_BCMC 0x268 +#define H_REGISTER_HEA_RPAGES 0x26C +#define H_DISABLE_AND_GET_HEA 0x270 +#define H_GET_HEA_INFO 0x274 +#define H_ALLOC_HEA_RESOURCE 0x278 +#define H_ADD_CONN 0x284 +#define H_DEL_CONN 0x288 +#define H_JOIN 0x298 +#define H_VASI_STATE 0x2A4 +#define H_ENABLE_CRQ 0x2B0 +#define H_GET_EM_PARMS 0x2B8 +#define H_SET_MPP 0x2D0 +#define H_GET_MPP 0x2D4 +#define MAX_HCALL_OPCODE H_GET_MPP + +extern sPAPREnvironment *spapr; + +/*#define DEBUG_SPAPR_HCALLS*/ + +#ifdef DEBUG_SPAPR_HCALLS +#define hcall_dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define hcall_dprintf(fmt, ...) \ + do { } while (0) +#endif + +typedef target_ulong (*spapr_hcall_fn)(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, + target_ulong *args); + +void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); +target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, + target_ulong *args); + +#endif /* !defined (__HW_SPAPR_H__) */ diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c new file mode 100644 index 0000000000..e3919d01c2 --- /dev/null +++ b/hw/spapr_hcall.c @@ -0,0 +1,41 @@ +#include "sysemu.h" +#include "cpu.h" +#include "qemu-char.h" +#include "hw/spapr.h" + +spapr_hcall_fn hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; + +void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) +{ + spapr_hcall_fn old_fn; + + assert(opcode <= MAX_HCALL_OPCODE); + assert((opcode & 0x3) == 0); + + old_fn = hypercall_table[opcode / 4]; + + assert(!old_fn || (fn == old_fn)); + + hypercall_table[opcode / 4] = fn; +} + +target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, + target_ulong *args) +{ + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + return H_PRIVILEGE; + } + + if ((opcode <= MAX_HCALL_OPCODE) + && ((opcode & 0x3) == 0)) { + spapr_hcall_fn fn = hypercall_table[opcode / 4]; + + if (fn) { + return fn(env, spapr, opcode, args); + } + } + + hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode); + return H_FUNCTION; +} From 4040ab72379f75fe171c03f93ceb75efb48c14a5 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:21 +1100 Subject: [PATCH 019/386] Implement the bus structure for PAPR virtual IO This extends the "pseries" (PAPR) machine to include a virtual IO bus supporting the PAPR defined hypercall based virtual IO mechanisms. So far only one VIO device is provided, the vty / vterm, providing a full console (polled only, for now). Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile.target | 5 +- hw/spapr.c | 48 +++++++---- hw/spapr.h | 3 + hw/spapr_vio.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 50 +++++++++++ hw/spapr_vty.c | 150 +++++++++++++++++++++++++++++++++ 6 files changed, 450 insertions(+), 20 deletions(-) create mode 100644 hw/spapr_vio.c create mode 100644 hw/spapr_vio.h create mode 100644 hw/spapr_vty.c diff --git a/Makefile.target b/Makefile.target index ccf090ba4f..cf12691670 100644 --- a/Makefile.target +++ b/Makefile.target @@ -231,9 +231,10 @@ obj-ppc-y += ppc_prep.o obj-ppc-y += ppc_oldworld.o # NewWorld PowerMac obj-ppc-y += ppc_newworld.o -# IBM pSeries (sPAPR)i +# IBM pSeries (sPAPR) ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) -obj-ppc-y += spapr.o spapr_hcall.o +obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o +obj-ppc-y += spapr_vty.o endif # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o diff --git a/hw/spapr.c b/hw/spapr.c index 410213afc8..c24c92b1a0 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -25,7 +25,6 @@ * */ #include "sysemu.h" -#include "qemu-char.h" #include "hw.h" #include "elf.h" @@ -34,6 +33,7 @@ #include "hw/loader.h" #include "hw/spapr.h" +#include "hw/spapr_vio.h" #include <libfdt.h> @@ -60,6 +60,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); int i; char *modelname; + int ret; #define _FDT(exp) \ do { \ @@ -159,9 +160,30 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_end_node(fdt))); + /* vdevice */ + _FDT((fdt_begin_node(fdt, "vdevice"))); + + _FDT((fdt_property_string(fdt, "device_type", "vdevice"))); + _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice"))); + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + + _FDT((fdt_end_node(fdt))); + _FDT((fdt_end_node(fdt))); /* close root node */ _FDT((fdt_finish(fdt))); + /* re-expand to allow for further tweaks */ + _FDT((fdt_open_into(fdt, fdt, FDT_MAX_SIZE))); + + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup vio devices in fdt\n"); + exit(1); + } + + _FDT((fdt_pack(fdt))); + *fdt_size = fdt_totalsize(fdt); return fdt; @@ -177,21 +199,6 @@ static void emulate_spapr_hypercall(CPUState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } -/* FIXME: hack until we implement the proper VIO console */ -static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - uint8_t buf[16]; - - stq_p(buf, args[2]); - stq_p(buf + 8, args[3]); - - qemu_chr_write(serial_hds[0], buf, args[1]); - - return 0; -} - - /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(ram_addr_t ram_size, const char *boot_device, @@ -243,7 +250,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_offset); - spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); + spapr->vio_bus = spapr_vio_bus_init(); + + for (i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + spapr_vty_create(spapr->vio_bus, i, serial_hds[i]); + } + } if (kernel_filename) { uint64_t lowaddr = 0; @@ -276,7 +289,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, initrd_base = 0; initrd_size = 0; } - } else { fprintf(stderr, "pSeries machine needs -kernel for now"); exit(1); diff --git a/hw/spapr.h b/hw/spapr.h index 685944b0f4..06cca15b94 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -1,7 +1,10 @@ #if !defined(__HW_SPAPR_H__) #define __HW_SPAPR_H__ +struct VIOsPAPRBus; + typedef struct sPAPREnvironment { + struct VIOsPAPRBus *vio_bus; } sPAPREnvironment; #define H_SUCCESS 0 diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c new file mode 100644 index 0000000000..10acb4c308 --- /dev/null +++ b/hw/spapr_vio.c @@ -0,0 +1,214 @@ +/* + * QEMU sPAPR VIO code + * + * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com> + * Based on the s390 virtio bus code: + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "sysemu.h" +#include "boards.h" +#include "monitor.h" +#include "loader.h" +#include "elf.h" +#include "hw/sysbus.h" +#include "kvm.h" +#include "device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#ifdef CONFIG_FDT +#include <libfdt.h> +#endif /* CONFIG_FDT */ + +/* #define DEBUG_SPAPR */ + +#ifdef DEBUG_SPAPR +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +static struct BusInfo spapr_vio_bus_info = { + .name = "spapr-vio", + .size = sizeof(VIOsPAPRBus), +}; + +VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) +{ + DeviceState *qdev; + VIOsPAPRDevice *dev = NULL; + + QLIST_FOREACH(qdev, &bus->bus.children, sibling) { + dev = (VIOsPAPRDevice *)qdev; + if (dev->reg == reg) { + break; + } + } + + return dev; +} + +#ifdef CONFIG_FDT +static int vio_make_devnode(VIOsPAPRDevice *dev, + void *fdt) +{ + VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + int vdevice_off, node_off; + int ret; + + vdevice_off = fdt_path_offset(fdt, "/vdevice"); + if (vdevice_off < 0) { + return vdevice_off; + } + + node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id); + if (node_off < 0) { + return node_off; + } + + ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); + if (ret < 0) { + return ret; + } + + if (info->dt_type) { + ret = fdt_setprop_string(fdt, node_off, "device_type", + info->dt_type); + if (ret < 0) { + return ret; + } + } + + if (info->dt_compatible) { + ret = fdt_setprop_string(fdt, node_off, "compatible", + info->dt_compatible); + if (ret < 0) { + return ret; + } + } + + if (info->devnode) { + ret = (info->devnode)(dev, fdt, node_off); + if (ret < 0) { + return ret; + } + } + + return node_off; +} +#endif /* CONFIG_FDT */ + +static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) +{ + VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + char *id; + + if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) { + return -1; + } + + dev->qdev.id = id; + + return info->init(dev); +} + +void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info) +{ + info->qdev.init = spapr_vio_busdev_init; + info->qdev.bus_info = &spapr_vio_bus_info; + + assert(info->qdev.size >= sizeof(VIOsPAPRDevice)); + qdev_register(&info->qdev); +} + +VIOsPAPRBus *spapr_vio_bus_init(void) +{ + VIOsPAPRBus *bus; + BusState *qbus; + DeviceState *dev; + DeviceInfo *qinfo; + + /* Create bridge device */ + dev = qdev_create(NULL, "spapr-vio-bridge"); + qdev_init_nofail(dev); + + /* Create bus on bridge device */ + + qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio"); + bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); + + for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { + VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; + + if (qinfo->bus_info != &spapr_vio_bus_info) { + continue; + } + + if (info->hcalls) { + info->hcalls(bus); + } + } + + return bus; +} + +/* Represents sPAPR hcall VIO devices */ + +static int spapr_vio_bridge_init(SysBusDevice *dev) +{ + /* nothing */ + return 0; +} + +static SysBusDeviceInfo spapr_vio_bridge_info = { + .init = spapr_vio_bridge_init, + .qdev.name = "spapr-vio-bridge", + .qdev.size = sizeof(SysBusDevice), + .qdev.no_user = 1, +}; + +static void spapr_vio_register_devices(void) +{ + sysbus_register_withprop(&spapr_vio_bridge_info); +} + +device_init(spapr_vio_register_devices) + +#ifdef CONFIG_FDT +int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) +{ + DeviceState *qdev; + int ret = 0; + + QLIST_FOREACH(qdev, &bus->bus.children, sibling) { + VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + + ret = vio_make_devnode(dev, fdt); + + if (ret < 0) { + return ret; + } + } + + return 0; +} +#endif /* CONFIG_FDT */ diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h new file mode 100644 index 0000000000..b164ad326c --- /dev/null +++ b/hw/spapr_vio.h @@ -0,0 +1,50 @@ +#ifndef _HW_SPAPR_VIO_H +#define _HW_SPAPR_VIO_H +/* + * QEMU sPAPR VIO bus definitions + * + * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au> + * Based on the s390 virtio bus definitions: + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +typedef struct VIOsPAPRDevice { + DeviceState qdev; + uint32_t reg; +} VIOsPAPRDevice; + +typedef struct VIOsPAPRBus { + BusState bus; +} VIOsPAPRBus; + +typedef struct { + DeviceInfo qdev; + const char *dt_name, *dt_type, *dt_compatible; + int (*init)(VIOsPAPRDevice *dev); + void (*hcalls)(VIOsPAPRBus *bus); + int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); +} VIOsPAPRDeviceInfo; + +extern VIOsPAPRBus *spapr_vio_bus_init(void); +extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); +extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); +extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); + +void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); +void spapr_vty_create(VIOsPAPRBus *bus, + uint32_t reg, CharDriverState *chardev); + +#endif /* _HW_SPAPR_VIO_H */ diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c new file mode 100644 index 0000000000..b4da6a83fb --- /dev/null +++ b/hw/spapr_vty.c @@ -0,0 +1,150 @@ +#include "qdev.h" +#include "qemu-char.h" +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#define VTERM_BUFSIZE 16 + +typedef struct VIOsPAPRVTYDevice { + VIOsPAPRDevice sdev; + CharDriverState *chardev; + uint32_t in, out; + uint8_t buf[VTERM_BUFSIZE]; +} VIOsPAPRVTYDevice; + +static int vty_can_receive(void *opaque) +{ + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; + + return (dev->in - dev->out) < VTERM_BUFSIZE; +} + +static void vty_receive(void *opaque, const uint8_t *buf, int size) +{ + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; + int i; + + for (i = 0; i < size; i++) { + assert((dev->in - dev->out) < VTERM_BUFSIZE); + dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i]; + } +} + +static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) +{ + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + int n = 0; + + while ((n < max) && (dev->out != dev->in)) { + buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; + } + + return n; +} + +void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) +{ + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + + /* FIXME: should check the qemu_chr_write() return value */ + qemu_chr_write(dev->chardev, buf, len); +} + +static int spapr_vty_init(VIOsPAPRDevice *sdev) +{ + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; + + qemu_chr_add_handlers(dev->chardev, vty_can_receive, + vty_receive, NULL, dev); + + return 0; +} + +static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong len = args[1]; + target_ulong char0_7 = args[2]; + target_ulong char8_15 = args[3]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + uint8_t buf[16]; + + if (!sdev) { + return H_PARAMETER; + } + + if (len > 16) { + return H_PARAMETER; + } + + *((uint64_t *)buf) = cpu_to_be64(char0_7); + *((uint64_t *)buf + 1) = cpu_to_be64(char8_15); + + vty_putchars(sdev, buf, len); + + return H_SUCCESS; +} + +static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong *len = args + 0; + target_ulong *char0_7 = args + 1; + target_ulong *char8_15 = args + 2; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + uint8_t buf[16]; + + if (!sdev) { + return H_PARAMETER; + } + + *len = vty_getchars(sdev, buf, sizeof(buf)); + if (*len < 16) { + memset(buf + *len, 0, 16 - *len); + } + + *char0_7 = be64_to_cpu(*((uint64_t *)buf)); + *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1)); + + return H_SUCCESS; +} + +void spapr_vty_create(VIOsPAPRBus *bus, + uint32_t reg, CharDriverState *chardev) +{ + DeviceState *dev; + + dev = qdev_create(&bus->bus, "spapr-vty"); + qdev_prop_set_uint32(dev, "reg", reg); + qdev_prop_set_chr(dev, "chardev", chardev); + qdev_init_nofail(dev); +} + +static void vty_hcalls(VIOsPAPRBus *bus) +{ + spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); + spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); +} + +static VIOsPAPRDeviceInfo spapr_vty = { + .init = spapr_vty_init, + .dt_name = "vty", + .dt_type = "serial", + .dt_compatible = "hvterm1", + .hcalls = vty_hcalls, + .qdev.name = "spapr-vty", + .qdev.size = sizeof(VIOsPAPRVTYDevice), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0), + DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void spapr_vty_register(void) +{ + spapr_vio_bus_register_withprop(&spapr_vty); +} +device_init(spapr_vty_register); From f43e35255cffb6ac6230dd09d308f7909f823f96 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:22 +1100 Subject: [PATCH 020/386] Virtual hash page table handling on pSeries machine On pSeries logical partitions, excepting the old POWER4-style full system partitions, the guest does not have direct access to the hardware page table. Instead, the pagetable exists in hypervisor memory, and the guest must manipulate it with hypercalls. However, our current pSeries emulation more closely resembles the old style where the guest must set up and handle the pagetables itself. This patch converts it to act like a modern partition. This involves two things: first, the hash translation path is modified to permit the has table to be stored externally to the emulated machine's RAM. The pSeries machine init code configures the CPUs to use this mode. Secondly, we emulate the PAPR hypercalls for manipulating the external hashed page table. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 35 +++++- hw/spapr_hcall.c | 254 ++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 2 + target-ppc/helper.c | 36 +++++-- 4 files changed, 315 insertions(+), 12 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index c24c92b1a0..57140d231d 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -52,12 +52,15 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, sPAPREnvironment *spapr, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, - const char *kernel_cmdline) + const char *kernel_cmdline, + long hash_shift) { void *fdt; uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); + uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; + char hypertas_prop[] = "hcall-pft\0hcall-term"; int i; char *modelname; int ret; @@ -145,6 +148,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, * full emu, for kvm we should copy it from the host */ _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); + _FDT((fdt_property(fdt, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); @@ -160,6 +165,14 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_end_node(fdt))); + /* RTAS */ + _FDT((fdt_begin_node(fdt, "rtas"))); + + _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, + sizeof(hypertas_prop)))); + + _FDT((fdt_end_node(fdt))); + /* vdevice */ _FDT((fdt_begin_node(fdt, "vdevice"))); @@ -208,12 +221,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, const char *cpu_model) { CPUState *envs[MAX_CPUS]; - void *fdt; + void *fdt, *htab; int i; ram_addr_t ram_offset; target_phys_addr_t fdt_addr; uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size; + long kernel_size, initrd_size, htab_size; + long pteg_shift = 17; int fdt_size; spapr = qemu_malloc(sizeof(*spapr)); @@ -250,6 +264,18 @@ static void ppc_spapr_init(ram_addr_t ram_size, ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_offset); + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + htab_size = 1ULL << (pteg_shift + 7); + htab = qemu_mallocz(htab_size); + + for (i = 0; i < smp_cpus; i++) { + envs[i]->external_htab = htab; + envs[i]->htab_base = -1; + envs[i]->htab_mask = htab_size - 1; + } + spapr->vio_bus = spapr_vio_bus_init(); for (i = 0; i < MAX_SERIAL_PORTS; i++) { @@ -296,7 +322,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Prepare the device tree */ fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, - initrd_base, initrd_size, kernel_cmdline); + initrd_base, initrd_size, kernel_cmdline, + pteg_shift + 7); assert(fdt != NULL); cpu_physical_memory_write(fdt_addr, fdt, fdt_size); diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index e3919d01c2..0ba17172da 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -1,8 +1,253 @@ #include "sysemu.h" #include "cpu.h" #include "qemu-char.h" +#include "sysemu.h" +#include "qemu-char.h" +#include "exec-all.h" #include "hw/spapr.h" +#define HPTES_PER_GROUP 8 + +#define HPTE_V_SSIZE_SHIFT 62 +#define HPTE_V_AVPN_SHIFT 7 +#define HPTE_V_AVPN 0x3fffffffffffff80ULL +#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT) +#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL)) +#define HPTE_V_BOLTED 0x0000000000000010ULL +#define HPTE_V_LOCK 0x0000000000000008ULL +#define HPTE_V_LARGE 0x0000000000000004ULL +#define HPTE_V_SECONDARY 0x0000000000000002ULL +#define HPTE_V_VALID 0x0000000000000001ULL + +#define HPTE_R_PP0 0x8000000000000000ULL +#define HPTE_R_TS 0x4000000000000000ULL +#define HPTE_R_KEY_HI 0x3000000000000000ULL +#define HPTE_R_RPN_SHIFT 12 +#define HPTE_R_RPN 0x3ffffffffffff000ULL +#define HPTE_R_FLAGS 0x00000000000003ffULL +#define HPTE_R_PP 0x0000000000000003ULL +#define HPTE_R_N 0x0000000000000004ULL +#define HPTE_R_G 0x0000000000000008ULL +#define HPTE_R_M 0x0000000000000010ULL +#define HPTE_R_I 0x0000000000000020ULL +#define HPTE_R_W 0x0000000000000040ULL +#define HPTE_R_WIMG 0x0000000000000078ULL +#define HPTE_R_C 0x0000000000000080ULL +#define HPTE_R_R 0x0000000000000100ULL +#define HPTE_R_KEY_LO 0x0000000000000e00ULL + +#define HPTE_V_1TB_SEG 0x4000000000000000ULL +#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL + +#define HPTE_V_HVLOCK 0x40ULL + +static inline int lock_hpte(void *hpte, target_ulong bits) +{ + uint64_t pteh; + + pteh = ldq_p(hpte); + + /* We're protected by qemu's global lock here */ + if (pteh & bits) { + return 0; + } + stq_p(hpte, pteh | HPTE_V_HVLOCK); + return 1; +} + +static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, + target_ulong pte_index) +{ + target_ulong rb, va_low; + + rb = (v & ~0x7fULL) << 16; /* AVA field */ + va_low = pte_index >> 3; + if (v & HPTE_V_SECONDARY) { + va_low = ~va_low; + } + /* xor vsid from AVA */ + if (!(v & HPTE_V_1TB_SEG)) { + va_low ^= v >> 12; + } else { + va_low ^= v >> 24; + } + va_low &= 0x7ff; + if (v & HPTE_V_LARGE) { + rb |= 1; /* L field */ +#if 0 /* Disable that P7 specific bit for now */ + if (r & 0xff000) { + /* non-16MB large page, must be 64k */ + /* (masks depend on page size) */ + rb |= 0x1000; /* page encoding in LP field */ + rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ + rb |= (va_low & 0xfe); /* AVAL field */ + } +#endif + } else { + /* 4kB page */ + rb |= (va_low & 0x7ff) << 12; /* remaining 11b of AVA */ + } + rb |= (v >> 54) & 0x300; /* B field */ + return rb; +} + +static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong pteh = args[2]; + target_ulong ptel = args[3]; + target_ulong porder; + target_ulong i, pa; + uint8_t *hpte; + + /* only handle 4k and 16M pages for now */ + porder = 12; + if (pteh & HPTE_V_LARGE) { +#if 0 /* We don't support 64k pages yet */ + if ((ptel & 0xf000) == 0x1000) { + /* 64k page */ + porder = 16; + } else +#endif + if ((ptel & 0xff000) == 0) { + /* 16M page */ + porder = 24; + /* lowest AVA bit must be 0 for 16M pages */ + if (pteh & 0x80) { + return H_PARAMETER; + } + } else { + return H_PARAMETER; + } + } + + pa = ptel & HPTE_R_RPN; + /* FIXME: bounds check the pa? */ + + /* Check WIMG */ + if ((ptel & HPTE_R_WIMG) != HPTE_R_M) { + return H_PARAMETER; + } + pteh &= ~0x60ULL; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + if (likely((flags & H_EXACT) == 0)) { + pte_index &= ~7ULL; + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + for (i = 0; ; ++i) { + if (i == 8) { + return H_PTEG_FULL; + } + if (((ldq_p(hpte) & HPTE_V_VALID) == 0) && + lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + break; + } + hpte += HASH_PTE_SIZE_64; + } + } else { + i = 0; + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + return H_PTEG_FULL; + } + } + stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel); + /* eieio(); FIXME: need some sort of barrier for smp? */ + stq_p(hpte, pteh); + + assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + args[0] = pte_index + i; + return H_SUCCESS; +} + +static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong avpn = args[2]; + uint8_t *hpte; + target_ulong v, r, rb; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { + /* We have no real concurrency in qemu soft-emulation, so we + * will never actually have a contested lock */ + assert(0); + } + + v = ldq_p(hpte); + r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + + if ((v & HPTE_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || + ((flags & H_ANDCOND) && (v & avpn) != 0)) { + stq_p(hpte, v & ~HPTE_V_HVLOCK); + assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + return H_NOT_FOUND; + } + args[0] = v & ~HPTE_V_HVLOCK; + args[1] = r; + stq_p(hpte, 0); + rb = compute_tlbie_rb(v, r, pte_index); + ppc_tlb_invalidate_one(env, rb); + assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + return H_SUCCESS; +} + +static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + target_ulong avpn = args[2]; + uint8_t *hpte; + target_ulong v, r, rb; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { + /* We have no real concurrency in qemu soft-emulation, so we + * will never actually have a contested lock */ + assert(0); + } + + v = ldq_p(hpte); + r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + + if ((v & HPTE_V_VALID) == 0 || + ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { + stq_p(hpte, v & ~HPTE_V_HVLOCK); + assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + return H_NOT_FOUND; + } + + r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | + HPTE_R_KEY_HI | HPTE_R_KEY_LO); + r |= (flags << 55) & HPTE_R_PP0; + r |= (flags << 48) & HPTE_R_KEY_HI; + r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO); + rb = compute_tlbie_rb(v, r, pte_index); + stq_p(hpte, v & ~HPTE_V_VALID); + ppc_tlb_invalidate_one(env, rb); + stq_p(hpte + (HASH_PTE_SIZE_64/2), r); + /* Don't need a memory barrier, due to qemu's global lock */ + stq_p(hpte, v & ~HPTE_V_HVLOCK); + assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + return H_SUCCESS; +} + spapr_hcall_fn hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) @@ -39,3 +284,12 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode); return H_FUNCTION; } + +static void hypercall_init(void) +{ + /* hcall-pft */ + spapr_register_hypercall(H_ENTER, h_enter); + spapr_register_hypercall(H_REMOVE, h_remove); + spapr_register_hypercall(H_PROTECT, h_protect); +} +device_init(hypercall_init); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 25d0658c47..b4c2555626 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -670,6 +670,8 @@ struct CPUPPCState { target_phys_addr_t htab_base; target_phys_addr_t htab_mask; target_ulong sr[32]; + /* externally stored hash table */ + uint8_t *external_htab; /* BATs */ int nb_BATs; target_ulong DBAT[2][8]; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 278bee4f17..5e4030bb53 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -589,8 +589,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, for (i = 0; i < 8; i++) { #if defined(TARGET_PPC64) if (is_64b) { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + if (env->external_htab) { + pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); + pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); + } else { + pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); + pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + } /* We have a TLB that saves 4K pages, so let's * split a huge page to 4k chunks */ @@ -606,8 +611,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, } else #endif { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + if (env->external_htab) { + pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); + pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); + } else { + pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); + pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + } r = pte32_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", @@ -647,13 +657,23 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { #if defined(TARGET_PPC64) if (is_64b) { - stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8, - pte1); + if (env->external_htab) { + stq_p(env->external_htab + pteg_off + (good * 16) + 8, + pte1); + } else { + stq_phys_notdirty(env->htab_base + pteg_off + + (good * 16) + 8, pte1); + } } else #endif { - stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4, - pte1); + if (env->external_htab) { + stl_p(env->external_htab + pteg_off + (good * 8) + 4, + pte1); + } else { + stl_phys_notdirty(env->htab_base + pteg_off + + (good * 8) + 4, pte1); + } } } } From 39ac8455106af1ed669b8e10223420cf1ac5b190 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:23 +1100 Subject: [PATCH 021/386] Implement hcall based RTAS for pSeries machines On pSeries machines, operating systems can instantiate "RTAS" (Run-Time Abstraction Services), a runtime component of the firmware which implements a number of low-level, infrequently used operations. On logical partitions under a hypervisor, many of the RTAS functions require hypervisor privilege. For simplicity, therefore, hypervisor systems typically implement the in-partition RTAS as just a tiny wrapper around a hypercall which actually implements the various RTAS functions. This patch implements such a hypercall based RTAS for our emulated pSeries machine. A tiny in-partition "firmware" calls a new hypercall, which looks up available RTAS services in a table. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile | 3 +- Makefile.target | 2 +- configure | 4 +- hw/spapr.c | 26 ++++++- hw/spapr.h | 32 ++++++++ hw/spapr_hcall.c | 44 +++++++++-- hw/spapr_rtas.c | 131 ++++++++++++++++++++++++++++++++ pc-bios/spapr-rtas.bin | Bin 0 -> 20 bytes pc-bios/spapr-rtas/Makefile | 24 ++++++ pc-bios/spapr-rtas/spapr-rtas.S | 37 +++++++++ 10 files changed, 289 insertions(+), 14 deletions(-) create mode 100644 hw/spapr_rtas.c create mode 100755 pc-bios/spapr-rtas.bin create mode 100644 pc-bios/spapr-rtas/Makefile create mode 100644 pc-bios/spapr-rtas/spapr-rtas.S diff --git a/Makefile b/Makefile index 89e88b4a9e..e0b3fea6bc 100644 --- a/Makefile +++ b/Makefile @@ -213,7 +213,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \ pxe-rtl8139.bin pxe-virtio.bin \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin \ -s390-zipl.rom +s390-zipl.rom \ +spapr-rtas.bin else BLOBS= endif diff --git a/Makefile.target b/Makefile.target index cf12691670..a53d99fd52 100644 --- a/Makefile.target +++ b/Makefile.target @@ -233,7 +233,7 @@ obj-ppc-y += ppc_oldworld.o obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) -obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o +obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-ppc-y += spapr_vty.o endif # PowerPC 4xx boards diff --git a/configure b/configure index 5a5827f6db..7d8d890891 100755 --- a/configure +++ b/configure @@ -2461,7 +2461,9 @@ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \ "$softmmu" = yes ; then roms="optionrom" fi - +if test "$cpu" = "ppc64" ; then + roms="$roms spapr-rtas" +fi echo "Install prefix $prefix" echo "BIOS directory `eval echo $datadir`" diff --git a/hw/spapr.c b/hw/spapr.c index 57140d231d..c07af19543 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -40,6 +40,7 @@ #define KERNEL_LOAD_ADDR 0x00000000 #define INITRD_LOAD_ADDR 0x02800000 #define FDT_MAX_SIZE 0x10000 +#define RTAS_MAX_SIZE 0x10000 #define TIMEBASE_FREQ 512000000ULL @@ -53,6 +54,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline, + target_phys_addr_t rtas_addr, + target_phys_addr_t rtas_size, long hash_shift) { void *fdt; @@ -195,6 +198,12 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, exit(1); } + /* RTAS */ + ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); + } + _FDT((fdt_pack(fdt))); *fdt_size = fdt_totalsize(fdt); @@ -224,11 +233,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, void *fdt, *htab; int i; ram_addr_t ram_offset; - target_phys_addr_t fdt_addr; + target_phys_addr_t fdt_addr, rtas_addr; uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size, htab_size; + long kernel_size, initrd_size, htab_size, rtas_size; long pteg_shift = 17; int fdt_size; + char *filename; spapr = qemu_malloc(sizeof(*spapr)); cpu_ppc_hypercall = emulate_spapr_hypercall; @@ -237,6 +247,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, * 2GB, so that it can be processed with 32-bit code if * necessary */ fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; + /* RTAS goes just below that */ + rtas_addr = fdt_addr - RTAS_MAX_SIZE; /* init CPUs */ if (cpu_model == NULL) { @@ -276,6 +288,14 @@ static void ppc_spapr_init(ram_addr_t ram_size, envs[i]->htab_mask = htab_size - 1; } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); + rtas_size = load_image_targphys(filename, rtas_addr, ram_size - rtas_addr); + if (rtas_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + qemu_free(filename); + spapr->vio_bus = spapr_vio_bus_init(); for (i = 0; i < MAX_SERIAL_PORTS; i++) { @@ -323,7 +343,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Prepare the device tree */ fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, initrd_base, initrd_size, kernel_cmdline, - pteg_shift + 7); + rtas_addr, rtas_size, pteg_shift + 7); assert(fdt != NULL); cpu_physical_memory_write(fdt_addr, fdt, fdt_size); diff --git a/hw/spapr.h b/hw/spapr.h index 06cca15b94..0dcb83a5ae 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -237,6 +237,18 @@ typedef struct sPAPREnvironment { #define H_GET_MPP 0x2D4 #define MAX_HCALL_OPCODE H_GET_MPP +/* The hcalls above are standardized in PAPR and implemented by pHyp + * as well. + * + * We also need some hcalls which are specific to qemu / KVM-on-POWER. + * So far we just need one for H_RTAS, but in future we'll need more + * for extensions like virtio. We put those into the 0xf000-0xfffc + * range which is reserved by PAPR for "platform-specific" hcalls. + */ +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) +#define KVMPPC_HCALL_MAX KVMPPC_H_RTAS + extern sPAPREnvironment *spapr; /*#define DEBUG_SPAPR_HCALLS*/ @@ -257,4 +269,24 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, target_ulong *args); +static inline uint32_t rtas_ld(target_ulong phys, int n) +{ + return ldl_phys(phys + 4*n); +} + +static inline void rtas_st(target_ulong phys, int n, uint32_t val) +{ + stl_phys(phys + 4*n, val); +} + +typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets); +void spapr_rtas_register(const char *name, spapr_rtas_fn fn); +target_ulong spapr_rtas_call(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets); +int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, + target_phys_addr_t rtas_size); + #endif /* !defined (__HW_SPAPR_H__) */ diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 0ba17172da..d8c721e472 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -248,20 +248,38 @@ static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -spapr_hcall_fn hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; +static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong rtas_r3 = args[0]; + uint32_t token = ldl_phys(rtas_r3); + uint32_t nargs = ldl_phys(rtas_r3 + 4); + uint32_t nret = ldl_phys(rtas_r3 + 8); + + return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12, + nret, rtas_r3 + 12 + 4*nargs); +} + +spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; +spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE]; void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) { - spapr_hcall_fn old_fn; + spapr_hcall_fn *slot; - assert(opcode <= MAX_HCALL_OPCODE); - assert((opcode & 0x3) == 0); + if (opcode <= MAX_HCALL_OPCODE) { + assert((opcode & 0x3) == 0); - old_fn = hypercall_table[opcode / 4]; + slot = &papr_hypercall_table[opcode / 4]; + } else { + assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); - assert(!old_fn || (fn == old_fn)); - hypercall_table[opcode / 4] = fn; + slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; + } + + assert(!(*slot) || (fn == *slot)); + *slot = fn; } target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, @@ -274,7 +292,14 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode, if ((opcode <= MAX_HCALL_OPCODE) && ((opcode & 0x3) == 0)) { - spapr_hcall_fn fn = hypercall_table[opcode / 4]; + spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; + + if (fn) { + return fn(env, spapr, opcode, args); + } + } else if ((opcode >= KVMPPC_HCALL_BASE) && + (opcode <= KVMPPC_HCALL_MAX)) { + spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; if (fn) { return fn(env, spapr, opcode, args); @@ -291,5 +316,8 @@ static void hypercall_init(void) spapr_register_hypercall(H_ENTER, h_enter); spapr_register_hypercall(H_REMOVE, h_remove); spapr_register_hypercall(H_PROTECT, h_protect); + + /* qemu/KVM-PPC specific hcalls */ + spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); } device_init(hypercall_init); diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c new file mode 100644 index 0000000000..3f090f5518 --- /dev/null +++ b/hw/spapr_rtas.c @@ -0,0 +1,131 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * Hypercall based emulated RTAS + * + * Copyright (c) 2010-2011 David Gibson, IBM Corporation. + * + * 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 "cpu.h" +#include "sysemu.h" +#include "qemu-char.h" +#include "hw/qdev.h" +#include "device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include <libfdt.h> + +#define TOKEN_BASE 0x2000 +#define TOKEN_MAX 0x100 + +static struct rtas_call { + const char *name; + spapr_rtas_fn fn; +} rtas_table[TOKEN_MAX]; + +struct rtas_call *rtas_next = rtas_table; + +target_ulong spapr_rtas_call(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + if ((token >= TOKEN_BASE) + && ((token - TOKEN_BASE) < TOKEN_MAX)) { + struct rtas_call *call = rtas_table + (token - TOKEN_BASE); + + if (call->fn) { + call->fn(spapr, token, nargs, args, nret, rets); + return H_SUCCESS; + } + } + + hcall_dprintf("Unknown RTAS token 0x%x\n", token); + rtas_st(rets, 0, -3); + return H_PARAMETER; +} + +void spapr_rtas_register(const char *name, spapr_rtas_fn fn) +{ + assert(rtas_next < (rtas_table + TOKEN_MAX)); + + rtas_next->name = name; + rtas_next->fn = fn; + + rtas_next++; +} + +int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, + target_phys_addr_t rtas_size) +{ + int ret; + int i; + + ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base", + rtas_addr); + if (ret < 0) { + fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry", + rtas_addr); + if (ret < 0) { + fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", + fdt_strerror(ret)); + return ret; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size", + rtas_size); + if (ret < 0) { + fprintf(stderr, "Couldn't add rtas-size property: %s\n", + fdt_strerror(ret)); + return ret; + } + + for (i = 0; i < TOKEN_MAX; i++) { + struct rtas_call *call = &rtas_table[i]; + + if (!call->fn) { + continue; + } + + ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name, + i + TOKEN_BASE); + if (ret < 0) { + fprintf(stderr, "Couldn't add rtas token for %s: %s\n", + call->name, fdt_strerror(ret)); + return ret; + } + + } + return 0; +} diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin new file mode 100755 index 0000000000000000000000000000000000000000..fc24c8ed8b92a3a441aed6e2bd013b2ccece9229 GIT binary patch literal 20 bcmb<Pk*=^wU|>i{{=neEz@X&Uz@PvCJTV0q literal 0 HcmV?d00001 diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile new file mode 100644 index 0000000000..dc8b23e3ce --- /dev/null +++ b/pc-bios/spapr-rtas/Makefile @@ -0,0 +1,24 @@ +all: build-all +# Dummy command so that make thinks it has done something + @true + +include ../../config-host.mak +include $(SRC_PATH)/rules.mak + +$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas) + +.PHONY : all clean build-all + +#CFLAGS += -I$(SRC_PATH) +#QEMU_CFLAGS = $(CFLAGS) + +build-all: spapr-rtas.bin + +%.img: %.o + $(call quiet-command,$(CC) -nostdlib -o $@ $<," Building $(TARGET_DIR)$@") + +%.bin: %.img + $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@," Building $(TARGET_DIR)$@") + +clean: + rm -f *.o *.d *.img *.bin *~ diff --git a/pc-bios/spapr-rtas/spapr-rtas.S b/pc-bios/spapr-rtas/spapr-rtas.S new file mode 100644 index 0000000000..903bec2150 --- /dev/null +++ b/pc-bios/spapr-rtas/spapr-rtas.S @@ -0,0 +1,37 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * Trivial in-partition RTAS implementation, based on a hypercall + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * 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. + * + */ + +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) + +.globl _start +_start: + mr 4,3 + lis 3,KVMPPC_H_RTAS@h + ori 3,3,KVMPPC_H_RTAS@l + sc 1 + blr From 821303f59b63ab832f0921f070db55e95bb21858 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:24 +1100 Subject: [PATCH 022/386] Implement assorted pSeries hcalls and RTAS methods This patch adds several small utility hypercalls and RTAS methods to the pSeries platform emulation. Specifically: * 'display-character' rtas call This just prints a character to the console, it's occasionally used for early debug of the OS. The support includes a hack to make this RTAS call respond on the normal token value present on real hardware, since some early debugging tools just assume this value without checking the device tree. * 'get-time-of-day' rtas call This one just takes the host real time, converts to the PAPR described format and returns it to the guest. * 'power-off' rtas call This one shuts down the emulated system. * H_DABR hypercall On pSeries, the DABR debug register is usually a hypervisor resource and virtualized through this hypercall. If the hypercall is not present, Linux will under some circumstances attempt to manipulate the DABR directly which will fail on this emulated machine. This stub implementation is enough to stop that behaviour, although it doesn't actually implement the requested DABR operations as yet. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 2 +- hw/spapr_hcall.c | 10 +++++++ hw/spapr_rtas.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index c07af19543..6c64de82de 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -63,7 +63,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; - char hypertas_prop[] = "hcall-pft\0hcall-term"; + char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr"; int i; char *modelname; int ret; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index d8c721e472..a47a97ba55 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -248,6 +248,13 @@ static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + /* FIXME: actually implement this */ + return H_HARDWARE; +} + static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -317,6 +324,9 @@ static void hypercall_init(void) spapr_register_hypercall(H_REMOVE, h_remove); spapr_register_hypercall(H_PROTECT, h_protect); + /* hcall-dabr */ + spapr_register_hypercall(H_SET_DABR, h_set_dabr); + /* qemu/KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); } diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 3f090f5518..72268537a8 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -38,6 +38,58 @@ #define TOKEN_BASE 0x2000 #define TOKEN_MAX 0x100 +static void rtas_display_character(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint8_t c = rtas_ld(args, 0); + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, 0); + + if (!sdev) { + rtas_st(rets, 0, -1); + } else { + vty_putchars(sdev, &c, sizeof(c)); + rtas_st(rets, 0, 0); + } +} + +static void rtas_get_time_of_day(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct tm tm; + + if (nret != 8) { + rtas_st(rets, 0, -3); + return; + } + + qemu_get_timedate(&tm, 0); + + rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 1, tm.tm_year + 1900); + rtas_st(rets, 2, tm.tm_mon + 1); + rtas_st(rets, 3, tm.tm_mday); + rtas_st(rets, 4, tm.tm_hour); + rtas_st(rets, 5, tm.tm_min); + rtas_st(rets, 6, tm.tm_sec); + rtas_st(rets, 7, 0); /* we don't do nanoseconds */ +} + +static void rtas_power_off(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + if (nargs != 2 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + qemu_system_shutdown_request(); + rtas_st(rets, 0, 0); +} + static struct rtas_call { const char *name; spapr_rtas_fn fn; @@ -59,6 +111,15 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr, } } + /* HACK: Some Linux early debug code uses RTAS display-character, + * but assumes the token value is 0xa (which it is on some real + * machines) without looking it up in the device tree. This + * special case makes this work */ + if (token == 0xa) { + rtas_display_character(spapr, 0xa, nargs, args, nret, rets); + return H_SUCCESS; + } + hcall_dprintf("Unknown RTAS token 0x%x\n", token); rtas_st(rets, 0, -3); return H_PARAMETER; @@ -129,3 +190,11 @@ int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, } return 0; } + +static void register_core_rtas(void) +{ + spapr_rtas_register("display-character", rtas_display_character); + spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); + spapr_rtas_register("power-off", rtas_power_off); +} +device_init(register_core_rtas); From b5cec4c5f294ca3af24e7edf4f37cc2de0ae0e03 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:25 +1100 Subject: [PATCH 023/386] Implement the PAPR (pSeries) virtualized interrupt controller (xics) PAPR defines an interrupt control architecture which is logically divided into ICS (Interrupt Control Presentation, each unit is responsible for presenting interrupts to a particular "interrupt server", i.e. CPU) and ICS (Interrupt Control Source, each unit responsible for one or more hardware interrupts as numbered globally across the system). All PAPR virtual IO devices expect to deliver interrupts via this mechanism. In Linux, this interrupt controller system is handled by the "xics" driver. On pSeries systems, access to the interrupt controller is virtualized via hypercalls and RTAS methods. However, the virtualized interface is very similar to the underlying interrupt controller hardware, and similar PICs exist un-virtualized in some other systems. This patch implements both the ICP and ICS sides of the PAPR interrupt controller. For now, only the hypercall virtualized interface is provided, however it would be relatively straightforward to graft an emulated register interface onto the underlying interrupt logic if we want to add a machine with a hardware ICS/ICP system in the future. There are some limitations in this implementation: it is assumed for now that only one instance of the ICS exists, although a full xics system can have several, each responsible for a different group of hardware irqs. ICP/ICS can handle both level-sensitve (LSI) and message signalled (MSI) interrupt inputs. For now, this implementation supports only MSI interrupts, since that is used by PAPR virtual IO devices. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile.target | 2 +- hw/spapr.c | 27 +++ hw/spapr.h | 2 + hw/xics.c | 486 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/xics.h | 39 ++++ 5 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 hw/xics.c create mode 100644 hw/xics.h diff --git a/Makefile.target b/Makefile.target index a53d99fd52..c79542842f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -234,7 +234,7 @@ obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o -obj-ppc-y += spapr_vty.o +obj-ppc-y += xics.o spapr_vty.o endif # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o diff --git a/hw/spapr.c b/hw/spapr.c index 6c64de82de..b5aefd72c3 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -34,6 +34,7 @@ #include "hw/spapr.h" #include "hw/spapr_vio.h" +#include "hw/xics.h" #include <libfdt.h> @@ -45,6 +46,7 @@ #define TIMEBASE_FREQ 512000000ULL #define MAX_CPUS 32 +#define XICS_IRQS 1024 sPAPREnvironment *spapr; @@ -64,6 +66,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr"; + uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; int ret; @@ -125,6 +128,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, for (i = 0; i < smp_cpus; i++) { CPUState *env = envs[i]; + uint32_t gserver_prop[] = {cpu_to_be32(i), 0}; /* HACK! */ char *nodename; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; @@ -155,6 +159,9 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); + _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", i))); + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", + gserver_prop, sizeof(gserver_prop)))); if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", @@ -176,6 +183,20 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_end_node(fdt))); + /* interrupt controller */ + _FDT((fdt_begin_node(fdt, "interrupt-controller@0"))); + + _FDT((fdt_property_string(fdt, "device_type", + "PowerPC-External-Interrupt-Presentation"))); + _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"))); + _FDT((fdt_property_cell(fdt, "reg", 0))); + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges", + interrupt_server_ranges_prop, + sizeof(interrupt_server_ranges_prop)))); + + _FDT((fdt_end_node(fdt))); + /* vdevice */ _FDT((fdt_begin_node(fdt, "vdevice"))); @@ -183,6 +204,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice"))); _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2))); + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); _FDT((fdt_end_node(fdt))); @@ -296,6 +319,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, } qemu_free(filename); + /* Set up Interrupt Controller */ + spapr->icp = xics_system_init(smp_cpus, envs, XICS_IRQS); + + /* Set up VIO bus */ spapr->vio_bus = spapr_vio_bus_init(); for (i = 0; i < MAX_SERIAL_PORTS; i++) { diff --git a/hw/spapr.h b/hw/spapr.h index 0dcb83a5ae..fae8e1351c 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -2,9 +2,11 @@ #define __HW_SPAPR_H__ struct VIOsPAPRBus; +struct icp_state; typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; + struct icp_state *icp; } sPAPREnvironment; #define H_SUCCESS 0 diff --git a/hw/xics.c b/hw/xics.c new file mode 100644 index 0000000000..66047a6c57 --- /dev/null +++ b/hw/xics.c @@ -0,0 +1,486 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * 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 "hw.h" +#include "hw/spapr.h" +#include "hw/xics.h" + +#include <pthread.h> + +/* + * ICP: Presentation layer + */ + +struct icp_server_state { + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; +}; + +#define XISR_MASK 0x00ffffff +#define CPPR_MASK 0xff000000 + +#define XISR(ss) (((ss)->xirr) & XISR_MASK) +#define CPPR(ss) (((ss)->xirr) >> 24) + +struct ics_state; + +struct icp_state { + long nr_servers; + struct icp_server_state *ss; + struct ics_state *ics; +}; + +static void ics_reject(struct ics_state *ics, int nr); +static void ics_resend(struct ics_state *ics); +static void ics_eoi(struct ics_state *ics, int nr); + +static void icp_check_ipi(struct icp_state *icp, int server) +{ + struct icp_server_state *ss = icp->ss + server; + + if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { + return; + } + + if (XISR(ss)) { + ics_reject(icp->ics, XISR(ss)); + } + + ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; + ss->pending_priority = ss->mfrr; + qemu_irq_raise(ss->output); +} + +static void icp_resend(struct icp_state *icp, int server) +{ + struct icp_server_state *ss = icp->ss + server; + + if (ss->mfrr < CPPR(ss)) { + icp_check_ipi(icp, server); + } + ics_resend(icp->ics); +} + +static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) +{ + struct icp_server_state *ss = icp->ss + server; + uint8_t old_cppr; + uint32_t old_xisr; + + old_cppr = CPPR(ss); + ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24); + + if (cppr < old_cppr) { + if (XISR(ss) && (cppr <= ss->pending_priority)) { + old_xisr = XISR(ss); + ss->xirr &= ~XISR_MASK; /* Clear XISR */ + qemu_irq_lower(ss->output); + ics_reject(icp->ics, old_xisr); + } + } else { + if (!XISR(ss)) { + icp_resend(icp, server); + } + } +} + +static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr) +{ + struct icp_server_state *ss = icp->ss + nr; + + ss->mfrr = mfrr; + if (mfrr < CPPR(ss)) { + icp_check_ipi(icp, nr); + } +} + +static uint32_t icp_accept(struct icp_server_state *ss) +{ + uint32_t xirr; + + qemu_irq_lower(ss->output); + xirr = ss->xirr; + ss->xirr = ss->pending_priority << 24; + return xirr; +} + +static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) +{ + struct icp_server_state *ss = icp->ss + server; + + ics_eoi(icp->ics, xirr & XISR_MASK); + /* Send EOI -> ICS */ + ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); + if (!XISR(ss)) { + icp_resend(icp, server); + } +} + +static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) +{ + struct icp_server_state *ss = icp->ss + server; + + if ((priority >= CPPR(ss)) + || (XISR(ss) && (ss->pending_priority <= priority))) { + ics_reject(icp->ics, nr); + } else { + if (XISR(ss)) { + ics_reject(icp->ics, XISR(ss)); + } + ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); + ss->pending_priority = priority; + qemu_irq_raise(ss->output); + } +} + +/* + * ICS: Source layer + */ + +struct ics_irq_state { + int server; + uint8_t priority; + uint8_t saved_priority; + /* int pending:1; */ + /* int presented:1; */ + int rejected:1; + int masked_pending:1; +}; + +struct ics_state { + int nr_irqs; + int offset; + qemu_irq *qirqs; + struct ics_irq_state *irqs; + struct icp_state *icp; +}; + +static int ics_valid_irq(struct ics_state *ics, uint32_t nr) +{ + return (nr >= ics->offset) + && (nr < (ics->offset + ics->nr_irqs)); +} + +static void ics_set_irq_msi(void *opaque, int nr, int val) +{ + struct ics_state *ics = (struct ics_state *)opaque; + struct ics_irq_state *irq = ics->irqs + nr; + + if (val) { + if (irq->priority == 0xff) { + irq->masked_pending = 1; + /* masked pending */ ; + } else { + icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority); + } + } +} + +static void ics_reject_msi(struct ics_state *ics, int nr) +{ + struct ics_irq_state *irq = ics->irqs + nr - ics->offset; + + irq->rejected = 1; +} + +static void ics_resend_msi(struct ics_state *ics) +{ + int i; + + for (i = 0; i < ics->nr_irqs; i++) { + struct ics_irq_state *irq = ics->irqs + i; + + /* FIXME: filter by server#? */ + if (irq->rejected) { + irq->rejected = 0; + if (irq->priority != 0xff) { + icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority); + } + } + } +} + +static void ics_write_xive_msi(struct ics_state *ics, int nr, int server, + uint8_t priority) +{ + struct ics_irq_state *irq = ics->irqs + nr; + + irq->server = server; + irq->priority = priority; + + if (!irq->masked_pending || (priority == 0xff)) { + return; + } + + irq->masked_pending = 0; + icp_irq(ics->icp, server, nr + ics->offset, priority); +} + +static void ics_reject(struct ics_state *ics, int nr) +{ + ics_reject_msi(ics, nr); +} + +static void ics_resend(struct ics_state *ics) +{ + ics_resend_msi(ics); +} + +static void ics_eoi(struct ics_state *ics, int nr) +{ +} + +/* + * Exported functions + */ + +qemu_irq xics_find_qirq(struct icp_state *icp, int irq) +{ + if ((irq < icp->ics->offset) + || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) { + return NULL; + } + + return icp->ics->qirqs[irq - icp->ics->offset]; +} + +static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong cppr = args[0]; + + icp_set_cppr(spapr->icp, env->cpu_index, cppr); + return H_SUCCESS; +} + +static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong server = args[0]; + target_ulong mfrr = args[1]; + + if (server >= spapr->icp->nr_servers) { + return H_PARAMETER; + } + + icp_set_mfrr(spapr->icp, server, mfrr); + return H_SUCCESS; + +} + +static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index); + + args[0] = xirr; + return H_SUCCESS; +} + +static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong xirr = args[0]; + + icp_eoi(spapr->icp, env->cpu_index, xirr); + return H_SUCCESS; +} + +static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr, server, priority; + + if ((nargs != 3) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + server = rtas_ld(args, 1); + priority = rtas_ld(args, 2); + + if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) + || (priority > 0xff)) { + rtas_st(rets, 0, -3); + return; + } + + ics_write_xive_msi(ics, nr - ics->offset, server, priority); + + rtas_st(rets, 0, 0); /* Success */ +} + +static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 3)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); + rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); +} + +static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + /* This is a NOP for now, since the described PAPR semantics don't + * seem to gel with what Linux does */ +#if 0 + struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); + + irq->saved_priority = irq->priority; + ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff); +#endif + + rtas_st(rets, 0, 0); /* Success */ +} + +static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + struct ics_state *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, -3); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, -3); + return; + } + + /* This is a NOP for now, since the described PAPR semantics don't + * seem to gel with what Linux does */ +#if 0 + struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); + + ics_write_xive_msi(xics, nr - xics->offset, + irq->server, irq->saved_priority); +#endif + + rtas_st(rets, 0, 0); /* Success */ +} + +struct icp_state *xics_system_init(int nr_servers, CPUState *servers[], + int nr_irqs) +{ + int i; + struct icp_state *icp; + struct ics_state *ics; + + icp = qemu_mallocz(sizeof(*icp)); + icp->nr_servers = nr_servers; + icp->ss = qemu_mallocz(nr_servers * sizeof(struct icp_server_state)); + + for (i = 0; i < nr_servers; i++) { + servers[i]->cpu_index = i; + + switch (PPC_INPUT(servers[i])) { + case PPC_FLAGS_INPUT_POWER7: + icp->ss[i].output = servers[i]->irq_inputs[POWER7_INPUT_INT]; + break; + + case PPC_FLAGS_INPUT_970: + icp->ss[i].output = servers[i]->irq_inputs[PPC970_INPUT_INT]; + break; + + default: + hw_error("XICS interrupt model does not support this CPU bus " + "model\n"); + exit(1); + } + + icp->ss[i].mfrr = 0xff; + } + + ics = qemu_mallocz(sizeof(*ics)); + ics->nr_irqs = nr_irqs; + ics->offset = 16; + ics->irqs = qemu_mallocz(nr_irqs * sizeof(struct ics_irq_state)); + + icp->ics = ics; + ics->icp = icp; + + for (i = 0; i < nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } + + ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs); + + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_EOI, h_eoi); + + spapr_rtas_register("ibm,set-xive", rtas_set_xive); + spapr_rtas_register("ibm,get-xive", rtas_get_xive); + spapr_rtas_register("ibm,int-off", rtas_int_off); + spapr_rtas_register("ibm,int-on", rtas_int_on); + + return icp; +} diff --git a/hw/xics.h b/hw/xics.h new file mode 100644 index 0000000000..096eeb346d --- /dev/null +++ b/hw/xics.h @@ -0,0 +1,39 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * 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. + * + */ +#if !defined(__XICS_H__) +#define __XICS_H__ + +#define XICS_IPI 0x2 + +struct icp_state; + +qemu_irq xics_find_qirq(struct icp_state *icp, int irq); + +struct icp_state *xics_system_init(int nr_servers, CPUState *servers[], + int nr_irqs); + +#endif /* __XICS_H__ */ From 00dc738d8a08fce0f0d327e081bb2bd7b6fba888 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:26 +1100 Subject: [PATCH 024/386] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts This patch adds infrastructure to support interrupts from PAPR virtual IO devices. This includes correctly advertising those interrupts in the device tree, and implementing the H_VIO_SIGNAL hypercall, used to enable and disable individual device interrupts. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 2 +- hw/spapr_vio.c | 37 +++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 6 ++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index b5aefd72c3..200617bc7c 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -65,7 +65,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; - char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr"; + char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 10acb4c308..605079cda5 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -105,6 +105,16 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } } + if (dev->qirq) { + uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0}; + + ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, + sizeof(ints_prop)); + if (ret < 0) { + return ret; + } + } + if (info->devnode) { ret = (info->devnode)(dev, fdt, node_off); if (ret < 0) { @@ -140,6 +150,30 @@ void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info) qdev_register(&info->qdev); } +static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong mode = args[1]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRDeviceInfo *info; + + if (!dev) { + return H_PARAMETER; + } + + info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + + if (mode & ~info->signal_mask) { + return H_PARAMETER; + } + + dev->signal_state = mode; + + return H_SUCCESS; +} + VIOsPAPRBus *spapr_vio_bus_init(void) { VIOsPAPRBus *bus; @@ -156,6 +190,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void) qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio"); bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); + /* hcall-vio */ + spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); + for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index b164ad326c..8a000c6fe5 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -24,6 +24,9 @@ typedef struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; + qemu_irq qirq; + uint32_t vio_irq_num; + target_ulong signal_state; } VIOsPAPRDevice; typedef struct VIOsPAPRBus { @@ -33,6 +36,7 @@ typedef struct VIOsPAPRBus { typedef struct { DeviceInfo qdev; const char *dt_name, *dt_type, *dt_compatible; + target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); void (*hcalls)(VIOsPAPRBus *bus); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); @@ -43,6 +47,8 @@ extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); +extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); + void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); From 0201e2da65b1828937c478fa1ac52e58522a32c1 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:27 +1100 Subject: [PATCH 025/386] Add (virtual) interrupt to PAPR virtual tty device Now that we have implemented the PAPR "xics" virtualized interrupt controller, we can add interrupts in PAPR VIO devices. This patch adds interrupt support to the PAPR virtual tty/console device. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 6 ++++-- hw/spapr_vio.h | 3 ++- hw/spapr_vty.c | 11 ++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 200617bc7c..859cf86011 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -262,6 +262,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, long pteg_shift = 17; int fdt_size; char *filename; + int irq = 16; spapr = qemu_malloc(sizeof(*spapr)); cpu_ppc_hypercall = emulate_spapr_hypercall; @@ -325,9 +326,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set up VIO bus */ spapr->vio_bus = spapr_vio_bus_init(); - for (i = 0; i < MAX_SERIAL_PORTS; i++) { + for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) { if (serial_hds[i]) { - spapr_vty_create(spapr->vio_bus, i, serial_hds[i]); + spapr_vty_create(spapr->vio_bus, i, serial_hds[i], + xics_find_qirq(spapr->icp, irq), irq); } } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 8a000c6fe5..20139273d3 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -51,6 +51,7 @@ extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, - uint32_t reg, CharDriverState *chardev); + uint32_t reg, CharDriverState *chardev, + qemu_irq qirq, uint32_t vio_irq_num); #endif /* _HW_SPAPR_VIO_H */ diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index b4da6a83fb..6fc0105eac 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -24,6 +24,10 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; int i; + if ((dev->in == dev->out) && size) { + /* toggle line to simulate edge interrupt */ + qemu_irq_pulse(dev->sdev.qirq); + } for (i = 0; i < size; i++) { assert((dev->in - dev->out) < VTERM_BUFSIZE); dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i]; @@ -112,14 +116,19 @@ static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr, } void spapr_vty_create(VIOsPAPRBus *bus, - uint32_t reg, CharDriverState *chardev) + uint32_t reg, CharDriverState *chardev, + qemu_irq qirq, uint32_t vio_irq_num) { DeviceState *dev; + VIOsPAPRDevice *sdev; dev = qdev_create(&bus->bus, "spapr-vty"); qdev_prop_set_uint32(dev, "reg", reg); qdev_prop_set_chr(dev, "chardev", chardev); qdev_init_nofail(dev); + sdev = (VIOsPAPRDevice *)dev; + sdev->qirq = qirq; + sdev->vio_irq_num = vio_irq_num; } static void vty_hcalls(VIOsPAPRBus *bus) From ee86dfeebb5c12372935374b32e796e5d2544c90 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:28 +1100 Subject: [PATCH 026/386] Implement TCE translation for sPAPR VIO This patch implements the necessary infrastructure and hypercalls for sPAPR's TCE (Translation Control Entry) IOMMU mechanism. This is necessary for all virtual IO devices which do DMA (i.e. nearly all of them). Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 3 +- hw/spapr_vio.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 32 +++++++ 3 files changed, 272 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index 859cf86011..f8749cc57d 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -65,7 +65,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; - char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"; + char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" + "\0hcall-tce"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 605079cda5..39d77ee28b 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -37,6 +37,7 @@ #endif /* CONFIG_FDT */ /* #define DEBUG_SPAPR */ +/* #define DEBUG_TCE */ #ifdef DEBUG_SPAPR #define dprintf(fmt, ...) \ @@ -115,6 +116,28 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } } + if (dev->rtce_window_size) { + uint32_t dma_prop[] = {cpu_to_be32(dev->reg), + 0, 0, + 0, cpu_to_be32(dev->rtce_window_size)}; + + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop, + sizeof(dma_prop)); + if (ret < 0) { + return ret; + } + } + if (info->devnode) { ret = (info->devnode)(dev, fdt, node_off); if (ret < 0) { @@ -126,6 +149,216 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } #endif /* CONFIG_FDT */ +/* + * RTCE handling + */ + +static void rtce_init(VIOsPAPRDevice *dev) +{ + size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT) + * sizeof(VIOsPAPR_RTCE); + + if (size) { + dev->rtce_table = qemu_mallocz(size); + } +} + +static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong liobn = args[0]; + target_ulong ioba = args[1]; + target_ulong tce = args[2]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn); + VIOsPAPR_RTCE *rtce; + + if (!dev) { + hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN " + TARGET_FMT_lx "\n", liobn); + return H_PARAMETER; + } + + ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1); + +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_vio_put_tce on %s ioba 0x" TARGET_FMT_lx + " TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce); +#endif + + if (ioba >= dev->rtce_window_size) { + hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" + TARGET_FMT_lx "\n", ioba); + return H_PARAMETER; + } + + rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT); + rtce->tce = tce; + + return H_SUCCESS; +} + +int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba, + target_ulong len, enum VIOsPAPR_TCEAccess access) +{ + int start, end, i; + + start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT; + end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT; + + for (i = start; i <= end; i++) { + if ((dev->rtce_table[i].tce & access) != access) { +#ifdef DEBUG_TCE + fprintf(stderr, "FAIL on %d\n", i); +#endif + return -1; + } + } + + return 0; +} + +int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf, + uint32_t size) +{ +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n", + (unsigned long long)taddr, size); +#endif + + while (size) { + uint64_t tce; + uint32_t lsize; + uint64_t txaddr; + + /* Check if we are in bound */ + if (taddr >= dev->rtce_window_size) { +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_dma_write out of bounds\n"); +#endif + return H_DEST_PARM; + } + tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce; + + /* How much til end of page ? */ + lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1); + + /* Check TCE */ + if (!(tce & 2)) { + return H_DEST_PARM; + } + + /* Translate */ + txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | + (taddr & SPAPR_VIO_TCE_PAGE_MASK); + +#ifdef DEBUG_TCE + fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n", + (unsigned long long)txaddr, lsize); +#endif + + /* Do it */ + cpu_physical_memory_write(txaddr, buf, lsize); + buf += lsize; + taddr += lsize; + size -= lsize; + } + return 0; +} + +int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size) +{ + /* FIXME: allocating a temp buffer is nasty, but just stepping + * through writing zeroes is awkward. This will do for now. */ + uint8_t zeroes[size]; + +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n", + (unsigned long long)taddr, size); +#endif + + memset(zeroes, 0, size); + return spapr_tce_dma_write(dev, taddr, zeroes, size); +} + +void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val) +{ + spapr_tce_dma_write(dev, taddr, &val, sizeof(val)); +} + +void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val) +{ + val = tswap16(val); + spapr_tce_dma_write(dev, taddr, &val, sizeof(val)); +} + + +void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val) +{ + val = tswap32(val); + spapr_tce_dma_write(dev, taddr, &val, sizeof(val)); +} + +void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val) +{ + val = tswap64(val); + spapr_tce_dma_write(dev, taddr, &val, sizeof(val)); +} + +int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf, + uint32_t size) +{ +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n", + (unsigned long long)taddr, size); +#endif + + while (size) { + uint64_t tce; + uint32_t lsize; + uint64_t txaddr; + + /* Check if we are in bound */ + if (taddr >= dev->rtce_window_size) { +#ifdef DEBUG_TCE + fprintf(stderr, "spapr_tce_dma_read out of bounds\n"); +#endif + return H_DEST_PARM; + } + tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce; + + /* How much til end of page ? */ + lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1); + + /* Check TCE */ + if (!(tce & 1)) { + return H_DEST_PARM; + } + + /* Translate */ + txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | + (taddr & SPAPR_VIO_TCE_PAGE_MASK); + +#ifdef DEBUG_TCE + fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n", + (unsigned long long)txaddr, lsize); +#endif + /* Do it */ + cpu_physical_memory_read(txaddr, buf, lsize); + buf += lsize; + taddr += lsize; + size -= lsize; + } + return H_SUCCESS; +} + +uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr) +{ + uint64_t val; + + spapr_tce_dma_read(dev, taddr, &val, sizeof(val)); + return tswap64(val); +} + static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; @@ -138,6 +371,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) dev->qdev.id = id; + rtce_init(dev); + return info->init(dev); } @@ -193,6 +428,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void) /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); + /* hcall-tce */ + spapr_register_hypercall(H_PUT_TCE, h_put_tce); + for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 20139273d3..9d864c20fe 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -21,12 +21,29 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#define SPAPR_VIO_TCE_PAGE_SHIFT 12 +#define SPAPR_VIO_TCE_PAGE_SIZE (1ULL << SPAPR_VIO_TCE_PAGE_SHIFT) +#define SPAPR_VIO_TCE_PAGE_MASK (SPAPR_VIO_TCE_PAGE_SIZE - 1) + +enum VIOsPAPR_TCEAccess { + SPAPR_TCE_FAULT = 0, + SPAPR_TCE_RO = 1, + SPAPR_TCE_WO = 2, + SPAPR_TCE_RW = 3, +}; + +typedef struct VIOsPAPR_RTCE { + uint64_t tce; +} VIOsPAPR_RTCE; + typedef struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; qemu_irq qirq; uint32_t vio_irq_num; target_ulong signal_state; + uint32_t rtce_window_size; + VIOsPAPR_RTCE *rtce_table; } VIOsPAPRDevice; typedef struct VIOsPAPRBus { @@ -49,6 +66,21 @@ extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); +int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba, + target_ulong len, + enum VIOsPAPR_TCEAccess access); + +int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, + void *buf, uint32_t size); +int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, + const void *buf, uint32_t size); +int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size); +void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val); +void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val); +void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val); +void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val); +uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr); + void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev, From 8d90ad900507e373a7aa26daacd51e0474760425 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:29 +1100 Subject: [PATCH 027/386] Implement sPAPR Virtual LAN (ibmveth) This patch implements the PAPR specified Inter Virtual Machine Logical LAN; that is the virtual hardware used by the Linux ibmveth driver. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile.target | 2 +- hw/spapr.c | 19 ++ hw/spapr_llan.c | 521 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 3 + 4 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 hw/spapr_llan.c diff --git a/Makefile.target b/Makefile.target index c79542842f..cd7bb41a95 100644 --- a/Makefile.target +++ b/Makefile.target @@ -234,7 +234,7 @@ obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o -obj-ppc-y += xics.o spapr_vty.o +obj-ppc-y += xics.o spapr_vty.o spapr_llan.o endif # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o diff --git a/hw/spapr.c b/hw/spapr.c index f8749cc57d..c7306d91a4 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -27,6 +27,7 @@ #include "sysemu.h" #include "hw.h" #include "elf.h" +#include "net.h" #include "hw/boards.h" #include "hw/ppc.h" @@ -334,6 +335,24 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } + for (i = 0; i < nb_nics; i++, irq++) { + NICInfo *nd = &nd_table[i]; + + if (!nd->model) { + nd->model = qemu_strdup("ibmveth"); + } + + if (strcmp(nd->model, "ibmveth") == 0) { + spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd, + xics_find_qirq(spapr->icp, irq), irq); + } else { + fprintf(stderr, "pSeries (sPAPR) platform does not support " + "NIC model '%s' (only ibmveth is supported)\n", + nd->model); + exit(1); + } + } + if (kernel_filename) { uint64_t lowaddr = 0; diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c new file mode 100644 index 0000000000..1d83fd58fd --- /dev/null +++ b/hw/spapr_llan.c @@ -0,0 +1,521 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Inter-VM Logical Lan, aka ibmveth + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * 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 "hw.h" +#include "net.h" +#include "hw/qdev.h" +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include <libfdt.h> + +#define ETH_ALEN 6 +#define MAX_PACKET_SIZE 65536 + +/*#define DEBUG*/ + +#ifdef DEBUG +#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0) +#else +#define dprintf(fmt...) +#endif + +/* + * Virtual LAN device + */ + +typedef uint64_t vlan_bd_t; + +#define VLAN_BD_VALID 0x8000000000000000ULL +#define VLAN_BD_TOGGLE 0x4000000000000000ULL +#define VLAN_BD_NO_CSUM 0x0200000000000000ULL +#define VLAN_BD_CSUM_GOOD 0x0100000000000000ULL +#define VLAN_BD_LEN_MASK 0x00ffffff00000000ULL +#define VLAN_BD_LEN(bd) (((bd) & VLAN_BD_LEN_MASK) >> 32) +#define VLAN_BD_ADDR_MASK 0x00000000ffffffffULL +#define VLAN_BD_ADDR(bd) ((bd) & VLAN_BD_ADDR_MASK) + +#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \ + (((len) << 32) & VLAN_BD_LEN_MASK) | \ + (addr & VLAN_BD_ADDR_MASK)) + +#define VLAN_RXQC_TOGGLE 0x80 +#define VLAN_RXQC_VALID 0x40 +#define VLAN_RXQC_NO_CSUM 0x02 +#define VLAN_RXQC_CSUM_GOOD 0x01 + +#define VLAN_RQ_ALIGNMENT 16 +#define VLAN_RXQ_BD_OFF 0 +#define VLAN_FILTER_BD_OFF 8 +#define VLAN_RX_BDS_OFF 16 +#define VLAN_MAX_BUFS ((SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8) + +typedef struct VIOsPAPRVLANDevice { + VIOsPAPRDevice sdev; + NICConf nicconf; + NICState *nic; + int isopen; + target_ulong buf_list; + int add_buf_ptr, use_buf_ptr, rx_bufs; + target_ulong rxq_ptr; +} VIOsPAPRVLANDevice; + +static int spapr_vlan_can_receive(VLANClientState *nc) +{ + VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque; + + return (dev->isopen && dev->rx_bufs > 0); +} + +static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf, + size_t size) +{ + VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque; + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + vlan_bd_t rxq_bd = ldq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF); + vlan_bd_t bd; + int buf_ptr = dev->use_buf_ptr; + uint64_t handle; + uint8_t control; + + dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id, + dev->rx_bufs); + + if (!dev->isopen) { + return -1; + } + + if (!dev->rx_bufs) { + return -1; + } + + do { + buf_ptr += 8; + if (buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) { + buf_ptr = VLAN_RX_BDS_OFF; + } + + bd = ldq_tce(sdev, dev->buf_list + buf_ptr); + dprintf("use_buf_ptr=%d bd=0x%016llx\n", + buf_ptr, (unsigned long long)bd); + } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) + && (buf_ptr != dev->use_buf_ptr)); + + if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) { + /* Failed to find a suitable buffer */ + return -1; + } + + /* Remove the buffer from the pool */ + dev->rx_bufs--; + dev->use_buf_ptr = buf_ptr; + stq_tce(sdev, dev->buf_list + dev->use_buf_ptr, 0); + + dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs); + + /* Transfer the packet data */ + if (spapr_tce_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) { + return -1; + } + + dprintf("spapr_vlan_receive: DMA write completed\n"); + + /* Update the receive queue */ + control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID; + if (rxq_bd & VLAN_BD_TOGGLE) { + control ^= VLAN_RXQC_TOGGLE; + } + + handle = ldq_tce(sdev, VLAN_BD_ADDR(bd)); + stq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle); + stw_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size); + sth_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8); + stb_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control); + + dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n", + (unsigned long long)dev->rxq_ptr, + (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr), + (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr + 8)); + + dev->rxq_ptr += 16; + if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) { + dev->rxq_ptr = 0; + stq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE); + } + + if (sdev->signal_state & 1) { + qemu_irq_pulse(sdev->qirq); + } + + return size; +} + +static NetClientInfo net_spapr_vlan_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = spapr_vlan_can_receive, + .receive = spapr_vlan_receive, +}; + +static int spapr_vlan_init(VIOsPAPRDevice *sdev) +{ + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + VIOsPAPRBus *bus; + + bus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus); + + qemu_macaddr_default_if_unset(&dev->nicconf.macaddr); + + dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, + sdev->qdev.info->name, sdev->qdev.id, dev); + qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a); + + return 0; +} + +void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd, + qemu_irq qirq, uint32_t vio_irq_num) +{ + DeviceState *dev; + VIOsPAPRDevice *sdev; + + dev = qdev_create(&bus->bus, "spapr-vlan"); + qdev_prop_set_uint32(dev, "reg", reg); + + qdev_set_nic_properties(dev, nd); + + qdev_init_nofail(dev); + sdev = (VIOsPAPRDevice *)dev; + sdev->qirq = qirq; + sdev->vio_irq_num = vio_irq_num; +} + +static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) +{ + VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev; + uint8_t padded_mac[8] = {0, 0}; + int ret; + + /* Some old phyp versions give the mac address in an 8-byte + * property. The kernel driver has an insane workaround for this; + * rather than doing the obvious thing and checking the property + * length, it checks whether the first byte has 0b10 in the low + * bits. If a correct 6-byte property has a different first byte + * the kernel will get the wrong mac address, overrunning its + * buffer in the process (read only, thank goodness). + * + * Here we workaround the kernel workaround by always supplying an + * 8-byte property, with the mac address in the last six bytes */ + memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN); + ret = fdt_setprop(fdt, node_off, "local-mac-address", + padded_mac, sizeof(padded_mac)); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd, + target_ulong alignment) +{ + if ((VLAN_BD_ADDR(bd) % alignment) + || (VLAN_BD_LEN(bd) % alignment)) { + return -1; + } + + if (spapr_vio_check_tces(&dev->sdev, VLAN_BD_ADDR(bd), + VLAN_BD_LEN(bd), SPAPR_TCE_RW) != 0) { + return -1; + } + + return 0; +} + +static target_ulong h_register_logical_lan(CPUState *env, + sPAPREnvironment *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong buf_list = args[1]; + target_ulong rec_queue = args[2]; + target_ulong filter_list = args[3]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + vlan_bd_t filter_list_bd; +#ifdef DEBUG + target_ulong mac_address = args[4]; +#endif + + if (!dev) { + return H_PARAMETER; + } + + if (dev->isopen) { + hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without " + "H_FREE_LOGICAL_LAN\n"); + return H_RESOURCE; + } + + if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE), + SPAPR_VIO_TCE_PAGE_SIZE) < 0) { + hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for " + "H_REGISTER_LOGICAL_LAN\n", buf_list); + return H_PARAMETER; + } + + filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE); + if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) { + hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for " + "H_REGISTER_LOGICAL_LAN\n", filter_list); + return H_PARAMETER; + } + + if (!(rec_queue & VLAN_BD_VALID) + || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) { + hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n"); + return H_PARAMETER; + } + + dev->buf_list = buf_list; + sdev->signal_state = 0; + + rec_queue &= ~VLAN_BD_TOGGLE; + + /* Initialize the buffer list */ + stq_tce(sdev, buf_list, rec_queue); + stq_tce(sdev, buf_list + 8, filter_list_bd); + spapr_tce_dma_zero(sdev, buf_list + VLAN_RX_BDS_OFF, + SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF); + dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8; + dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8; + dev->rx_bufs = 0; + dev->rxq_ptr = 0; + + /* Initialize the receive queue */ + spapr_tce_dma_zero(sdev, VLAN_BD_ADDR(rec_queue), VLAN_BD_LEN(rec_queue)); + + dev->isopen = 1; + return H_SUCCESS; +} + + +static target_ulong h_free_logical_lan(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + + if (!dev) { + return H_PARAMETER; + } + + if (!dev->isopen) { + hcall_dprintf("H_FREE_LOGICAL_LAN called without " + "H_REGISTER_LOGICAL_LAN\n"); + return H_RESOURCE; + } + + dev->buf_list = 0; + dev->rx_bufs = 0; + dev->isopen = 0; + return H_SUCCESS; +} + +static target_ulong h_add_logical_lan_buffer(CPUState *env, + sPAPREnvironment *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong buf = args[1]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + vlan_bd_t bd; + + dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx + ", 0x" TARGET_FMT_lx ")\n", reg, buf); + + if (!sdev) { + hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n"); + return H_PARAMETER; + } + + if ((check_bd(dev, buf, 4) < 0) + || (VLAN_BD_LEN(buf) < 16)) { + hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n"); + return H_PARAMETER; + } + + if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) { + return H_RESOURCE; + } + + do { + dev->add_buf_ptr += 8; + if (dev->add_buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) { + dev->add_buf_ptr = VLAN_RX_BDS_OFF; + } + + bd = ldq_tce(sdev, dev->buf_list + dev->add_buf_ptr); + } while (bd & VLAN_BD_VALID); + + stq_tce(sdev, dev->buf_list + dev->add_buf_ptr, buf); + + dev->rx_bufs++; + + dprintf("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d" + " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs, + (unsigned long long)buf); + + return H_SUCCESS; +} + +static target_ulong h_send_logical_lan(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong *bufs = args + 1; + target_ulong continue_token = args[7]; + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; + unsigned total_len; + uint8_t *lbuf, *p; + int i, nbufs; + int ret; + + dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x" + TARGET_FMT_lx ")\n", reg, continue_token); + + if (!sdev) { + return H_PARAMETER; + } + + dprintf("rxbufs = %d\n", dev->rx_bufs); + + if (!dev->isopen) { + return H_DROPPED; + } + + if (continue_token) { + return H_HARDWARE; /* FIXME actually handle this */ + } + + total_len = 0; + for (i = 0; i < 6; i++) { + dprintf(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]); + if (!(bufs[i] & VLAN_BD_VALID)) { + break; + } + total_len += VLAN_BD_LEN(bufs[i]); + } + + nbufs = i; + dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n", + nbufs, total_len); + + if (total_len == 0) { + return H_SUCCESS; + } + + if (total_len > MAX_PACKET_SIZE) { + /* Don't let the guest force too large an allocation */ + return H_RESOURCE; + } + + lbuf = alloca(total_len); + p = lbuf; + for (i = 0; i < nbufs; i++) { + ret = spapr_tce_dma_read(sdev, VLAN_BD_ADDR(bufs[i]), + p, VLAN_BD_LEN(bufs[i])); + if (ret < 0) { + return ret; + } + + p += VLAN_BD_LEN(bufs[i]); + } + + qemu_send_packet(&dev->nic->nc, lbuf, total_len); + + return H_SUCCESS; +} + +static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + return H_PARAMETER; + } + + return H_SUCCESS; +} + +static void vlan_hcalls(VIOsPAPRBus *bus) +{ + spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan); + spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan); + spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan); + spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, + h_add_logical_lan_buffer); + spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl); +} + +static VIOsPAPRDeviceInfo spapr_vlan = { + .init = spapr_vlan_init, + .devnode = spapr_vlan_devnode, + .dt_name = "l-lan", + .dt_type = "network", + .dt_compatible = "IBM,l-lan", + .signal_mask = 0x1, + .hcalls = vlan_hcalls, + .qdev.name = "spapr-vlan", + .qdev.size = sizeof(VIOsPAPRVLANDevice), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000), + DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size, + 0x10000000), + DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void spapr_vlan_register(void) +{ + spapr_vio_bus_register_withprop(&spapr_vlan); +} +device_init(spapr_vlan_register); diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 9d864c20fe..4cfaf55bd8 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -86,4 +86,7 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev, qemu_irq qirq, uint32_t vio_irq_num); +void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd, + qemu_irq qirq, uint32_t vio_irq_num); + #endif /* _HW_SPAPR_VIO_H */ From b45d63b62f0c05eb54bba0fafaf29b9b3f4dd99a Mon Sep 17 00:00:00 2001 From: Ben Herrenschmidt <benh@kernel.crashing.org> Date: Fri, 1 Apr 2011 15:15:30 +1100 Subject: [PATCH 028/386] Implement PAPR CRQ hypercalls This patch implements the infrastructure and hypercalls necessary for the PAPR specified CRQ (Command Request Queue) mechanism. This general request queueing system is used by many of the PAPR virtual IO devices, including the virtual scsi adapter. Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 2 +- hw/spapr_vio.c | 160 +++++++++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 12 ++++ target-ppc/kvm_ppc.h | 11 +++ 4 files changed, 184 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index c7306d91a4..b432a9dcee 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -67,7 +67,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" - "\0hcall-tce"; + "\0hcall-tce\0hcall-vio"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 39d77ee28b..8f14fcc794 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -28,6 +28,7 @@ #include "hw/sysbus.h" #include "kvm.h" #include "device_tree.h" +#include "kvm_ppc.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" @@ -359,6 +360,159 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr) return tswap64(val); } +/* + * CRQ handling + */ +static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong queue_addr = args[1]; + target_ulong queue_len = args[2]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("h_reg_crq on non-existent unit 0x" + TARGET_FMT_lx "\n", reg); + return H_PARAMETER; + } + + /* We can't grok a queue size bigger than 256M for now */ + if (queue_len < 0x1000 || queue_len > 0x10000000) { + hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n", + (unsigned long long)queue_len); + return H_PARAMETER; + } + + /* Check queue alignment */ + if (queue_addr & 0xfff) { + hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n", + (unsigned long long)queue_addr); + return H_PARAMETER; + } + + /* Check if device supports CRQs */ + if (!dev->crq.SendFunc) { + return H_NOT_FOUND; + } + + + /* Already a queue ? */ + if (dev->crq.qsize) { + return H_RESOURCE; + } + dev->crq.qladdr = queue_addr; + dev->crq.qsize = queue_len; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" + TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", + reg, queue_addr, queue_len); + return H_SUCCESS; +} + +static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("h_free_crq on non-existent unit 0x" + TARGET_FMT_lx "\n", reg); + return H_PARAMETER; + } + + dev->crq.qladdr = 0; + dev->crq.qsize = 0; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg); + + return H_SUCCESS; +} + +static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + target_ulong msg_hi = args[1]; + target_ulong msg_lo = args[2]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + uint64_t crq_mangle[2]; + + if (!dev) { + hcall_dprintf("h_send_crq on non-existent unit 0x" + TARGET_FMT_lx "\n", reg); + return H_PARAMETER; + } + crq_mangle[0] = cpu_to_be64(msg_hi); + crq_mangle[1] = cpu_to_be64(msg_lo); + + if (dev->crq.SendFunc) { + return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); + } + + return H_HARDWARE; +} + +static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong reg = args[0]; + VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); + + if (!dev) { + hcall_dprintf("h_enable_crq on non-existent unit 0x" + TARGET_FMT_lx "\n", reg); + return H_PARAMETER; + } + + return 0; +} + +/* Returns negative error, 0 success, or positive: queue full */ +int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) +{ + int rc; + uint8_t byte; + + if (!dev->crq.qsize) { + fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n"); + return -1; + } + + /* Maybe do a fast path for KVM just writing to the pages */ + rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); + if (rc) { + return rc; + } + if (byte != 0) { + return 1; + } + + rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, + &crq[8], 8); + if (rc) { + return rc; + } + + kvmppc_eieio(); + + rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); + if (rc) { + return rc; + } + + dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; + + if (dev->signal_state & 1) { + qemu_irq_pulse(dev->qirq); + } + + return 0; +} + static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; @@ -431,6 +585,12 @@ VIOsPAPRBus *spapr_vio_bus_init(void) /* hcall-tce */ spapr_register_hypercall(H_PUT_TCE, h_put_tce); + /* hcall-crq */ + spapr_register_hypercall(H_REG_CRQ, h_reg_crq); + spapr_register_hypercall(H_FREE_CRQ, h_free_crq); + spapr_register_hypercall(H_SEND_CRQ, h_send_crq); + spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); + for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 4cfaf55bd8..ba16795c37 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -32,10 +32,19 @@ enum VIOsPAPR_TCEAccess { SPAPR_TCE_RW = 3, }; +struct VIOsPAPRDevice; + typedef struct VIOsPAPR_RTCE { uint64_t tce; } VIOsPAPR_RTCE; +typedef struct VIOsPAPR_CRQ { + uint64_t qladdr; + uint32_t qsize; + uint32_t qnext; + int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq); +} VIOsPAPR_CRQ; + typedef struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; @@ -44,6 +53,7 @@ typedef struct VIOsPAPRDevice { target_ulong signal_state; uint32_t rtce_window_size; VIOsPAPR_RTCE *rtce_table; + VIOsPAPR_CRQ crq; } VIOsPAPRDevice; typedef struct VIOsPAPRBus { @@ -81,6 +91,8 @@ void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val); void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val); uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr); +int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq); + void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev, diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 911b19e378..5afb308477 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -18,6 +18,17 @@ uint32_t kvmppc_get_tbfreq(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); +#ifndef CONFIG_KVM +#define kvmppc_eieio() do { } while (0) +#else +#define kvmppc_eieio() \ + do { \ + if (kvm_enabled()) { \ + asm volatile("eieio" : : : "memory"); \ + } \ + } while (0) +#endif + #ifndef KVM_INTERRUPT_SET #define KVM_INTERRUPT_SET -1 #endif From 6e270446d0e107b5227d8c51d2f85546f8811e99 Mon Sep 17 00:00:00 2001 From: Ben Herrenschmidt <benh@kernel.crashing.org> Date: Fri, 1 Apr 2011 15:15:31 +1100 Subject: [PATCH 029/386] Implement PAPR virtual SCSI interface (ibmvscsi) This patch implements the infrastructure and hypercalls necessary for the PAPR specified Virtual SCSI interface. This is the normal method for providing (virtual) disks to PAPR partitions. Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- Makefile.target | 2 +- hw/ppc-viosrp.h | 216 +++++++++++ hw/spapr.c | 8 + hw/spapr_vio.h | 3 + hw/spapr_vscsi.c | 988 +++++++++++++++++++++++++++++++++++++++++++++++ hw/srp.h | 240 ++++++++++++ 6 files changed, 1456 insertions(+), 1 deletion(-) create mode 100644 hw/ppc-viosrp.h create mode 100644 hw/spapr_vscsi.c create mode 100644 hw/srp.h diff --git a/Makefile.target b/Makefile.target index cd7bb41a95..565e1fbd04 100644 --- a/Makefile.target +++ b/Makefile.target @@ -234,7 +234,7 @@ obj-ppc-y += ppc_newworld.o # IBM pSeries (sPAPR) ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy) obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o -obj-ppc-y += xics.o spapr_vty.o spapr_llan.o +obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o endif # PowerPC 4xx boards obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o diff --git a/hw/ppc-viosrp.h b/hw/ppc-viosrp.h new file mode 100644 index 0000000000..d8e365db1e --- /dev/null +++ b/hw/ppc-viosrp.h @@ -0,0 +1,216 @@ +/*****************************************************************************/ +/* srp.h -- SCSI RDMA Protocol definitions */ +/* */ +/* Written By: Colin Devilbis, IBM Corporation */ +/* */ +/* Copyright (C) 2003 IBM Corporation */ +/* */ +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* */ +/* This file contains structures and definitions for IBM RPA (RS/6000 */ +/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */ +/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */ +/* commands between logical partitions. */ +/* */ +/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */ +/* between partitions. The definitions in this file are architected, */ +/* and cannot be changed without breaking compatibility with other versions */ +/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/ +/* between logical partitions */ +/*****************************************************************************/ +#ifndef PPC_VIOSRP_H +#define PPC_VIOSRP_H + +#define SRP_VERSION "16.a" +#define SRP_MAX_IU_LEN 256 +#define SRP_MAX_LOC_LEN 32 + +union srp_iu { + struct srp_login_req login_req; + struct srp_login_rsp login_rsp; + struct srp_login_rej login_rej; + struct srp_i_logout i_logout; + struct srp_t_logout t_logout; + struct srp_tsk_mgmt tsk_mgmt; + struct srp_cmd cmd; + struct srp_rsp rsp; + uint8_t reserved[SRP_MAX_IU_LEN]; +}; + +enum viosrp_crq_formats { + VIOSRP_SRP_FORMAT = 0x01, + VIOSRP_MAD_FORMAT = 0x02, + VIOSRP_OS400_FORMAT = 0x03, + VIOSRP_AIX_FORMAT = 0x04, + VIOSRP_LINUX_FORMAT = 0x06, + VIOSRP_INLINE_FORMAT = 0x07 +}; + +enum viosrp_crq_status { + VIOSRP_OK = 0x0, + VIOSRP_NONRECOVERABLE_ERR = 0x1, + VIOSRP_VIOLATES_MAX_XFER = 0x2, + VIOSRP_PARTNER_PANIC = 0x3, + VIOSRP_DEVICE_BUSY = 0x8, + VIOSRP_ADAPTER_FAIL = 0x10, + VIOSRP_OK2 = 0x99, +}; + +struct viosrp_crq { + uint8_t valid; /* used by RPA */ + uint8_t format; /* SCSI vs out-of-band */ + uint8_t reserved; + uint8_t status; /* non-scsi failure? (e.g. DMA failure) */ + uint16_t timeout; /* in seconds */ + uint16_t IU_length; /* in bytes */ + uint64_t IU_data_ptr; /* the TCE for transferring data */ +}; + +/* MADs are Management requests above and beyond the IUs defined in the SRP + * standard. + */ +enum viosrp_mad_types { + VIOSRP_EMPTY_IU_TYPE = 0x01, + VIOSRP_ERROR_LOG_TYPE = 0x02, + VIOSRP_ADAPTER_INFO_TYPE = 0x03, + VIOSRP_HOST_CONFIG_TYPE = 0x04, + VIOSRP_CAPABILITIES_TYPE = 0x05, + VIOSRP_ENABLE_FAST_FAIL = 0x08, +}; + +enum viosrp_mad_status { + VIOSRP_MAD_SUCCESS = 0x00, + VIOSRP_MAD_NOT_SUPPORTED = 0xF1, + VIOSRP_MAD_FAILED = 0xF7, +}; + +enum viosrp_capability_type { + MIGRATION_CAPABILITIES = 0x01, + RESERVATION_CAPABILITIES = 0x02, +}; + +enum viosrp_capability_support { + SERVER_DOES_NOT_SUPPORTS_CAP = 0x0, + SERVER_SUPPORTS_CAP = 0x01, + SERVER_CAP_DATA = 0x02, +}; + +enum viosrp_reserve_type { + CLIENT_RESERVE_SCSI_2 = 0x01, +}; + +enum viosrp_capability_flag { + CLIENT_MIGRATED = 0x01, + CLIENT_RECONNECT = 0x02, + CAP_LIST_SUPPORTED = 0x04, + CAP_LIST_DATA = 0x08, +}; + +/* + * Common MAD header + */ +struct mad_common { + uint32_t type; + uint16_t status; + uint16_t length; + uint64_t tag; +}; + +/* + * All SRP (and MAD) requests normally flow from the + * client to the server. There is no way for the server to send + * an asynchronous message back to the client. The Empty IU is used + * to hang out a meaningless request to the server so that it can respond + * asynchrouously with something like a SCSI AER + */ +struct viosrp_empty_iu { + struct mad_common common; + uint64_t buffer; + uint32_t port; +}; + +struct viosrp_error_log { + struct mad_common common; + uint64_t buffer; +}; + +struct viosrp_adapter_info { + struct mad_common common; + uint64_t buffer; +}; + +struct viosrp_host_config { + struct mad_common common; + uint64_t buffer; +}; + +struct viosrp_fast_fail { + struct mad_common common; +}; + +struct viosrp_capabilities { + struct mad_common common; + uint64_t buffer; +}; + +struct mad_capability_common { + uint32_t cap_type; + uint16_t length; + uint16_t server_support; +}; + +struct mad_reserve_cap { + struct mad_capability_common common; + uint32_t type; +}; + +struct mad_migration_cap { + struct mad_capability_common common; + uint32_t ecl; +}; + +struct capabilities { + uint32_t flags; + char name[SRP_MAX_LOC_LEN]; + char loc[SRP_MAX_LOC_LEN]; + struct mad_migration_cap migration; + struct mad_reserve_cap reserve; +}; + +union mad_iu { + struct viosrp_empty_iu empty_iu; + struct viosrp_error_log error_log; + struct viosrp_adapter_info adapter_info; + struct viosrp_host_config host_config; + struct viosrp_fast_fail fast_fail; + struct viosrp_capabilities capabilities; +}; + +union viosrp_iu { + union srp_iu srp; + union mad_iu mad; +}; + +struct mad_adapter_info_data { + char srp_version[8]; + char partition_name[96]; + uint32_t partition_number; + uint32_t mad_version; + uint32_t os_type; + uint32_t port_max_txu[8]; /* per-port maximum transfer */ +}; + +#endif diff --git a/hw/spapr.c b/hw/spapr.c index b432a9dcee..3bffaabe86 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -28,6 +28,7 @@ #include "hw.h" #include "elf.h" #include "net.h" +#include "blockdev.h" #include "hw/boards.h" #include "hw/ppc.h" @@ -353,6 +354,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } + for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) { + spapr_vscsi_create(spapr->vio_bus, 0x2000 + i, + xics_find_qirq(spapr->icp, irq), irq); + irq++; + } + if (kernel_filename) { uint64_t lowaddr = 0; @@ -411,6 +418,7 @@ static QEMUMachine spapr_machine = { .max_cpus = MAX_CPUS, .no_vga = 1, .no_parallel = 1, + .use_scsi = 1, }; static void spapr_machine_init(void) diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index ba16795c37..b7d0daab07 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -101,4 +101,7 @@ void spapr_vty_create(VIOsPAPRBus *bus, void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd, qemu_irq qirq, uint32_t vio_irq_num); +void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg, + qemu_irq qirq, uint32_t vio_irq_num); + #endif /* _HW_SPAPR_VIO_H */ diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c new file mode 100644 index 0000000000..e142dae624 --- /dev/null +++ b/hw/spapr_vscsi.c @@ -0,0 +1,988 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtual SCSI, aka ibmvscsi + * + * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation. + * + * 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. + * + * TODO: + * + * - Cleanups :-) + * - Sort out better how to assign devices to VSCSI instances + * - Fix residual counts + * - Add indirect descriptors support + * - Maybe do autosense (PAPR seems to mandate it, linux doesn't care) + */ +#include "hw.h" +#include "scsi.h" +#include "scsi-defs.h" +#include "net.h" /* Remove that when we can */ +#include "srp.h" +#include "hw/qdev.h" +#include "hw/spapr.h" +#include "hw/spapr_vio.h" +#include "hw/ppc-viosrp.h" + +#include <libfdt.h> + +/*#define DEBUG_VSCSI*/ + +#ifdef DEBUG_VSCSI +#define dprintf(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define dprintf(fmt, ...) \ + do { } while (0) +#endif + +/* + * Virtual SCSI device + */ + +/* Random numbers */ +#define VSCSI_MAX_SECTORS 4096 +#define VSCSI_REQ_LIMIT 24 + +#define SCSI_SENSE_BUF_SIZE 96 +#define SRP_RSP_SENSE_DATA_LEN 18 + +typedef union vscsi_crq { + struct viosrp_crq s; + uint8_t raw[16]; +} vscsi_crq; + +typedef struct vscsi_req { + vscsi_crq crq; + union viosrp_iu iu; + + /* SCSI request tracking */ + SCSIDevice *sdev; + uint32_t qtag; /* qemu tag != srp tag */ + int lun; + int active; + long data_len; + int writing; + int sensing; + int senselen; + uint8_t sense[SCSI_SENSE_BUF_SIZE]; + + /* RDMA related bits */ + uint8_t dma_fmt; + struct srp_direct_buf ext_desc; + struct srp_direct_buf *cur_desc; + struct srp_indirect_buf *ind_desc; + int local_desc; + int total_desc; +} vscsi_req; + + +typedef struct { + VIOsPAPRDevice vdev; + SCSIBus bus; + vscsi_req reqs[VSCSI_REQ_LIMIT]; +} VSCSIState; + +/* XXX Debug only */ +static VSCSIState *dbg_vscsi_state; + + +static struct vscsi_req *vscsi_get_req(VSCSIState *s) +{ + vscsi_req *req; + int i; + + for (i = 0; i < VSCSI_REQ_LIMIT; i++) { + req = &s->reqs[i]; + if (!req->active) { + memset(req, 0, sizeof(*req)); + req->qtag = i; + req->active = 1; + return req; + } + } + return NULL; +} + +static void vscsi_put_req(VSCSIState *s, vscsi_req *req) +{ + req->active = 0; +} + +static vscsi_req *vscsi_find_req(VSCSIState *s, uint32_t tag) +{ + if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) { + return NULL; + } + return &s->reqs[tag]; +} + +static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun) +{ + /* XXX Figure that one out properly ! This is crackpot */ + *id = (srp_lun >> 56) & 0x7f; + *lun = (srp_lun >> 48) & 0xff; +} + +static int vscsi_send_iu(VSCSIState *s, vscsi_req *req, + uint64_t length, uint8_t format) +{ + long rc, rc1; + + /* First copy the SRP */ + rc = spapr_tce_dma_write(&s->vdev, req->crq.s.IU_data_ptr, + &req->iu, length); + if (rc) { + fprintf(stderr, "vscsi_send_iu: DMA write failure !\n"); + } + + req->crq.s.valid = 0x80; + req->crq.s.format = format; + req->crq.s.reserved = 0x00; + req->crq.s.timeout = cpu_to_be16(0x0000); + req->crq.s.IU_length = cpu_to_be16(length); + req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */ + + if (rc == 0) { + req->crq.s.status = 0x99; /* Just needs to be non-zero */ + } else { + req->crq.s.status = 0x00; + } + + rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw); + if (rc1) { + fprintf(stderr, "vscsi_send_iu: Error sending response\n"); + return rc1; + } + + return rc; +} + +static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req, + uint8_t key, uint8_t asc, uint8_t ascq) +{ + req->senselen = SRP_RSP_SENSE_DATA_LEN; + + /* Valid bit and 'current errors' */ + req->sense[0] = (0x1 << 7 | 0x70); + /* Sense key */ + req->sense[2] = key; + /* Additional sense length */ + req->sense[7] = 0xa; /* 10 bytes */ + /* Additional sense code */ + req->sense[12] = asc; + req->sense[13] = ascq; +} + +static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, + uint8_t status, int32_t res_in, int32_t res_out) +{ + union viosrp_iu *iu = &req->iu; + uint64_t tag = iu->srp.rsp.tag; + int total_len = sizeof(iu->srp.rsp); + + dprintf("VSCSI: Sending resp status: 0x%x, " + "res_in: %d, res_out: %d\n", status, res_in, res_out); + + memset(iu, 0, sizeof(struct srp_rsp)); + iu->srp.rsp.opcode = SRP_RSP; + iu->srp.rsp.req_lim_delta = cpu_to_be32(1); + iu->srp.rsp.tag = tag; + + /* Handle residuals */ + if (res_in < 0) { + iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER; + res_in = -res_in; + } else if (res_in) { + iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER; + } + if (res_out < 0) { + iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER; + res_out = -res_out; + } else if (res_out) { + iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER; + } + iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in); + iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out); + + /* We don't do response data */ + /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */ + iu->srp.rsp.resp_data_len = cpu_to_be32(0); + + /* Handle success vs. failure */ + iu->srp.rsp.status = status; + if (status) { + iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2; + if (req->senselen) { + req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen); + memcpy(req->iu.srp.rsp.data, req->sense, req->senselen); + total_len += req->senselen; + } + } else { + iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1; + } + + vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT); + return 0; +} + +static inline void vscsi_swap_desc(struct srp_direct_buf *desc) +{ + desc->va = be64_to_cpu(desc->va); + desc->len = be32_to_cpu(desc->len); +} + +static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req, + uint8_t *buf, uint32_t len) +{ + struct srp_direct_buf *md = req->cur_desc; + uint32_t llen; + int rc; + + dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n", + len, (unsigned long long)md->va, md->len); + + llen = MIN(len, md->len); + if (llen) { + if (req->writing) { /* writing = to device = reading from memory */ + rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen); + } else { + rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen); + } + } + md->len -= llen; + md->va += llen; + + if (rc) { + return -1; + } + return llen; +} + +static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, + uint8_t *buf, uint32_t len) +{ + struct srp_direct_buf *td = &req->ind_desc->table_desc; + struct srp_direct_buf *md = req->cur_desc; + int rc = 0; + uint32_t llen, total = 0; + + dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n", + len, (unsigned long long)td->va, td->len); + + /* While we have data ... */ + while (len) { + /* If we have a descriptor but it's empty, go fetch a new one */ + if (md && md->len == 0) { + /* More local available, use one */ + if (req->local_desc) { + md = ++req->cur_desc; + --req->local_desc; + --req->total_desc; + td->va += sizeof(struct srp_direct_buf); + } else { + md = req->cur_desc = NULL; + } + } + /* No descriptor at hand, fetch one */ + if (!md) { + if (!req->total_desc) { + dprintf("VSCSI: Out of descriptors !\n"); + break; + } + md = req->cur_desc = &req->ext_desc; + dprintf("VSCSI: Reading desc from 0x%llx\n", + (unsigned long long)td->va); + rc = spapr_tce_dma_read(&s->vdev, td->va, md, + sizeof(struct srp_direct_buf)); + if (rc) { + dprintf("VSCSI: tce_dma_read -> %d reading ext_desc\n", rc); + break; + } + vscsi_swap_desc(md); + td->va += sizeof(struct srp_direct_buf); + --req->total_desc; + } + dprintf("VSCSI: [desc va=0x%llx,len=0x%x] remaining=0x%x\n", + (unsigned long long)md->va, md->len, len); + + /* Perform transfer */ + llen = MIN(len, md->len); + if (req->writing) { /* writing = to device = reading from memory */ + rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen); + } else { + rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen); + } + if (rc) { + dprintf("VSCSI: tce_dma_r/w(%d) -> %d\n", req->writing, rc); + break; + } + dprintf("VSCSI: data: %02x %02x %02x %02x...\n", + buf[0], buf[1], buf[2], buf[3]); + + len -= llen; + buf += llen; + total += llen; + md->va += llen; + md->len -= llen; + } + return rc ? -1 : total; +} + +static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req, + int writing, uint8_t *buf, uint32_t len) +{ + int err = 0; + + switch (req->dma_fmt) { + case SRP_NO_DATA_DESC: + dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); + break; + case SRP_DATA_DESC_DIRECT: + err = vscsi_srp_direct_data(s, req, buf, len); + break; + case SRP_DATA_DESC_INDIRECT: + err = vscsi_srp_indirect_data(s, req, buf, len); + break; + } + return err; +} + +/* Bits from linux srp */ +static int data_out_desc_size(struct srp_cmd *cmd) +{ + int size = 0; + uint8_t fmt = cmd->buf_fmt >> 4; + + switch (fmt) { + case SRP_NO_DATA_DESC: + break; + case SRP_DATA_DESC_DIRECT: + size = sizeof(struct srp_direct_buf); + break; + case SRP_DATA_DESC_INDIRECT: + size = sizeof(struct srp_indirect_buf) + + sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt; + break; + default: + break; + } + return size; +} + +static int vscsi_preprocess_desc(vscsi_req *req) +{ + struct srp_cmd *cmd = &req->iu.srp.cmd; + int offset, i; + + offset = cmd->add_cdb_len & ~3; + + if (req->writing) { + req->dma_fmt = cmd->buf_fmt >> 4; + } else { + offset += data_out_desc_size(cmd); + req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1); + } + + switch (req->dma_fmt) { + case SRP_NO_DATA_DESC: + break; + case SRP_DATA_DESC_DIRECT: + req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset); + req->total_desc = req->local_desc = 1; + vscsi_swap_desc(req->cur_desc); + dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n", + req->writing ? "write" : "read", + req->cur_desc->len, (unsigned long long)req->cur_desc->va); + break; + case SRP_DATA_DESC_INDIRECT: + req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset); + vscsi_swap_desc(&req->ind_desc->table_desc); + req->total_desc = req->ind_desc->table_desc.len / + sizeof(struct srp_direct_buf); + req->local_desc = req->writing ? cmd->data_out_desc_cnt : + cmd->data_in_desc_cnt; + for (i = 0; i < req->local_desc; i++) { + vscsi_swap_desc(&req->ind_desc->desc_list[i]); + } + req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL; + dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs " + "(%d local) VA: 0x%llx\n", + req->writing ? "read" : "write", + be32_to_cpu(req->ind_desc->len), + req->total_desc, req->local_desc, + (unsigned long long)req->ind_desc->table_desc.va); + break; + default: + fprintf(stderr, + "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt); + return -1; + } + + return 0; +} + +static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) +{ + SCSIDevice *sdev = req->sdev; + uint8_t *cdb = req->iu.srp.cmd.cdb; + int n; + + cdb[0] = 3; + cdb[1] = 0; + cdb[2] = 0; + cdb[3] = 0; + cdb[4] = 96; + cdb[5] = 0; + req->sensing = 1; + n = sdev->info->send_command(sdev, req->qtag, cdb, req->lun); + dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); + if (n < 0) { + fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); + sdev->info->cancel_io(sdev, req->qtag); + vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + vscsi_put_req(s, req); + return; + } else if (n == 0) { + return; + } + sdev->info->read_data(sdev, req->qtag); +} + +/* Callback to indicate that the SCSI layer has completed a transfer. */ +static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, + uint32_t arg) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, bus->qbus.parent); + vscsi_req *req = vscsi_find_req(s, tag); + SCSIDevice *sdev; + uint8_t *buf; + int32_t res_in = 0, res_out = 0; + int len, rc = 0; + + dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", + reason, tag, arg, req); + if (req == NULL) { + fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", tag); + return; + } + sdev = req->sdev; + + if (req->sensing) { + if (reason == SCSI_REASON_DONE) { + dprintf("VSCSI: Sense done !\n"); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + vscsi_put_req(s, req); + } else { + uint8_t *buf = sdev->info->get_buf(sdev, tag); + + len = MIN(arg, SCSI_SENSE_BUF_SIZE); + dprintf("VSCSI: Sense data, %d bytes:\n", len); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + memcpy(req->sense, buf, len); + req->senselen = len; + sdev->info->read_data(sdev, req->qtag); + } + return; + } + + if (reason == SCSI_REASON_DONE) { + dprintf("VSCSI: Command complete err=%d\n", arg); + if (arg == 0) { + /* We handle overflows, not underflows for normal commands, + * but hopefully nobody cares + */ + if (req->writing) { + res_out = req->data_len; + } else { + res_in = req->data_len; + } + vscsi_send_rsp(s, req, 0, res_in, res_out); + } else if (arg == CHECK_CONDITION) { + dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n"); + vscsi_send_request_sense(s, req); + return; + } else { + vscsi_send_rsp(s, req, arg, 0, 0); + } + vscsi_put_req(s, req); + return; + } + + /* "arg" is how much we have read for reads and how much we want + * to write for writes (ie, how much is to be DMA'd) + */ + if (arg) { + buf = sdev->info->get_buf(sdev, tag); + rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); + } + if (rc < 0) { + fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); + sdev->info->cancel_io(sdev, req->qtag); + vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + vscsi_put_req(s, req); + return; + } + + /* Start next chunk */ + req->data_len -= rc; + if (req->writing) { + sdev->info->write_data(sdev, req->qtag); + } else { + sdev->info->read_data(sdev, req->qtag); + } +} + +static void vscsi_process_login(VSCSIState *s, vscsi_req *req) +{ + union viosrp_iu *iu = &req->iu; + struct srp_login_rsp *rsp = &iu->srp.login_rsp; + uint64_t tag = iu->srp.rsp.tag; + + dprintf("VSCSI: Got login, sendin response !\n"); + + /* TODO handle case that requested size is wrong and + * buffer format is wrong + */ + memset(iu, 0, sizeof(struct srp_login_rsp)); + rsp->opcode = SRP_LOGIN_RSP; + /* Don't advertise quite as many request as we support to + * keep room for management stuff etc... + */ + rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2); + rsp->tag = tag; + rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu)); + rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu)); + /* direct and indirect */ + rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT); + + vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT); +} + +static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req) +{ + uint8_t *cdb = req->iu.srp.cmd.cdb; + uint8_t resp_data[36]; + int rc, len, alen; + + /* We dont do EVPD. Also check that page_code is 0 */ + if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) { + /* Send INVALID FIELD IN CDB */ + vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + return; + } + alen = cdb[3]; + alen = (alen << 8) | cdb[4]; + len = MIN(alen, 36); + + /* Fake up inquiry using PQ=3 */ + memset(resp_data, 0, 36); + resp_data[0] = 0x7f; /* Not capable of supporting a device here */ + resp_data[2] = 0x06; /* SPS-4 */ + resp_data[3] = 0x02; /* Resp data format */ + resp_data[4] = 36 - 5; /* Additional length */ + resp_data[7] = 0x10; /* Sync transfers */ + memcpy(&resp_data[16], "QEMU EMPTY ", 16); + memcpy(&resp_data[8], "QEMU ", 8); + + req->writing = 0; + vscsi_preprocess_desc(req); + rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len); + if (rc < 0) { + vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + } else { + vscsi_send_rsp(s, req, 0, 36 - rc, 0); + } +} + +static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) +{ + union srp_iu *srp = &req->iu.srp; + SCSIDevice *sdev; + int n, id, lun; + + vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun); + + /* Qemu vs. linux issue with LUNs to be sorted out ... */ + sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL; + if (!sdev) { + dprintf("VSCSI: Command for id %d with no drive\n", id); + if (srp->cmd.cdb[0] == INQUIRY) { + vscsi_inquiry_no_target(s, req); + } else { + vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + } return 1; + } + + req->sdev = sdev; + req->lun = lun; + n = sdev->info->send_command(sdev, req->qtag, srp->cmd.cdb, lun); + + dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", + req->qtag, srp->cmd.cdb[0], id, lun, n); + + if (n) { + /* Transfer direction must be set before preprocessing the + * descriptors + */ + req->writing = (n < 1); + + /* Preprocess RDMA descriptors */ + vscsi_preprocess_desc(req); + } + + /* Get transfer direction and initiate transfer */ + if (n > 0) { + req->data_len = n; + sdev->info->read_data(sdev, req->qtag); + } else if (n < 0) { + req->data_len = -n; + sdev->info->write_data(sdev, req->qtag); + } + /* Don't touch req here, it may have been recycled already */ + + return 0; +} + +static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) +{ + union viosrp_iu *iu = &req->iu; + int fn; + + fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n", + iu->srp.tsk_mgmt.tsk_mgmt_func); + + switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { +#if 0 /* We really don't deal with these for now */ + case SRP_TSK_ABORT_TASK: + fn = ABORT_TASK; + break; + case SRP_TSK_ABORT_TASK_SET: + fn = ABORT_TASK_SET; + break; + case SRP_TSK_CLEAR_TASK_SET: + fn = CLEAR_TASK_SET; + break; + case SRP_TSK_LUN_RESET: + fn = LOGICAL_UNIT_RESET; + break; + case SRP_TSK_CLEAR_ACA: + fn = CLEAR_ACA; + break; +#endif + default: + fn = 0; + } + if (fn) { + /* XXX Send/Handle target task management */ + ; + } else { + vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + } + return !fn; +} + +static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req) +{ + union srp_iu *srp = &req->iu.srp; + int done = 1; + uint8_t opcode = srp->rsp.opcode; + + switch (opcode) { + case SRP_LOGIN_REQ: + vscsi_process_login(s, req); + break; + case SRP_TSK_MGMT: + done = vscsi_process_tsk_mgmt(s, req); + break; + case SRP_CMD: + done = vscsi_queue_cmd(s, req); + break; + case SRP_LOGIN_RSP: + case SRP_I_LOGOUT: + case SRP_T_LOGOUT: + case SRP_RSP: + case SRP_CRED_REQ: + case SRP_CRED_RSP: + case SRP_AER_REQ: + case SRP_AER_RSP: + fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode); + break; + default: + fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode); + } + + return done; +} + +static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req) +{ + struct viosrp_adapter_info *sinfo; + struct mad_adapter_info_data info; + int rc; + + sinfo = &req->iu.mad.adapter_info; + +#if 0 /* What for ? */ + rc = spapr_tce_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer), + &info, be16_to_cpu(sinfo->common.length)); + if (rc) { + fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n"); + } +#endif + memset(&info, 0, sizeof(info)); + strcpy(info.srp_version, SRP_VERSION); + strncpy(info.partition_name, "qemu", sizeof("qemu")); + info.partition_number = cpu_to_be32(0); + info.mad_version = cpu_to_be32(1); + info.os_type = cpu_to_be32(2); + info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9); + + rc = spapr_tce_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer), + &info, be16_to_cpu(sinfo->common.length)); + if (rc) { + fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n"); + } + + sinfo->common.status = rc ? cpu_to_be32(1) : 0; + + return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT); +} + +static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req) +{ + union mad_iu *mad = &req->iu.mad; + + switch (be32_to_cpu(mad->empty_iu.common.type)) { + case VIOSRP_EMPTY_IU_TYPE: + fprintf(stderr, "Unsupported EMPTY MAD IU\n"); + break; + case VIOSRP_ERROR_LOG_TYPE: + fprintf(stderr, "Unsupported ERROR LOG MAD IU\n"); + mad->error_log.common.status = cpu_to_be16(1); + vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT); + break; + case VIOSRP_ADAPTER_INFO_TYPE: + vscsi_send_adapter_info(s, req); + break; + case VIOSRP_HOST_CONFIG_TYPE: + mad->host_config.common.status = cpu_to_be16(1); + vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT); + break; + default: + fprintf(stderr, "VSCSI: Unknown MAD type %02x\n", + be32_to_cpu(mad->empty_iu.common.type)); + } + + return 1; +} + +static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) +{ + vscsi_req *req; + int done; + + req = vscsi_get_req(s); + if (req == NULL) { + fprintf(stderr, "VSCSI: Failed to get a request !\n"); + return; + } + + /* We only support a limited number of descriptors, we know + * the ibmvscsi driver uses up to 10 max, so it should fit + * in our 256 bytes IUs. If not we'll have to increase the size + * of the structure. + */ + if (crq->s.IU_length > sizeof(union viosrp_iu)) { + fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n", + crq->s.IU_length); + return; + } + + /* XXX Handle failure differently ? */ + if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu, + crq->s.IU_length)) { + fprintf(stderr, "vscsi_got_payload: DMA read failure !\n"); + qemu_free(req); + } + memcpy(&req->crq, crq, sizeof(vscsi_crq)); + + if (crq->s.format == VIOSRP_MAD_FORMAT) { + done = vscsi_handle_mad_req(s, req); + } else { + done = vscsi_handle_srp_req(s, req); + } + + if (done) { + vscsi_put_req(s, req); + } +} + + +static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); + vscsi_crq crq; + + memcpy(crq.raw, crq_data, 16); + crq.s.timeout = be16_to_cpu(crq.s.timeout); + crq.s.IU_length = be16_to_cpu(crq.s.IU_length); + crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr); + + dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); + + switch (crq.s.valid) { + case 0xc0: /* Init command/response */ + + /* Respond to initialization request */ + if (crq.s.format == 0x01) { + memset(crq.raw, 0, 16); + crq.s.valid = 0xc0; + crq.s.format = 0x02; + spapr_vio_send_crq(dev, crq.raw); + } + + /* Note that in hotplug cases, we might get a 0x02 + * as a result of us emitting the init request + */ + + break; + case 0xff: /* Link event */ + + /* Not handled for now */ + + break; + case 0x80: /* Payloads */ + switch (crq.s.format) { + case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */ + case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */ + vscsi_got_payload(s, &crq); + break; + case VIOSRP_OS400_FORMAT: + case VIOSRP_AIX_FORMAT: + case VIOSRP_LINUX_FORMAT: + case VIOSRP_INLINE_FORMAT: + fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n", + crq.s.format); + break; + default: + fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n", + crq.s.format); + } + break; + default: + fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n", + crq.raw[0], crq.raw[1]); + }; + + return 0; +} + +static int spapr_vscsi_init(VIOsPAPRDevice *dev) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); + int i; + + dbg_vscsi_state = s; + + /* Initialize qemu request tags */ + memset(s->reqs, 0, sizeof(s->reqs)); + for (i = 0; i < VSCSI_REQ_LIMIT; i++) { + s->reqs[i].qtag = i; + } + + dev->crq.SendFunc = vscsi_do_crq; + + scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT, + vscsi_command_complete); + if (!dev->qdev.hotplugged) { + scsi_bus_legacy_handle_cmdline(&s->bus); + } + + return 0; +} + +void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg, + qemu_irq qirq, uint32_t vio_irq_num) +{ + DeviceState *dev; + VIOsPAPRDevice *sdev; + + dev = qdev_create(&bus->bus, "spapr-vscsi"); + qdev_prop_set_uint32(dev, "reg", reg); + + qdev_init_nofail(dev); + + sdev = (VIOsPAPRDevice *)dev; + sdev->qirq = qirq; + sdev->vio_irq_num = vio_irq_num; +} + +static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) +{ + int ret; + + ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2); + if (ret < 0) { + return ret; + } + + ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0); + if (ret < 0) { + return ret; + } + + return 0; +} + +static VIOsPAPRDeviceInfo spapr_vscsi = { + .init = spapr_vscsi_init, + .devnode = spapr_vscsi_devnode, + .dt_name = "v-scsi", + .dt_type = "vscsi", + .dt_compatible = "IBM,v-scsi", + .signal_mask = 0x00000001, + .qdev.name = "spapr-vscsi", + .qdev.size = sizeof(VSCSIState), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000), + DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, + rtce_window_size, 0x10000000), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void spapr_vscsi_register(void) +{ + spapr_vio_bus_register_withprop(&spapr_vscsi); +} +device_init(spapr_vscsi_register); diff --git a/hw/srp.h b/hw/srp.h new file mode 100644 index 0000000000..afcd135c8f --- /dev/null +++ b/hw/srp.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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. + * + */ + +#ifndef SCSI_SRP_H +#define SCSI_SRP_H + +/* + * Structures and constants for the SCSI RDMA Protocol (SRP) as + * defined by the INCITS T10 committee. This file was written using + * draft Revision 16a of the SRP standard. + */ + +enum { + + SRP_LOGIN_REQ = 0x00, + SRP_TSK_MGMT = 0x01, + SRP_CMD = 0x02, + SRP_I_LOGOUT = 0x03, + SRP_LOGIN_RSP = 0xc0, + SRP_RSP = 0xc1, + SRP_LOGIN_REJ = 0xc2, + SRP_T_LOGOUT = 0x80, + SRP_CRED_REQ = 0x81, + SRP_AER_REQ = 0x82, + SRP_CRED_RSP = 0x41, + SRP_AER_RSP = 0x42 +}; + +enum { + SRP_BUF_FORMAT_DIRECT = 1 << 1, + SRP_BUF_FORMAT_INDIRECT = 1 << 2 +}; + +enum { + SRP_NO_DATA_DESC = 0, + SRP_DATA_DESC_DIRECT = 1, + SRP_DATA_DESC_INDIRECT = 2 +}; + +enum { + SRP_TSK_ABORT_TASK = 0x01, + SRP_TSK_ABORT_TASK_SET = 0x02, + SRP_TSK_CLEAR_TASK_SET = 0x04, + SRP_TSK_LUN_RESET = 0x08, + SRP_TSK_CLEAR_ACA = 0x40 +}; + +enum srp_login_rej_reason { + SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL = 0x00010000, + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES = 0x00010001, + SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002, + SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL = 0x00010003, + SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004, + SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED = 0x00010005, + SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006 +}; + +enum { + SRP_REV10_IB_IO_CLASS = 0xff00, + SRP_REV16A_IB_IO_CLASS = 0x0100 +}; + +struct srp_direct_buf { + uint64_t va; + uint32_t key; + uint32_t len; +}; + +/* + * We need the packed attribute because the SRP spec puts the list of + * descriptors at an offset of 20, which is not aligned to the size of + * struct srp_direct_buf. The whole structure must be packed to avoid + * having the 20-byte structure padded to 24 bytes on 64-bit architectures. + */ +struct srp_indirect_buf { + struct srp_direct_buf table_desc; + uint32_t len; + struct srp_direct_buf desc_list[0]; +} __attribute__((packed)); + +enum { + SRP_MULTICHAN_SINGLE = 0, + SRP_MULTICHAN_MULTI = 1 +}; + +struct srp_login_req { + uint8_t opcode; + uint8_t reserved1[7]; + uint64_t tag; + uint32_t req_it_iu_len; + uint8_t reserved2[4]; + uint16_t req_buf_fmt; + uint8_t req_flags; + uint8_t reserved3[5]; + uint8_t initiator_port_id[16]; + uint8_t target_port_id[16]; +}; + +/* + * The SRP spec defines the size of the LOGIN_RSP structure to be 52 + * bytes, so it needs to be packed to avoid having it padded to 56 + * bytes on 64-bit architectures. + */ +struct srp_login_rsp { + uint8_t opcode; + uint8_t reserved1[3]; + uint32_t req_lim_delta; + uint64_t tag; + uint32_t max_it_iu_len; + uint32_t max_ti_iu_len; + uint16_t buf_fmt; + uint8_t rsp_flags; + uint8_t reserved2[25]; +} __attribute__((packed)); + +struct srp_login_rej { + uint8_t opcode; + uint8_t reserved1[3]; + uint32_t reason; + uint64_t tag; + uint8_t reserved2[8]; + uint16_t buf_fmt; + uint8_t reserved3[6]; +}; + +struct srp_i_logout { + uint8_t opcode; + uint8_t reserved[7]; + uint64_t tag; +}; + +struct srp_t_logout { + uint8_t opcode; + uint8_t sol_not; + uint8_t reserved[2]; + uint32_t reason; + uint64_t tag; +}; + +/* + * We need the packed attribute because the SRP spec only aligns the + * 8-byte LUN field to 4 bytes. + */ +struct srp_tsk_mgmt { + uint8_t opcode; + uint8_t sol_not; + uint8_t reserved1[6]; + uint64_t tag; + uint8_t reserved2[4]; + uint64_t lun __attribute__((packed)); + uint8_t reserved3[2]; + uint8_t tsk_mgmt_func; + uint8_t reserved4; + uint64_t task_tag; + uint8_t reserved5[8]; +}; + +/* + * We need the packed attribute because the SRP spec only aligns the + * 8-byte LUN field to 4 bytes. + */ +struct srp_cmd { + uint8_t opcode; + uint8_t sol_not; + uint8_t reserved1[3]; + uint8_t buf_fmt; + uint8_t data_out_desc_cnt; + uint8_t data_in_desc_cnt; + uint64_t tag; + uint8_t reserved2[4]; + uint64_t lun __attribute__((packed)); + uint8_t reserved3; + uint8_t task_attr; + uint8_t reserved4; + uint8_t add_cdb_len; + uint8_t cdb[16]; + uint8_t add_data[0]; +}; + +enum { + SRP_RSP_FLAG_RSPVALID = 1 << 0, + SRP_RSP_FLAG_SNSVALID = 1 << 1, + SRP_RSP_FLAG_DOOVER = 1 << 2, + SRP_RSP_FLAG_DOUNDER = 1 << 3, + SRP_RSP_FLAG_DIOVER = 1 << 4, + SRP_RSP_FLAG_DIUNDER = 1 << 5 +}; + +/* + * The SRP spec defines the size of the RSP structure to be 36 bytes, + * so it needs to be packed to avoid having it padded to 40 bytes on + * 64-bit architectures. + */ +struct srp_rsp { + uint8_t opcode; + uint8_t sol_not; + uint8_t reserved1[2]; + uint32_t req_lim_delta; + uint64_t tag; + uint8_t reserved2[2]; + uint8_t flags; + uint8_t status; + uint32_t data_out_res_cnt; + uint32_t data_in_res_cnt; + uint32_t sense_data_len; + uint32_t resp_data_len; + uint8_t data[0]; +} __attribute__((packed)); + +#endif /* SCSI_SRP_H */ From 08942ac17922d923a7cc5cf9854e9cc4b150b942 Mon Sep 17 00:00:00 2001 From: Ben Herrenschmidt <benh@kernel.crashing.org> Date: Fri, 1 Apr 2011 15:15:32 +1100 Subject: [PATCH 030/386] Add a PAPR TCE-bypass mechanism for the pSeries machine Usually, PAPR virtual IO devices use a virtual IOMMU mechanism, TCEs, to mediate all DMA transfers. While this is necessary for some sorts of operation, it can be complex to program and slow for others. This patch implements a mechanism for bypassing TCE translation, treating "IO" addresses as plain (guest) physical memory addresses. This has two main uses: * Simple, but 64-bit aware programs like firmwares can use the VIO devices without the complexity of TCE setup. * The guest OS can optionally use the TCE bypass to improve performance in suitable situations. The mechanism used is a per-device flag which disables TCE translation. The flag is toggled with some (hypervisor-implemented) RTAS methods. Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr_vio.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/spapr_vio.h | 5 +++ 2 files changed, 87 insertions(+) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 8f14fcc794..481a804e73 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -226,6 +226,12 @@ int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf, (unsigned long long)taddr, size); #endif + /* Check for bypass */ + if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) { + cpu_physical_memory_write(taddr, buf, size); + return 0; + } + while (size) { uint64_t tce; uint32_t lsize; @@ -313,6 +319,12 @@ int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf, (unsigned long long)taddr, size); #endif + /* Check for bypass */ + if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) { + cpu_physical_memory_read(taddr, buf, size); + return 0; + } + while (size) { uint64_t tce; uint32_t lsize; @@ -513,6 +525,72 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) return 0; } +/* "quiesce" handling */ + +static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) +{ + dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS; + + if (dev->rtce_table) { + size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT) + * sizeof(VIOsPAPR_RTCE); + memset(dev->rtce_table, 0, size); + } + + dev->crq.qladdr = 0; + dev->crq.qsize = 0; + dev->crq.qnext = 0; +} + +static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + VIOsPAPRBus *bus = spapr->vio_bus; + VIOsPAPRDevice *dev; + uint32_t unit, enable; + + if (nargs != 2) { + rtas_st(rets, 0, -3); + return; + } + unit = rtas_ld(args, 0); + enable = rtas_ld(args, 1); + dev = spapr_vio_find_by_reg(bus, unit); + if (!dev) { + rtas_st(rets, 0, -3); + return; + } + if (enable) { + dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS; + } else { + dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS; + } + + rtas_st(rets, 0, 0); +} + +static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + VIOsPAPRBus *bus = spapr->vio_bus; + DeviceState *qdev; + VIOsPAPRDevice *dev = NULL; + + if (nargs != 0) { + rtas_st(rets, 0, -3); + return; + } + + QLIST_FOREACH(qdev, &bus->bus.children, sibling) { + dev = (VIOsPAPRDevice *)qdev; + spapr_vio_quiesce_one(dev); + } + + rtas_st(rets, 0, 0); +} + static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; @@ -591,6 +669,10 @@ VIOsPAPRBus *spapr_vio_bus_init(void) spapr_register_hypercall(H_SEND_CRQ, h_send_crq); spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); + /* RTAS calls */ + spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); + spapr_rtas_register("quiesce", rtas_quiesce); + for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) { VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index b7d0daab07..841b04351a 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -48,6 +48,8 @@ typedef struct VIOsPAPR_CRQ { typedef struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; + uint32_t flags; +#define VIO_PAPR_FLAG_DMA_BYPASS 0x1 qemu_irq qirq; uint32_t vio_irq_num; target_ulong signal_state; @@ -104,4 +106,7 @@ void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd, void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg, qemu_irq qirq, uint32_t vio_irq_num); +int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); +void spapr_vio_quiesce(void); + #endif /* _HW_SPAPR_VIO_H */ From ed120055c7f9b26b5707d3ceabbe5a3f06aaf937 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:33 +1100 Subject: [PATCH 031/386] Implement PAPR VPA functions for pSeries shared processor partitions Shared-processor partitions are those where a CPU is time-sliced between partitions, rather than being permanently dedicated to a single partition. qemu emulated partitions, since they are just scheduled with the qemu user process, behave mostly like shared processor partitions. In order to better support shared processor partitions (splpar), PAPR defines the "VPA" (Virtual Processor Area), a shared memory communication channel between the hypervisor and partitions. There are also two additional shared memory communication areas for specialized purposes associated with the VPA. A VPA is not essential for operating an splpar, though it can be necessary for obtaining accurate performance measurements in the presence of runtime partition switching. Most importantly, however, the VPA is a prerequisite for PAPR's H_CEDE, hypercall, which allows a partition OS to give up it's shared processor timeslices to other partitions when idle. This patch implements the VPA and H_CEDE hypercalls in qemu. We don't implement any of the more advanced statistics which can be communicated through the VPA. However, this is enough to make normal pSeries kernels do an effective power-save idle on an emulated pSeries, significantly reducing the host load of a qemu emulated pSeries running an idle guest OS. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 2 +- hw/spapr_hcall.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 7 ++ 3 files changed, 200 insertions(+), 1 deletion(-) diff --git a/hw/spapr.c b/hw/spapr.c index 3bffaabe86..876768631b 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -68,7 +68,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" - "\0hcall-tce\0hcall-vio"; + "\0hcall-tce\0hcall-vio\0hcall-splpar"; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index a47a97ba55..f88e1d2083 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -4,6 +4,8 @@ #include "sysemu.h" #include "qemu-char.h" #include "exec-all.h" +#include "exec.h" +#include "helper_regs.h" #include "hw/spapr.h" #define HPTES_PER_GROUP 8 @@ -255,6 +257,192 @@ static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr, return H_HARDWARE; } +#define FLAGS_REGISTER_VPA 0x0000200000000000ULL +#define FLAGS_REGISTER_DTL 0x0000400000000000ULL +#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL +#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL +#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL +#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL + +#define VPA_MIN_SIZE 640 +#define VPA_SIZE_OFFSET 0x4 +#define VPA_SHARED_PROC_OFFSET 0x9 +#define VPA_SHARED_PROC_VAL 0x2 + +static target_ulong register_vpa(CPUState *env, target_ulong vpa) +{ + uint16_t size; + uint8_t tmp; + + if (vpa == 0) { + hcall_dprintf("Can't cope with registering a VPA at logical 0\n"); + return H_HARDWARE; + } + + if (vpa % env->dcache_line_size) { + return H_PARAMETER; + } + /* FIXME: bounds check the address */ + + size = lduw_phys(vpa + 0x4); + + if (size < VPA_MIN_SIZE) { + return H_PARAMETER; + } + + /* VPA is not allowed to cross a page boundary */ + if ((vpa / 4096) != ((vpa + size - 1) / 4096)) { + return H_PARAMETER; + } + + env->vpa = vpa; + + tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET); + tmp |= VPA_SHARED_PROC_VAL; + stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp); + + return H_SUCCESS; +} + +static target_ulong deregister_vpa(CPUState *env, target_ulong vpa) +{ + if (env->slb_shadow) { + return H_RESOURCE; + } + + if (env->dispatch_trace_log) { + return H_RESOURCE; + } + + env->vpa = 0; + return H_SUCCESS; +} + +static target_ulong register_slb_shadow(CPUState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with SLB shadow at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_phys(addr + 0x4); + if (size < 0x8) { + return H_PARAMETER; + } + + if ((addr / 4096) != ((addr + size - 1) / 4096)) { + return H_PARAMETER; + } + + if (!env->vpa) { + return H_RESOURCE; + } + + env->slb_shadow = addr; + + return H_SUCCESS; +} + +static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr) +{ + env->slb_shadow = 0; + return H_SUCCESS; +} + +static target_ulong register_dtl(CPUState *env, target_ulong addr) +{ + uint32_t size; + + if (addr == 0) { + hcall_dprintf("Can't cope with DTL at logical 0\n"); + return H_HARDWARE; + } + + size = ldl_phys(addr + 0x4); + + if (size < 48) { + return H_PARAMETER; + } + + if (!env->vpa) { + return H_RESOURCE; + } + + env->dispatch_trace_log = addr; + env->dtl_size = size; + + return H_SUCCESS; +} + +static target_ulong deregister_dtl(CPUState *emv, target_ulong addr) +{ + env->dispatch_trace_log = 0; + env->dtl_size = 0; + + return H_SUCCESS; +} + +static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong procno = args[1]; + target_ulong vpa = args[2]; + target_ulong ret = H_PARAMETER; + CPUState *tenv; + + for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { + if (tenv->cpu_index == procno) { + break; + } + } + + if (!tenv) { + return H_PARAMETER; + } + + switch (flags) { + case FLAGS_REGISTER_VPA: + ret = register_vpa(tenv, vpa); + break; + + case FLAGS_DEREGISTER_VPA: + ret = deregister_vpa(tenv, vpa); + break; + + case FLAGS_REGISTER_SLBSHADOW: + ret = register_slb_shadow(tenv, vpa); + break; + + case FLAGS_DEREGISTER_SLBSHADOW: + ret = deregister_slb_shadow(tenv, vpa); + break; + + case FLAGS_REGISTER_DTL: + ret = register_dtl(tenv, vpa); + break; + + case FLAGS_DEREGISTER_DTL: + ret = deregister_dtl(tenv, vpa); + break; + } + + return ret; +} + +static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + env->msr |= (1ULL << MSR_EE); + hreg_compute_hflags(env); + if (!cpu_has_work(env)) { + env->halted = 1; + } + return H_SUCCESS; +} + static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -327,6 +515,10 @@ static void hypercall_init(void) /* hcall-dabr */ spapr_register_hypercall(H_SET_DABR, h_set_dabr); + /* hcall-splpar */ + spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); + spapr_register_hypercall(H_CEDE, h_cede); + /* qemu/KVM-PPC specific hcalls */ spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas); } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b4c2555626..04b12590fa 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -721,6 +721,13 @@ struct CPUPPCState { uint32_t flags; uint64_t insns_flags; +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + target_phys_addr_t vpa; + target_phys_addr_t slb_shadow; + target_phys_addr_t dispatch_trace_log; + uint32_t dtl_size; +#endif /* TARGET_PPC64 */ + int error_code; uint32_t pending_interrupts; #if !defined(CONFIG_USER_ONLY) From a9f8ad8f2acdb2398da5d32a5efc19cb0196d79f Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 1 Apr 2011 15:15:34 +1100 Subject: [PATCH 032/386] Add SLOF-based partition firmware for pSeries machine, allowing more boot options Currently, the emulated pSeries machine requires the use of the -kernel parameter in order to explicitly load a guest kernel. This means booting from the virtual disk, cdrom or network is not possible. This patch addresses this limitation by inserting a within-partition firmware image (derived from the "SLOF" free Open Firmware project). If -kernel is not specified, qemu will now load the SLOF image, which has access to the qemu boot device list through the device tree, and can boot from any of the usual virtual devices. In order to support the new firmware, an extension to the emulated machine/hypervisor is necessary. Unlike Linux, which expects multi-CPU entry to be handled kexec() style, the SLOF firmware expects only one CPU to be active at entry, and to use a hypervisor RTAS method to enable the other CPUs one by one. This patch also implements this 'start-cpu' method, so that SLOF can start the secondary CPUs and marshal them into the kexec() holding pattern ready for entry into the guest OS. Linux should, and in the future might directly use the start-cpu method to enable initially disabled CPUs, but for now it does require kexec() entry. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- .gitmodules | 3 ++ Makefile | 2 +- hw/spapr.c | 35 ++++++++++++++++++--- hw/spapr_rtas.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ pc-bios/README | 5 +++ pc-bios/slof.bin | Bin 0 -> 579072 bytes roms/SLOF | 1 + 7 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 pc-bios/slof.bin create mode 160000 roms/SLOF diff --git a/.gitmodules b/.gitmodules index 5217ce7d1c..44fdd1a02d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "roms/seabios"] path = roms/seabios url = git://git.qemu.org/seabios.git/ +[submodule "roms/SLOF"] + path = roms/SLOF + url = git://git.qemu.org/SLOF.git diff --git a/Makefile b/Makefile index e0b3fea6bc..989622b388 100644 --- a/Makefile +++ b/Makefile @@ -214,7 +214,7 @@ pxe-rtl8139.bin pxe-virtio.bin \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin \ s390-zipl.rom \ -spapr-rtas.bin +spapr-rtas.bin slof.bin else BLOBS= endif diff --git a/hw/spapr.c b/hw/spapr.c index 876768631b..1152a25b2e 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -44,6 +44,10 @@ #define INITRD_LOAD_ADDR 0x02800000 #define FDT_MAX_SIZE 0x10000 #define RTAS_MAX_SIZE 0x10000 +#define FW_MAX_SIZE 0x400000 +#define FW_FILE_NAME "slof.bin" + +#define MIN_RAM_SLOF 512UL #define TIMEBASE_FREQ 512000000ULL @@ -57,6 +61,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, sPAPREnvironment *spapr, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, + const char *boot_device, const char *kernel_cmdline, target_phys_addr_t rtas_addr, target_phys_addr_t rtas_size, @@ -105,6 +110,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, &start_prop, sizeof(start_prop)))); _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop)))); + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); _FDT((fdt_end_node(fdt))); @@ -261,7 +267,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, ram_addr_t ram_offset; target_phys_addr_t fdt_addr, rtas_addr; uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size, htab_size, rtas_size; + long kernel_size, initrd_size, htab_size, rtas_size, fw_size; long pteg_shift = 17; int fdt_size; char *filename; @@ -392,13 +398,33 @@ static void ppc_spapr_init(ram_addr_t ram_size, initrd_size = 0; } } else { - fprintf(stderr, "pSeries machine needs -kernel for now"); - exit(1); + if (ram_size < (MIN_RAM_SLOF << 20)) { + fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " + "%ldM guest RAM\n", MIN_RAM_SLOF); + exit(1); + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin"); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + qemu_free(filename); + kernel_base = 0x100; + initrd_base = 0; + initrd_size = 0; + + /* SLOF will startup the secondary CPUs using RTAS, + rather than expecting a kexec() style entry */ + for (i = 0; i < smp_cpus; i++) { + envs[i]->halted = 1; + } } /* Prepare the device tree */ fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, - initrd_base, initrd_size, kernel_cmdline, + initrd_base, initrd_size, + boot_device, kernel_cmdline, rtas_addr, rtas_size, pteg_shift + 7); assert(fdt != NULL); @@ -409,6 +435,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, envs[0]->gpr[3] = fdt_addr; envs[0]->gpr[5] = 0; envs[0]->hreset_vector = kernel_base; + envs[0]->halted = 0; } static QEMUMachine spapr_machine = { diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 72268537a8..16b65422b6 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -90,6 +90,81 @@ static void rtas_power_off(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } +static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id; + CPUState *env; + + if (nargs != 1 || nret != 2) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + for (env = first_cpu; env; env = env->next_cpu) { + if (env->cpu_index != id) { + continue; + } + + if (env->halted) { + rtas_st(rets, 1, 0); + } else { + rtas_st(rets, 1, 2); + } + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + +static void rtas_start_cpu(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id, start, r3; + CPUState *env; + + if (nargs != 3 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + start = rtas_ld(args, 1); + r3 = rtas_ld(args, 2); + + for (env = first_cpu; env; env = env->next_cpu) { + if (env->cpu_index != id) { + continue; + } + + if (!env->halted) { + rtas_st(rets, 0, -1); + return; + } + + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + env->nip = start; + env->gpr[3] = r3; + env->halted = 0; + + qemu_cpu_kick(env); + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + static struct rtas_call { const char *name; spapr_rtas_fn fn; @@ -196,5 +271,8 @@ static void register_core_rtas(void) spapr_rtas_register("display-character", rtas_display_character); spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); spapr_rtas_register("power-off", rtas_power_off); + spapr_rtas_register("query-cpu-stopped-state", + rtas_query_cpu_stopped_state); + spapr_rtas_register("start-cpu", rtas_start_cpu); } device_init(register_core_rtas); diff --git a/pc-bios/README b/pc-bios/README index 3fc09449fa..646a31a313 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -13,6 +13,11 @@ The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 and Sparc64 are built from OpenBIOS SVN revision 1018. +- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware + implementation for certain IBM POWER hardware. The sources are at + https://github.com/dgibson/SLOF, and the image currently in qemu is + built from git tag qemu-slof-20110323. + - The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0 e1000 8086:100E diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin new file mode 100644 index 0000000000000000000000000000000000000000..22c4c7f5c448e3002aefecf3438f5d080586d666 GIT binary patch literal 579072 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 literal 0 HcmV?d00001 diff --git a/roms/SLOF b/roms/SLOF new file mode 160000 index 0000000000..d1d6b53b71 --- /dev/null +++ b/roms/SLOF @@ -0,0 +1 @@ +Subproject commit d1d6b53b713a2b7c2c25685268fa932d28a4b4c0 From d818bfc5c34c59e9c6d03b3b9983bb5435967292 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Fri, 1 Apr 2011 20:04:24 +0200 Subject: [PATCH 033/386] pc-bios/spapr-rtas.bin: remove executable flag Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- pc-bios/spapr-rtas.bin | Bin 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 pc-bios/spapr-rtas.bin diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin old mode 100755 new mode 100644 From 09cec717bfaaaabd4c2789e480626ce70fdab204 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Wed, 16 Feb 2011 21:15:40 +0100 Subject: [PATCH 034/386] ui/sdl: Load optional QEMU icon Load an optional QEMU icon file. If there is no icon file named qemu.bmp in QEMU's default search path, QEMU will run with the usual system default icon. A matching icon file will be loaded and used by X Windows managers or MS Windows while a QEMU instance is running. SDL requires icon files in 32x32x4 bmp format. Cc: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- ui/sdl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ui/sdl.c b/ui/sdl.c index c5bb0a3705..dc5c3a1bc2 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -812,6 +812,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) uint8_t data = 0; DisplayAllocator *da; const SDL_VideoInfo *vi; + char *filename; #if defined(__APPLE__) /* always use generic keymaps */ @@ -844,6 +845,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) vi = SDL_GetVideoInfo(); host_format = *(vi->vfmt); + /* Load a 32x32x4 image. White pixels are transparent. */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); + if (filename) { + SDL_Surface *image = SDL_LoadBMP(filename); + if (image) { + uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255); + SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey); + SDL_WM_SetIcon(image, NULL); + } + qemu_free(filename); + } + dcl = qemu_mallocz(sizeof(DisplayChangeListener)); dcl->dpy_update = sdl_update; dcl->dpy_resize = sdl_resize; From 59df4c11560fb5da9071b5ab5c4607055fbe927a Mon Sep 17 00:00:00 2001 From: Wen Congyang <wency@cn.fujitsu.com> Date: Mon, 28 Feb 2011 10:22:33 +0800 Subject: [PATCH 035/386] fix build errors when we enable acpi_piix4 debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I enable acpi_piix4 debug, and got the following build errors: # make CC libhw64/acpi_piix4.o cc1: warnings being treated as errors /home/wency/source/qemu/hw/acpi_piix4.c: In function ‘pm_ioport_write’: /home/wency/source/qemu/hw/acpi_piix4.c:193: error: format ‘%04x’ expects type ‘unsigned int’, but argument 2 has type ‘uint64_t’ /home/wency/source/qemu/hw/acpi_piix4.c:193: error: format ‘%04x’ expects type ‘unsigned int’, but argument 3 has type ‘uint64_t’ /home/wency/source/qemu/hw/acpi_piix4.c: In function ‘pm_ioport_read’: /home/wency/source/qemu/hw/acpi_piix4.c:219: error: format ‘%04x’ expects type ‘unsigned int’, but argument 2 has type ‘uint64_t’ make[1]: *** [acpi_piix4.o] Error 1 make: *** [subdir-libhw64] Error 2 Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi_piix4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 0b2bc97cf1..74044ddd9b 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -190,7 +190,8 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, default: break; } - PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val); + PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr, + (unsigned int)val); } static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, @@ -216,7 +217,7 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, val = 0; break; } - PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val); + PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val); *data = val; } From 508240c0daecdd62ab46727f37145f2dbb029ff7 Mon Sep 17 00:00:00 2001 From: Bernhard Kohl <bernhard.kohl@nsn.com> Date: Mon, 6 Sep 2010 04:42:54 +0000 Subject: [PATCH 036/386] lsi53c895a: add support for ABORT messages If these messages are not handled correctly the guest driver may hang. Always mandatory: - ABORT - BUS DEVICE RESET Mandatory if tagged queuing is implemented (which disks usually do): - ABORT TAG - CLEAR QUEUE Signed-off-by: Bernhard Kohl <bernhard.kohl@nsn.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/lsi53c895a.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 84a49928dc..e4b51a8eaf 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -853,6 +853,18 @@ static void lsi_do_msgout(LSIState *s) { uint8_t msg; int len; + uint32_t current_tag; + SCSIDevice *current_dev; + lsi_request *p, *p_next; + int id; + + if (s->current) { + current_tag = s->current->tag; + } else { + current_tag = s->select_tag; + } + id = (current_tag >> 8) & 0xf; + current_dev = s->bus.devs[id]; DPRINTF("MSG out len=%d\n", s->dbc); while (s->dbc) { @@ -898,6 +910,51 @@ static void lsi_do_msgout(LSIState *s) BADF("ORDERED queue not implemented\n"); s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; break; + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag); + current_dev->info->cancel_io(current_dev, current_tag); + lsi_disconnect(s); + break; + case 0x06: + case 0x0e: + case 0x0c: + /* The ABORT message clears all I/O processes for the selecting + initiator on the specified logical unit of the target. */ + if (msg == 0x06) { + DPRINTF("MSG: ABORT tag=0x%x\n", current_tag); + } + /* The CLEAR QUEUE message clears all I/O processes for all + initiators on the specified logical unit of the target. */ + if (msg == 0x0e) { + DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); + } + /* The BUS DEVICE RESET message clears all I/O processes for all + initiators on all logical units of the target. */ + if (msg == 0x0c) { + DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); + } + + /* clear the current I/O process */ + current_dev->info->cancel_io(current_dev, current_tag); + + /* As the current implemented devices scsi_disk and scsi_generic + only support one LUN, we don't need to keep track of LUNs. + Clearing I/O processes for other initiators could be possible + for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX + device, but this is currently not implemented (and seems not + to be really necessary). So let's simply clear all queued + commands for the current device: */ + id = current_tag & 0x0000ff00; + QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) { + if ((p->tag & 0x0000ff00) == id) { + current_dev->info->cancel_io(current_dev, p->tag); + QTAILQ_REMOVE(&s->queue, p, next); + } + } + + lsi_disconnect(s); + break; default: if ((msg & 0x80) == 0) { goto bad; From 8cffde7329734c17ee2eeec84944abbf4a0f23f3 Mon Sep 17 00:00:00 2001 From: Michael Tokarev <mjt@tls.msk.ru> Date: Thu, 10 Mar 2011 17:03:41 +0300 Subject: [PATCH 037/386] get rid of private bitmap functions in block/sheepdog.c, use generic ones qemu now has generic bitmap functions, so don't redefine them in sheepdog.c, use common header instead. A small cleanup. Here's only one function which is actually used in sheepdog and gets replaced with a generic one (simplified): - static inline int test_bit(int nr, const volatile unsigned long *addr) + static inline int test_bit(int nr, const unsigned long *addr) { - return ((1UL << (nr % BITS_PER_LONG)) & ((unsigned long*)addr)[nr / BITS_PER_LONG])) != 0; + return 1UL & (addr[nr / BITS_PER_LONG] >> (nr & (BITS_PER_LONG-1))); } The body is equivalent, but the argument is not: there's "volatile" in there. Why it is used for - I'm not sure. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Acked-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- block/sheepdog.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index a54e0dee31..98946d72b7 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -13,6 +13,7 @@ #include "qemu-error.h" #include "qemu_socket.h" #include "block_int.h" +#include "bitops.h" #define SD_PROTO_VER 0x01 @@ -1829,20 +1830,6 @@ static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) return 0; } -#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) -#define BITS_PER_BYTE 8 -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] - -#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) - -static inline int test_bit(unsigned int nr, const unsigned long *addr) -{ - return ((1UL << (nr % BITS_PER_LONG)) & - (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; -} - static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) { BDRVSheepdogState *s = bs->opaque; From ee7495d3a9304942ad75f07713b565db25352411 Mon Sep 17 00:00:00 2001 From: Leszek Grzegorek <leszek.grzegorek@gmail.com> Date: Mon, 14 Mar 2011 10:30:08 +0100 Subject: [PATCH 038/386] vnc: added missing name->keysym pairs for Polish national characters There are no { name, keysym } values in name2keysym[] array for Polish national characters so "-k pl" option has no effect. Signed-off-by: Leszek Grzegorek <leszek.grzegorek@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- ui/vnc_keysym.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h index 55cb87edec..df33cfe53c 100644 --- a/ui/vnc_keysym.h +++ b/ui/vnc_keysym.h @@ -202,6 +202,24 @@ static const name2keysym_t name2keysym[]={ { "ydiaeresis", 0x0ff}, {"EuroSign", 0x20ac}, /* XK_EuroSign */ +/* latin 2 - Polish national characters */ +{ "eogonek", 0x1ea}, +{ "Eogonek", 0x1ca}, +{ "aogonek", 0x1b1}, +{ "Aogonek", 0x1a1}, +{ "sacute", 0x1b6}, +{ "Sacute", 0x1a6}, +{ "lstroke", 0x1b3}, +{ "Lstroke", 0x1a3}, +{ "zabovedot", 0x1bf}, +{ "Zabovedot", 0x1af}, +{ "zacute", 0x1bc}, +{ "Zacute", 0x1ac}, +{ "cacute", 0x1e6}, +{ "Cacute", 0x1c6}, +{ "nacute", 0x1f1}, +{ "Nacute", 0x1d1}, + /* modifiers */ {"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */ {"Control_L", 0xffe3}, /* XK_Control_L */ From ac60cc18711a9786af9844d7e3d002276fbd85f3 Mon Sep 17 00:00:00 2001 From: Tristan Gingold <gingold@adacore.com> Date: Tue, 15 Mar 2011 14:20:54 +0100 Subject: [PATCH 039/386] Fix net_check_clients warnings: make it per vlan. Signed-off-by: Tristan Gingold <gingold@adacore.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- net.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net.c b/net.c index ddcca9752d..b2dfaa8085 100644 --- a/net.c +++ b/net.c @@ -1305,9 +1305,10 @@ void net_check_clients(void) { VLANState *vlan; VLANClientState *vc; - int has_nic = 0, has_host_dev = 0; QTAILQ_FOREACH(vlan, &vlans, next) { + int has_nic = 0, has_host_dev = 0; + QTAILQ_FOREACH(vc, &vlan->clients, next) { switch (vc->info->type) { case NET_CLIENT_TYPE_NIC: From 8e18cde30b06d2e7411bf38091c4e30602f85cdd Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 15 Mar 2011 16:26:51 +0000 Subject: [PATCH 040/386] target-arm: Fix VLD of single element to all lanes Fix several bugs in VLD of single element to all lanes: The "single element to all lanes" form of VLD1 differs from those for VLD2, VLD3 and VLD4 in that bit 5 indicates whether the loaded element should be written to one or two Dregs (rather than being a register stride). Handle this by special-casing VLD1 rather than trying to have one loop which deals with both VLD1 and 2/3/4. Handle VLD4.32 with 16 byte alignment specified, rather than UNDEFfing. UNDEF for the invalid size and alignment combinations. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 84 +++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index f69912f20c..1dfd4823f5 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2648,6 +2648,28 @@ static void gen_neon_dup_high16(TCGv var) tcg_temp_free_i32(tmp); } +static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size) +{ + /* Load a single Neon element and replicate into a 32 bit TCG reg */ + TCGv tmp; + switch (size) { + case 0: + tmp = gen_ld8u(addr, IS_USER(s)); + gen_neon_dup_u8(tmp, 0); + break; + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + gen_neon_dup_low16(tmp); + break; + case 2: + tmp = gen_ld32(addr, IS_USER(s)); + break; + default: /* Avoid compiler warnings. */ + abort(); + } + return tmp; +} + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) @@ -3890,36 +3912,48 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) size = (insn >> 10) & 3; if (size == 3) { /* Load single element to all lanes. */ - if (!load) + int a = (insn >> 4) & 1; + if (!load) { return 1; + } size = (insn >> 6) & 3; nregs = ((insn >> 8) & 3) + 1; - stride = (insn & (1 << 5)) ? 2 : 1; - load_reg_var(s, addr, rn); - for (reg = 0; reg < nregs; reg++) { - switch (size) { - case 0: - tmp = gen_ld8u(addr, IS_USER(s)); - gen_neon_dup_u8(tmp, 0); - break; - case 1: - tmp = gen_ld16u(addr, IS_USER(s)); - gen_neon_dup_low16(tmp); - break; - case 2: - tmp = gen_ld32(addr, IS_USER(s)); - break; - case 3: + + if (size == 3) { + if (nregs != 4 || a == 0) { return 1; - default: /* Avoid compiler warnings. */ - abort(); } - tcg_gen_addi_i32(addr, addr, 1 << size); - tmp2 = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp2, tmp); - neon_store_reg(rd, 0, tmp2); - neon_store_reg(rd, 1, tmp); - rd += stride; + /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */ + size = 2; + } + if (nregs == 1 && a == 1 && size == 0) { + return 1; + } + if (nregs == 3 && a == 1) { + return 1; + } + load_reg_var(s, addr, rn); + if (nregs == 1) { + /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */ + tmp = gen_load_and_replicate(s, addr, size); + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0)); + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1)); + if (insn & (1 << 5)) { + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0)); + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1)); + } + tcg_temp_free_i32(tmp); + } else { + /* VLD2/3/4 to all lanes: bit 5 indicates register stride */ + stride = (insn & (1 << 5)) ? 2 : 1; + for (reg = 0; reg < nregs; reg++) { + tmp = gen_load_and_replicate(s, addr, size); + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0)); + tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1)); + tcg_temp_free_i32(tmp); + tcg_gen_addi_i32(addr, addr, 1 << size); + rd += stride; + } } stride = (1 << size) * nregs; } else { From e318a60b94b152c1e80125861a8917ae177d845e Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 15 Mar 2011 16:26:52 +0000 Subject: [PATCH 041/386] target-arm: Don't leak TCG temp for UNDEFs in Neon load/store space Move the allocation and freeing of the TCG temp used for the address for Neon load/store instructions so that we don't allocate the temporary until we've done enough decoding to know that the instruction is not an UNDEF pattern; this avoids leaking the TCG temp in these cases. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 1dfd4823f5..39512bc62f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3810,7 +3810,6 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) rn = (insn >> 16) & 0xf; rm = insn & 0xf; load = (insn & (1 << 21)) != 0; - addr = tcg_temp_new_i32(); if ((insn & (1 << 23)) == 0) { /* Load store all elements. */ op = (insn >> 8) & 0xf; @@ -3822,6 +3821,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) spacing = neon_ls_element_type[op].spacing; if (size == 3 && (interleave | spacing) != 1) return 1; + addr = tcg_temp_new_i32(); load_reg_var(s, addr, rn); stride = (1 << size) * interleave; for (reg = 0; reg < nregs; reg++) { @@ -3907,6 +3907,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) } rd += spacing; } + tcg_temp_free_i32(addr); stride = nregs * 8; } else { size = (insn >> 10) & 3; @@ -3932,6 +3933,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) if (nregs == 3 && a == 1) { return 1; } + addr = tcg_temp_new_i32(); load_reg_var(s, addr, rn); if (nregs == 1) { /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */ @@ -3955,6 +3957,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) rd += stride; } } + tcg_temp_free_i32(addr); stride = (1 << size) * nregs; } else { /* Single element. */ @@ -3976,6 +3979,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) abort(); } nregs = ((insn >> 8) & 3) + 1; + addr = tcg_temp_new_i32(); load_reg_var(s, addr, rn); for (reg = 0; reg < nregs; reg++) { if (load) { @@ -4017,10 +4021,10 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) rd += stride; tcg_gen_addi_i32(addr, addr, 1 << size); } + tcg_temp_free_i32(addr); stride = nregs * (1 << size); } } - tcg_temp_free_i32(addr); if (rm != 15) { TCGv base; From 366c9332450caace5843c17806ba4879bf2d005c Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 15 Mar 2011 10:47:22 -0600 Subject: [PATCH 042/386] pcnet: Fix sign extension: make ipxe work with >2G RAM The problem is with definitions in hw/pcnet.c such as: #define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) "(S)->csr[29]" is a uint16_t, but "(S)->csr[29] << 16" gets promoted to int, so the overall CSR_CRDA(s) is a (signed) int rather than a uint32_t. This then gets assigned to a uint64_t using target_phys_addr_t crda = CSR_CRDA(s); so when (S)->csr[29] has the high bit set, we end up with crda=0xffffffffxxxxxxxx. From: Michael Brown <mcb30@ipxe.org> Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/pcnet.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 82ccbbd2c3..cf16fd4d01 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -113,23 +113,23 @@ struct qemu_ether_header { #define CSR_XMTRL(S) ((S)->csr[78]) #define CSR_MISSC(S) ((S)->csr[112]) -#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) -#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) -#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) -#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) -#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) -#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) -#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) -#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) -#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) -#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) -#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) -#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) -#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) -#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) +#define CSR_IADR(S) ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16)) +#define CSR_CRBA(S) ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16)) +#define CSR_CXBA(S) ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16)) +#define CSR_NRBA(S) ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16)) +#define CSR_BADR(S) ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16)) +#define CSR_NRDA(S) ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16)) +#define CSR_CRDA(S) ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16)) +#define CSR_BADX(S) ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16)) +#define CSR_NXDA(S) ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16)) +#define CSR_CXDA(S) ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16)) +#define CSR_NNRD(S) ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16)) +#define CSR_NNXD(S) ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16)) +#define CSR_PXDA(S) ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16)) +#define CSR_NXBA(S) ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16)) #define PHYSADDR(S,A) \ - (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16)) struct pcnet_initblk16 { uint16_t mode; From e6b3c8ca0222f6633516c0461a713e7bddc4f076 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 22 Mar 2011 18:21:58 +0000 Subject: [PATCH 043/386] hw/versatilepb, realview: Fix condition for instantiation of onboard NIC Correct the condition determining whether we instantiate the onboard NIC or a PCI card NIC on VersatilePB and Realview boards. This was broken in two ways: (1) if the user asked for two default NICs ("-net nic -net nic") we would crash trying to strcmp() a NULL pointer (2) if the user asked for two NICs explicitly of the same model as the onboard NIC (eg "-net nic,model=smc91c111 -net nic,model=smc91c111") we would try to instantiate two onboard NICs at the same address. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/realview.c | 4 ++-- hw/versatilepb.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/realview.c b/hw/realview.c index a67861ec3c..96fb9da241 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -288,8 +288,8 @@ static void realview_init(ram_addr_t ram_size, for(n = 0; n < nb_nics; n++) { nd = &nd_table[n]; - if ((!nd->model && !done_nic) - || strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0) { + if (!done_nic && (!nd->model || + strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0)) { if (is_pb) { lan9118_init(nd, 0x4e000000, pic[28]); } else { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 9f1bfcf941..46b6a3f383 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -223,7 +223,7 @@ static void versatile_init(ram_addr_t ram_size, for(n = 0; n < nb_nics; n++) { nd = &nd_table[n]; - if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) { + if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) { smc91c111_init(nd, 0x10010000, sic[25]); done_smc = 1; } else { From f68b9d672b90dedc79aeb9b44607f484dbe46a6b Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 22 Mar 2011 18:39:40 +0000 Subject: [PATCH 044/386] net: Improve the warnings for dubious command line option combinations Improve the warnings we give if the user specified a combination of -net options which don't make much sense: * Don't warn about anything if the config is the implicit default "-net user -net nic" rather than one specified by the user (this will only kick in for boards with no NIC or if CONFIG_SLIRP is not set) * Diagnose the case where the user asked for NICs which the board didn't instantiate (for example where the user asked for two NICs but the board only supports one) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- net.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/net.c b/net.c index b2dfaa8085..8d6a555374 100644 --- a/net.c +++ b/net.c @@ -1305,6 +1305,22 @@ void net_check_clients(void) { VLANState *vlan; VLANClientState *vc; + int seen_nics = 0; + + /* Don't warn about the default network setup that you get if + * no command line -net options are specified. There are two + * cases that we would otherwise complain about: + * (1) board doesn't support a NIC but the implicit "-net nic" + * requested one; we'd otherwise complain about more NICs being + * specified than we support, and also that the vlan set up by + * the implicit "-net user" didn't have any NICs connected to it + * (2) CONFIG_SLIRP not set: we'd otherwise complain about the + * implicit "-net nic" setting up a nic that wasn't connected to + * anything. + */ + if (default_net) { + return; + } QTAILQ_FOREACH(vlan, &vlans, next) { int has_nic = 0, has_host_dev = 0; @@ -1312,6 +1328,7 @@ void net_check_clients(void) QTAILQ_FOREACH(vc, &vlan->clients, next) { switch (vc->info->type) { case NET_CLIENT_TYPE_NIC: + seen_nics++; has_nic = 1; break; case NET_CLIENT_TYPE_SLIRP: @@ -1331,12 +1348,26 @@ void net_check_clients(void) vlan->id); } QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + if (vc->info->type == NET_CLIENT_TYPE_NIC) { + seen_nics++; + } if (!vc->peer) { fprintf(stderr, "Warning: %s %s has no peer\n", vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev", vc->name); } } + if (seen_nics != nb_nics) { + /* Number of NICs requested by user on command line doesn't match + * the number the model actually registered with us. + * This will generally only happen for models of embedded boards + * with no PCI bus or similar. PCI based machines can instantiate + * all requested NICs as PCI devices but usually embedded boards + * only have a single NIC. + */ + fprintf(stderr, "Warning: more nics requested than this machine " + "supports; some have been ignored\n"); + } } static int net_init_client(QemuOpts *opts, void *dummy) From f20600f213d4cae223660b4ca2eddf139f5e681e Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Wed, 16 Mar 2011 17:30:21 +0200 Subject: [PATCH 045/386] trace: move trace objects from Makefile to Makefile.objs --- Makefile | 32 -------------------------------- Makefile.objs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 989622b388..1e3f51a881 100644 --- a/Makefile +++ b/Makefile @@ -112,38 +112,6 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -ifeq ($(TRACE_BACKEND),dtrace) -trace.h: trace.h-timestamp trace-dtrace.h -else -trace.h: trace.h-timestamp -endif -trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") - @cmp -s $@ trace.h || cp $@ trace.h - -trace.c: trace.c-timestamp -trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") - @cmp -s $@ trace.c || cp $@ trace.c - -trace.o: trace.c $(GENERATED_HEADERS) - -trace-dtrace.h: trace-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") - -# Normal practice is to name DTrace probe file with a '.d' extension -# but that gets picked up by QEMU's Makefile as an external dependancy -# rule file. So we use '.dtrace' instead -trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp -trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") - @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace - -trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") - -simpletrace.o: simpletrace.c $(GENERATED_HEADERS) - version.o: $(SRC_PATH)/version.rc config-host.mak $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") diff --git a/Makefile.objs b/Makefile.objs index 42301fdf0c..d906a8e5d7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -309,6 +309,38 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o ###################################################################### # trace +ifeq ($(TRACE_BACKEND),dtrace) +trace.h: trace.h-timestamp trace-dtrace.h +else +trace.h: trace.h-timestamp +endif +trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") + @cmp -s $@ trace.h || cp $@ trace.h + +trace.c: trace.c-timestamp +trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") + @cmp -s $@ trace.c || cp $@ trace.c + +trace.o: trace.c $(GENERATED_HEADERS) + +trace-dtrace.h: trace-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependancy +# rule file. So we use '.dtrace' instead +trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace + +trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") + +simpletrace.o: simpletrace.c $(GENERATED_HEADERS) + ifeq ($(TRACE_BACKEND),dtrace) trace-obj-y = trace-dtrace.o else From 65097429ae1929c0c2da5577f6510a1eac82bd7a Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Tue, 15 Mar 2011 00:18:02 +0200 Subject: [PATCH 046/386] qemu-thread.h: include inttypes.h qemu-thread.h relies on uint64_t being defined, but doesn't include inttypes.h explicitly. This makes it easier to use it from vscclient (part of libcacard). --- qemu-thread.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu-thread.h b/qemu-thread.h index edc7ab6858..0a73d50524 100644 --- a/qemu-thread.h +++ b/qemu-thread.h @@ -1,6 +1,8 @@ #ifndef __QEMU_THREAD_H #define __QEMU_THREAD_H 1 +#include <inttypes.h> + typedef struct QemuMutex QemuMutex; typedef struct QemuCond QemuCond; typedef struct QemuThread QemuThread; From 367071447ec5b0dabc5452384bbeb62371838112 Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Sun, 17 Oct 2010 11:40:07 +0200 Subject: [PATCH 047/386] usb-ccid: add CCID bus A CCID device is a smart card reader. It is a USB device, defined at [1]. This patch introduces the usb-ccid device that is a ccid bus. Next patches will introduce two card types to use it, a passthru card and an emulated card. [1] http://www.usb.org/developers/devclass_docs/DWG_Smart-Card_CCID_Rev110. Signed-off-by: Alon Levy <alevy@redhat.com> --- changes from v20->v21: (Jes Sorenson review) * cosmetic changes - fix multi line comments. * reorder fields in USBCCIDState * add reference to COPYING * add --enable-smartcard and --disable-smartcard here (moved from last patch) changes from v19->v20: * checkpatch.pl changes from v18->v19: * merged: ccid.h: add copyright, fix define and remove non C89 comments * add qdev.desc changes from v15->v16: Behavioral changes: * fix abort on client answer after card remove * enable migration * remove side affect code from asserts * return consistent self-powered state * mask out reserved bits in ccid_set_parameters * add missing abRFU in SetParameters (no affect on linux guest) whitefixes / comments / consts defines: * remove stale comment * remove ccid_print_pending_answers if no DEBUG_CCID * replace printf's with DPRINTF, remove DEBUG_CCID, add verbosity defines * use error_report * update copyright (most of the code is not original) * reword known bug comment * add missing closing quote in comment * add missing whitespace on one line * s/CCID_SetParameter/CCID_SetParameters/ * add comments * use define for max packet size Comment for "return consistent self-powered state": the Configuration Descriptor bmAttributes claims we are self powered, but we were returning not self powered to USB_REQ_GET_STATUS control message. In practice, this message is not sent by a linux 2.6.35.10-74.fc14.x86_64 guest (not tested on other guests), unless you issue lsusb -v as root (for example). --- Makefile.objs | 1 + configure | 11 + hw/ccid.h | 59 ++ hw/usb-ccid.c | 1419 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1490 insertions(+) create mode 100644 hw/ccid.h create mode 100644 hw/usb-ccid.c diff --git a/Makefile.objs b/Makefile.objs index d906a8e5d7..7fdfc487fb 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -200,6 +200,7 @@ hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o hw-obj-$(CONFIG_DMA) += dma.o hw-obj-$(CONFIG_HPET) += hpet.o hw-obj-$(CONFIG_APPLESMC) += applesmc.o +hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o diff --git a/configure b/configure index 7d8d890891..01ee94d009 100755 --- a/configure +++ b/configure @@ -175,6 +175,7 @@ trace_backend="nop" trace_file="trace" spice="" rbd="" +smartcard="" # parse CC options first for opt do @@ -724,6 +725,10 @@ for opt do ;; --enable-rbd) rbd="yes" ;; + --disable-smartcard) smartcard="no" + ;; + --enable-smartcard) smartcard="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -921,6 +926,8 @@ echo " Default:trace-<pid>" echo " --disable-spice disable spice" echo " --enable-spice enable spice" echo " --enable-rbd enable building the rados block device (rbd)" +echo " --disable-smartcard disable smartcard support" +echo " --enable-smartcard enable smartcard support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -2824,6 +2831,10 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi +if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak diff --git a/hw/ccid.h b/hw/ccid.h new file mode 100644 index 0000000000..dbfc13c4f5 --- /dev/null +++ b/hw/ccid.h @@ -0,0 +1,59 @@ +/* + * CCID Passthru Card Device emulation + * + * Copyright (c) 2011 Red Hat. + * Written by Alon Levy. + * + * This code is licenced under the GNU LGPL, version 2 or later. + */ + +#ifndef CCID_H +#define CCID_H + +#include "qdev.h" + +typedef struct CCIDCardState CCIDCardState; +typedef struct CCIDCardInfo CCIDCardInfo; + +/* + * state of the CCID Card device (i.e. hw/ccid-card-*.c) + */ +struct CCIDCardState { + DeviceState qdev; + uint32_t slot; /* For future use with multiple slot reader. */ +}; + +/* + * callbacks to be used by the CCID device (hw/usb-ccid.c) to call + * into the smartcard device (hw/ccid-card-*.c) + */ +struct CCIDCardInfo { + DeviceInfo qdev; + void (*print)(Monitor *mon, CCIDCardState *card, int indent); + const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len); + void (*apdu_from_guest)(CCIDCardState *card, + const uint8_t *apdu, + uint32_t len); + int (*exitfn)(CCIDCardState *card); + int (*initfn)(CCIDCardState *card); +}; + +/* + * API for smartcard calling the CCID device (used by hw/ccid-card-*.c) + */ +void ccid_card_send_apdu_to_guest(CCIDCardState *card, + uint8_t *apdu, + uint32_t len); +void ccid_card_card_removed(CCIDCardState *card); +void ccid_card_card_inserted(CCIDCardState *card); +void ccid_card_card_error(CCIDCardState *card, uint64_t error); +void ccid_card_qdev_register(CCIDCardInfo *card); + +/* + * support guest visible insertion/removal of ccid devices based on actual + * devices connected/removed. Called by card implementation (passthru, local) + */ +int ccid_card_ccid_attach(CCIDCardState *card); +void ccid_card_ccid_detach(CCIDCardState *card); + +#endif /* CCID_H */ diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c new file mode 100644 index 0000000000..723b2e325f --- /dev/null +++ b/hw/usb-ccid.c @@ -0,0 +1,1419 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * CCID Device emulation + * + * Written by Alon Levy, with contributions from Robert Relyea. + * + * Based on usb-serial.c, see it's copyright and attributions below. + * + * This work is licensed under the terms of the GNU GPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + * ------- (original copyright & attribution for usb-serial.c below) -------- + * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> + * Written by Paul Brook, reused for FTDI by Samuel Thibault, + */ + +/* + * References: + * + * CCID Specification Revision 1.1 April 22nd 2005 + * "Universal Serial Bus, Device Class: Smart Card" + * Specification for Integrated Circuit(s) Cards Interface Devices + * + * Endianess note: from the spec (1.3) + * "Fields that are larger than a byte are stored in little endian" + * + * KNOWN BUGS + * 1. remove/insert can sometimes result in removed state instead of inserted. + * This is a result of the following: + * symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. This can happen + * when a short packet is sent, as seen in uhci-usb.c, resulting from a urb + * from the guest requesting SPD and us returning a smaller packet. + * Not sure which messages trigger this. + */ + +#include "qemu-common.h" +#include "qemu-error.h" +#include "usb.h" +#include "monitor.h" + +#include "hw/ccid.h" + +#define DPRINTF(s, lvl, fmt, ...) \ +do { \ + if (lvl <= s->debug) { \ + printf("usb-ccid: " fmt , ## __VA_ARGS__); \ + } \ +} while (0) + +#define D_WARN 1 +#define D_INFO 2 +#define D_MORE_INFO 3 +#define D_VERBOSE 4 + +#define CCID_DEV_NAME "usb-ccid" + +/* + * The two options for variable sized buffers: + * make them constant size, for large enough constant, + * or handle the migration complexity - VMState doesn't handle this case. + * sizes are expected never to be exceeded, unless guest misbehaves. + */ +#define BULK_OUT_DATA_SIZE 65536 +#define PENDING_ANSWERS_NUM 128 + +#define BULK_IN_BUF_SIZE 384 +#define BULK_IN_PENDING_NUM 8 + +#define InterfaceOutClass \ + ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8) + +#define InterfaceInClass \ + ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8) + +#define CCID_MAX_PACKET_SIZE 64 + +#define CCID_CONTROL_ABORT 0x1 +#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2 +#define CCID_CONTROL_GET_DATA_RATES 0x3 + +#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID" +#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION +#define CCID_INTERFACE_NAME "CCID Interface" +#define CCID_SERIAL_NUMBER_STRING "1" +/* + * Using Gemplus Vendor and Product id + * Effect on various drivers: + * usbccid.sys (winxp, others untested) is a class driver so it doesn't care. + * linux has a number of class drivers, but openct filters based on + * vendor/product (/etc/openct.conf under fedora), hence Gemplus. + */ +#define CCID_VENDOR_ID 0x08e6 +#define CCID_PRODUCT_ID 0x4433 +#define CCID_DEVICE_VERSION 0x0000 + +/* + * BULK_OUT messages from PC to Reader + * Defined in CCID Rev 1.1 6.1 (page 26) + */ +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62 +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63 +#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65 +#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f +#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c +#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d +#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e +#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a +#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72 +#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73 + +/* + * BULK_IN messages from Reader to PC + * Defined in CCID Rev 1.1 6.2 (page 48) + */ +#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80 +#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81 +#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82 +#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83 +#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84 + +/* + * INTERRUPT_IN messages from Reader to PC + * Defined in CCID Rev 1.1 6.3 (page 56) + */ +#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50 +#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51 + +/* + * Endpoints for CCID - addresses are up to us to decide. + * To support slot insertion and removal we must have an interrupt in ep + * in addition we need a bulk in and bulk out ep + * 5.2, page 20 + */ +#define CCID_INT_IN_EP 1 +#define CCID_BULK_IN_EP 2 +#define CCID_BULK_OUT_EP 3 + +/* bmSlotICCState masks */ +#define SLOT_0_STATE_MASK 1 +#define SLOT_0_CHANGED_MASK 2 + +/* Status codes that go in bStatus (see 6.2.6) */ +enum { + ICC_STATUS_PRESENT_ACTIVE = 0, + ICC_STATUS_PRESENT_INACTIVE, + ICC_STATUS_NOT_PRESENT +}; + +enum { + COMMAND_STATUS_NO_ERROR = 0, + COMMAND_STATUS_FAILED, + COMMAND_STATUS_TIME_EXTENSION_REQUIRED +}; + +/* Error codes that go in bError (see 6.2.6) */ +enum { + ERROR_CMD_NOT_SUPPORTED = 0, + ERROR_CMD_ABORTED = -1, + ERROR_ICC_MUTE = -2, + ERROR_XFR_PARITY_ERROR = -3, + ERROR_XFR_OVERRUN = -4, + ERROR_HW_ERROR = -5, +}; + +/* 6.2.6 RDR_to_PC_SlotStatus definitions */ +enum { + CLOCK_STATUS_RUNNING = 0, + /* + * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H, + * 3 - unkonwn state. rest are RFU + */ +}; + +typedef struct __attribute__ ((__packed__)) CCID_Header { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; +} CCID_Header; + +typedef struct __attribute__ ((__packed__)) CCID_BULK_IN { + CCID_Header hdr; + uint8_t bStatus; /* Only used in BULK_IN */ + uint8_t bError; /* Only used in BULK_IN */ +} CCID_BULK_IN; + +typedef struct __attribute__ ((__packed__)) CCID_SlotStatus { + CCID_BULK_IN b; + uint8_t bClockStatus; +} CCID_SlotStatus; + +typedef struct __attribute__ ((__packed__)) CCID_Parameter { + CCID_BULK_IN b; + uint8_t bProtocolNum; + uint8_t abProtocolDataStructure[0]; +} CCID_Parameter; + +typedef struct __attribute__ ((__packed__)) CCID_DataBlock { + CCID_BULK_IN b; + uint8_t bChainParameter; + uint8_t abData[0]; +} CCID_DataBlock; + +/* 6.1.4 PC_to_RDR_XfrBlock */ +typedef struct __attribute__ ((__packed__)) CCID_XferBlock { + CCID_Header hdr; + uint8_t bBWI; /* Block Waiting Timeout */ + uint16_t wLevelParameter; /* XXX currently unused */ + uint8_t abData[0]; +} CCID_XferBlock; + +typedef struct __attribute__ ((__packed__)) CCID_IccPowerOn { + CCID_Header hdr; + uint8_t bPowerSelect; + uint16_t abRFU; +} CCID_IccPowerOn; + +typedef struct __attribute__ ((__packed__)) CCID_IccPowerOff { + CCID_Header hdr; + uint16_t abRFU; +} CCID_IccPowerOff; + +typedef struct __attribute__ ((__packed__)) CCID_SetParameters { + CCID_Header hdr; + uint8_t bProtocolNum; + uint16_t abRFU; + uint8_t abProtocolDataStructure[0]; +} CCID_SetParameters; + +typedef struct CCID_Notify_Slot_Change { + uint8_t bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */ + uint8_t bmSlotICCState; +} CCID_Notify_Slot_Change; + +/* used for DataBlock response to XferBlock */ +typedef struct Answer { + uint8_t slot; + uint8_t seq; +} Answer; + +/* pending BULK_IN messages */ +typedef struct BulkIn { + uint8_t data[BULK_IN_BUF_SIZE]; + uint32_t len; + uint32_t pos; +} BulkIn; + +enum { + MIGRATION_NONE, + MIGRATION_MIGRATED, +}; + +typedef struct CCIDBus CCIDBus; +typedef struct USBCCIDState USBCCIDState; + +#define MAX_PROTOCOL_SIZE 7 + +/* + * powered - defaults to true, changed by PowerOn/PowerOff messages + */ +struct USBCCIDState { + USBDevice dev; + CCIDBus *bus; + CCIDCardState *card; + CCIDCardInfo *cardinfo; /* caching the info pointer */ + BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */ + uint32_t bulk_in_pending_start; + uint32_t bulk_in_pending_end; /* first free */ + uint32_t bulk_in_pending_num; + BulkIn *current_bulk_in; + uint8_t bulk_out_data[BULK_OUT_DATA_SIZE]; + uint32_t bulk_out_pos; + uint64_t last_answer_error; + Answer pending_answers[PENDING_ANSWERS_NUM]; + uint32_t pending_answers_start; + uint32_t pending_answers_end; + uint32_t pending_answers_num; + uint8_t bError; + uint8_t bmCommandStatus; + uint8_t bProtocolNum; + uint8_t abProtocolDataStructure[MAX_PROTOCOL_SIZE]; + uint32_t ulProtocolDataStructureSize; + uint32_t state_vmstate; + uint32_t migration_target_ip; + uint16_t migration_target_port; + uint8_t migration_state; + uint8_t bmSlotICCState; + uint8_t powered; + uint8_t notify_slot_change; + uint8_t debug; +}; + +/* + * CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9, + * "USB Device Framework", section 9.6.1, in the Universal Serial Bus + * Specification. + * + * This device implemented based on the spec and with an Athena Smart Card + * Reader as reference: + * 0dc3:1004 Athena Smartcard Solutions, Inc. + */ + +static const uint8_t qemu_ccid_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + USB_DT_DEVICE, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x40, /* u8 bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */ + + /* Vendor and product id are arbitrary. */ + /* u16 idVendor */ + CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8, + /* u16 idProduct */ + CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8, + /* u16 bcdDevice */ + CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8, + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01, /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_ccid_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ + 0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xe0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 100/2, /* u8 MaxPower; 50 == 100mA */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x03, /* u8 if_bNumEndpoints; */ + 0x0b, /* u8 if_bInterfaceClass; Smart Card Device Class */ + 0x00, /* u8 if_bInterfaceSubClass; Subclass code */ + 0x00, /* u8 if_bInterfaceProtocol; Protocol code */ + 0x04, /* u8 if_iInterface; Index of string descriptor */ + + /* Smart Card Device Class Descriptor */ + 0x36, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; Functional */ + 0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */ + 0x00, /* + * u8 bMaxSlotIndex; The index of the highest available + * slot on this device. All slots are consecutive starting + * at 00h. + */ + 0x07, /* u8 bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */ + + 0x03, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/ + 0x00, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */ + /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */ + 0xa0, 0x0f, 0x00, 0x00, + /* u32 dwMaximumClock; */ + 0x00, 0x00, 0x01, 0x00, + 0x00, /* u8 bNumClockSupported; * + * 0 means just the default and max. */ + /* u32 dwDataRate ;bps. 9600 == 00002580h */ + 0x80, 0x25, 0x00, 0x00, + /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */ + 0x00, 0xC2, 0x01, 0x00, + 0x00, /* u8 bNumDataRatesSupported; 00 means all rates between + * default and max */ + /* u32 dwMaxIFSD; * + * maximum IFSD supported by CCID for protocol * + * T=1 (Maximum seen from various cards) */ + 0xfe, 0x00, 0x00, 0x00, + /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */ + 0x00, 0x00, 0x00, 0x00, + /* u32 dwMechanical; 0 - no special characteristics. */ + 0x00, 0x00, 0x00, 0x00, + /* + * u32 dwFeatures; + * 0 - No special characteristics + * + 2 Automatic parameter configuration based on ATR data + * + 4 Automatic activation of ICC on inserting + * + 8 Automatic ICC voltage selection + * + 10 Automatic ICC clock frequency change + * + 20 Automatic baud rate change + * + 40 Automatic parameters negotiation made by the CCID + * + 80 automatic PPS made by the CCID + * 100 CCID can set ICC in clock stop mode + * 200 NAD value other then 00 accepted (T=1 protocol) + * + 400 Automatic IFSD exchange as first exchange (T=1) + * One of the following only: + * + 10000 TPDU level exchanges with CCID + * 20000 Short APDU level exchange with CCID + * 40000 Short and Extended APDU level exchange with CCID + * + * + 100000 USB Wake up signaling supported on card + * insertion and removal. Must set bit 5 in bmAttributes + * in Configuration descriptor if 100000 is set. + */ + 0xfe, 0x04, 0x11, 0x00, + /* + * u32 dwMaxCCIDMessageLength; For extended APDU in + * [261 + 10 , 65544 + 10]. Otherwise the minimum is + * wMaxPacketSize of the Bulk-OUT endpoint + */ + 0x12, 0x00, 0x01, 0x00, + 0xFF, /* + * u8 bClassGetResponse; Significant only for CCID that + * offers an APDU level for exchanges. Indicates the + * default class value used by the CCID when it sends a + * Get Response command to perform the transportation of + * an APDU by T=0 protocol + * FFh indicates that the CCID echos the class of the APDU. + */ + 0xFF, /* + * u8 bClassEnvelope; EAPDU only. Envelope command for + * T=0 + */ + 0x00, 0x00, /* + * u16 wLcdLayout; XXYY Number of lines (XX) and chars per + * line for LCD display used for PIN entry. 0000 - no LCD + */ + 0x01, /* + * u8 bPINSupport; 01h PIN Verification, + * 02h PIN Modification + */ + 0x01, /* u8 bMaxCCIDBusySlots; */ + + /* Interrupt-IN endpoint */ + 0x07, /* u8 ep_bLength; */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x80 | CCID_INT_IN_EP, + 0x03, /* u8 ep_bmAttributes; Interrupt */ + /* u16 ep_wMaxPacketSize; */ + CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8), + 0xff, /* u8 ep_bInterval; */ + + /* Bulk-In endpoint */ + 0x07, /* u8 ep_bLength; */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; IN Endpoint 2 */ + 0x80 | CCID_BULK_IN_EP, + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + + /* Bulk-Out endpoint */ + 0x07, /* u8 ep_bLength; */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; OUT Endpoint 3 */ + CCID_BULK_OUT_EP, + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + +}; + +static bool ccid_has_pending_answers(USBCCIDState *s) +{ + return s->pending_answers_num > 0; +} + +static void ccid_clear_pending_answers(USBCCIDState *s) +{ + s->pending_answers_num = 0; + s->pending_answers_start = 0; + s->pending_answers_end = 0; +} + +static void ccid_print_pending_answers(USBCCIDState *s) +{ + Answer *answer; + int i, count; + + DPRINTF(s, D_VERBOSE, "usb-ccid: pending answers:"); + if (!ccid_has_pending_answers(s)) { + DPRINTF(s, D_VERBOSE, " empty\n"); + return; + } + for (i = s->pending_answers_start, count = s->pending_answers_num ; + count > 0; count--, i++) { + answer = &s->pending_answers[i % PENDING_ANSWERS_NUM]; + if (count == 1) { + DPRINTF(s, D_VERBOSE, "%d:%d\n", answer->slot, answer->seq); + } else { + DPRINTF(s, D_VERBOSE, "%d:%d,", answer->slot, answer->seq); + } + } +} + +static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr) +{ + Answer *answer; + + assert(s->pending_answers_num < PENDING_ANSWERS_NUM); + s->pending_answers_num++; + answer = + &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM]; + answer->slot = hdr->bSlot; + answer->seq = hdr->bSeq; + ccid_print_pending_answers(s); +} + +static void ccid_remove_pending_answer(USBCCIDState *s, + uint8_t *slot, uint8_t *seq) +{ + Answer *answer; + + assert(s->pending_answers_num > 0); + s->pending_answers_num--; + answer = + &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM]; + *slot = answer->slot; + *seq = answer->seq; + ccid_print_pending_answers(s); +} + +static void ccid_bulk_in_clear(USBCCIDState *s) +{ + s->bulk_in_pending_start = 0; + s->bulk_in_pending_end = 0; + s->bulk_in_pending_num = 0; +} + +static void ccid_bulk_in_release(USBCCIDState *s) +{ + assert(s->current_bulk_in != NULL); + s->current_bulk_in->pos = 0; + s->current_bulk_in = NULL; +} + +static void ccid_bulk_in_get(USBCCIDState *s) +{ + if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) { + return; + } + assert(s->bulk_in_pending_num > 0); + s->bulk_in_pending_num--; + s->current_bulk_in = + &s->bulk_in_pending[(s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM]; +} + +static void *ccid_reserve_recv_buf(USBCCIDState *s, uint16_t len) +{ + BulkIn *bulk_in; + + DPRINTF(s, D_VERBOSE, "%s: QUEUE: reserve %d bytes\n", __func__, len); + + /* look for an existing element */ + if (len > BULK_IN_BUF_SIZE) { + DPRINTF(s, D_WARN, "usb-ccid.c: %s: len larger then max (%d>%d). " + "discarding message.\n", + __func__, len, BULK_IN_BUF_SIZE); + return NULL; + } + if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) { + DPRINTF(s, D_WARN, "usb-ccid.c: %s: No free bulk_in buffers. " + "discarding message.\n", __func__); + return NULL; + } + bulk_in = + &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM]; + s->bulk_in_pending_num++; + bulk_in->len = len; + return bulk_in->data; +} + +static void ccid_reset(USBCCIDState *s) +{ + ccid_bulk_in_clear(s); + ccid_clear_pending_answers(s); +} + +static void ccid_detach(USBCCIDState *s) +{ + ccid_reset(s); +} + +static void ccid_handle_reset(USBDevice *dev) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + + DPRINTF(s, 1, "Reset\n"); + + ccid_reset(s); +} + +static int ccid_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + int ret = 0; + + DPRINTF(s, 1, "got control %x, value %x\n", request, value); + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_ccid_dev_descriptor, + sizeof(qemu_ccid_dev_descriptor)); + ret = sizeof(qemu_ccid_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_ccid_config_descriptor, + sizeof(qemu_ccid_config_descriptor)); + ret = sizeof(qemu_ccid_config_descriptor); + break; + case USB_DT_STRING: + switch (value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING); + break; + case 4: + /* interface name */ + ret = set_usb_string(data, CCID_INTERFACE_NAME); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + /* Only one configuration - we just ignore the request */ + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + ret = 0; + break; + + /* Class specific requests. */ + case InterfaceOutClass | CCID_CONTROL_ABORT: + DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES: + DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES: + DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + default: +fail: + DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n", + request, value); + ret = USB_RET_STALL; + break; + } + return ret; +} + +static bool ccid_card_inserted(USBCCIDState *s) +{ + return s->bmSlotICCState & SLOT_0_STATE_MASK; +} + +static uint8_t ccid_card_status(USBCCIDState *s) +{ + return ccid_card_inserted(s) + ? (s->powered ? + ICC_STATUS_PRESENT_ACTIVE + : ICC_STATUS_PRESENT_INACTIVE + ) + : ICC_STATUS_NOT_PRESENT; +} + +static uint8_t ccid_calc_status(USBCCIDState *s) +{ + /* + * page 55, 6.2.6, calculation of bStatus from bmICCStatus and + * bmCommandStatus + */ + uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6); + DPRINTF(s, D_VERBOSE, "status = %d\n", ret); + return ret; +} + +static void ccid_reset_error_status(USBCCIDState *s) +{ + s->bError = ERROR_CMD_NOT_SUPPORTED; + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; +} + +static void ccid_write_slot_status(USBCCIDState *s, CCID_Header *recv) +{ + CCID_SlotStatus *h = ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus)); + if (h == NULL) { + return; + } + h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus; + h->b.hdr.dwLength = 0; + h->b.hdr.bSlot = recv->bSlot; + h->b.hdr.bSeq = recv->bSeq; + h->b.bStatus = ccid_calc_status(s); + h->b.bError = s->bError; + h->bClockStatus = CLOCK_STATUS_RUNNING; + ccid_reset_error_status(s); +} + +static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv) +{ + CCID_Parameter *h; + uint32_t len = s->ulProtocolDataStructureSize; + + h = ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len); + if (h == NULL) { + return; + } + h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters; + h->b.hdr.dwLength = 0; + h->b.hdr.bSlot = recv->bSlot; + h->b.hdr.bSeq = recv->bSeq; + h->b.bStatus = ccid_calc_status(s); + h->b.bError = s->bError; + h->bProtocolNum = s->bProtocolNum; + memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len); + ccid_reset_error_status(s); +} + +static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq, + const uint8_t *data, uint32_t len) +{ + CCID_DataBlock *p = ccid_reserve_recv_buf(s, sizeof(*p) + len); + + if (p == NULL) { + return; + } + p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock; + p->b.hdr.dwLength = cpu_to_le32(len); + p->b.hdr.bSlot = slot; + p->b.hdr.bSeq = seq; + p->b.bStatus = ccid_calc_status(s); + p->b.bError = s->bError; + if (p->b.bError) { + DPRINTF(s, D_VERBOSE, "error %d", p->b.bError); + } + memcpy(p->abData, data, len); + ccid_reset_error_status(s); +} + +static void ccid_write_data_block_answer(USBCCIDState *s, + const uint8_t *data, uint32_t len) +{ + uint8_t seq; + uint8_t slot; + + if (!ccid_has_pending_answers(s)) { + abort(); + } + ccid_remove_pending_answer(s, &slot, &seq); + ccid_write_data_block(s, slot, seq, data, len); +} + +static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv) +{ + const uint8_t *atr = NULL; + uint32_t len = 0; + + if (s->card) { + atr = s->cardinfo->get_atr(s->card, &len); + } + ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len); +} + +static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv) +{ + CCID_SetParameters *ph = (CCID_SetParameters *) recv; + uint32_t len = 0; + if ((ph->bProtocolNum & 3) == 0) { + len = 5; + } + if ((ph->bProtocolNum & 3) == 1) { + len = 7; + } + if (len == 0) { + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->bError = 7; /* Protocol invalid or not supported */ + return; + } + s->bProtocolNum = ph->bProtocolNum; + memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len); + s->ulProtocolDataStructureSize = len; + DPRINTF(s, 1, "%s: using len %d\n", __func__, len); +} + +/* + * must be 5 bytes for T=0, 7 bytes for T=1 + * See page 52 + */ +static const uint8_t abDefaultProtocolDataStructure[7] = { + 0x77, 0x00, 0x00, 0x00, 0x00, 0xfe /*IFSC*/, 0x00 /*NAD*/ }; + +static void ccid_reset_parameters(USBCCIDState *s) +{ + uint32_t len = sizeof(abDefaultProtocolDataStructure); + + s->bProtocolNum = 1; /* T=1 */ + s->ulProtocolDataStructureSize = len; + memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len); +} + +static void ccid_report_error_failed(USBCCIDState *s, uint8_t error) +{ + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->bError = error; +} + +/* NOTE: only a single slot is supported (SLOT_0) */ +static void ccid_on_slot_change(USBCCIDState *s, bool full) +{ + /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 */ + uint8_t current = s->bmSlotICCState; + if (full) { + s->bmSlotICCState |= SLOT_0_STATE_MASK; + } else { + s->bmSlotICCState &= ~SLOT_0_STATE_MASK; + } + if (current != s->bmSlotICCState) { + s->bmSlotICCState |= SLOT_0_CHANGED_MASK; + } + s->notify_slot_change = true; +} + +static void ccid_write_data_block_error( + USBCCIDState *s, uint8_t slot, uint8_t seq) +{ + ccid_write_data_block(s, slot, seq, NULL, 0); +} + +static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) +{ + uint32_t len; + + if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) { + DPRINTF(s, 1, + "usb-ccid: not sending apdu to client, no card connected\n"); + ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq); + return; + } + len = le32_to_cpu(recv->hdr.dwLength); + DPRINTF(s, 1, "%s: seq %d, len %d\n", __func__, + recv->hdr.bSeq, len); + ccid_add_pending_answer(s, (CCID_Header *)recv); + if (s->card) { + s->cardinfo->apdu_from_guest(s->card, recv->abData, len); + } else { + DPRINTF(s, D_WARN, "warning: discarded apdu\n"); + } +} + +/* + * Handle a single USB_TOKEN_OUT, return value returned to guest. + * Return value: + * 0 - all ok + * USB_RET_STALL - failed to handle packet + */ +static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) +{ + CCID_Header *ccid_header; + + if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) { + return USB_RET_STALL; + } + ccid_header = (CCID_Header *)s->bulk_out_data; + memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len); + s->bulk_out_pos += p->len; + if (p->len == CCID_MAX_PACKET_SIZE) { + DPRINTF(s, D_VERBOSE, + "usb-ccid: bulk_in: expecting more packets (%d/%d)\n", + p->len, ccid_header->dwLength); + return 0; + } + if (s->bulk_out_pos < 10) { + DPRINTF(s, 1, + "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n", + __func__); + } else { + DPRINTF(s, D_MORE_INFO, "%s %x\n", __func__, ccid_header->bMessageType); + switch (ccid_header->bMessageType) { + case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus: + ccid_write_slot_status(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn: + DPRINTF(s, 1, "PowerOn: %d\n", + ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect); + s->powered = true; + if (!ccid_card_inserted(s)) { + ccid_report_error_failed(s, ERROR_ICC_MUTE); + } + /* atr is written regardless of error. */ + ccid_write_data_block_atr(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: + DPRINTF(s, 1, "PowerOff\n"); + ccid_reset_error_status(s); + s->powered = false; + ccid_write_slot_status(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock: + ccid_on_apdu_from_guest(s, (CCID_XferBlock *)s->bulk_out_data); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters: + ccid_reset_error_status(s); + ccid_set_parameters(s, ccid_header); + ccid_write_parameters(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters: + ccid_reset_error_status(s); + ccid_reset_parameters(s); + ccid_write_parameters(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters: + ccid_reset_error_status(s); + ccid_write_parameters(s, ccid_header); + break; + default: + DPRINTF(s, 1, + "handle_data: ERROR: unhandled message type %Xh\n", + ccid_header->bMessageType); + /* + * The caller is expecting the device to respond, tell it we + * don't support the operation. + */ + ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED); + ccid_write_slot_status(s, ccid_header); + break; + } + } + s->bulk_out_pos = 0; + return 0; +} + +static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len) +{ + int ret = 0; + + assert(len > 0); + ccid_bulk_in_get(s); + if (s->current_bulk_in != NULL) { + ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len); + memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret); + s->current_bulk_in->pos += ret; + if (s->current_bulk_in->pos == s->current_bulk_in->len) { + ccid_bulk_in_release(s); + } + } else { + /* return when device has no data - usb 2.0 spec Table 8-4 */ + ret = USB_RET_NAK; + } + if (ret > 0) { + DPRINTF(s, D_MORE_INFO, + "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret); + } + if (ret != USB_RET_NAK && ret < len) { + DPRINTF(s, 1, + "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len); + } + return ret; +} + +static int ccid_handle_data(USBDevice *dev, USBPacket *p) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + int ret = 0; + uint8_t *data = p->data; + int len = p->len; + + switch (p->pid) { + case USB_TOKEN_OUT: + ret = ccid_handle_bulk_out(s, p); + break; + + case USB_TOKEN_IN: + switch (p->devep & 0xf) { + case CCID_BULK_IN_EP: + if (!len) { + ret = USB_RET_NAK; + } else { + ret = ccid_bulk_in_copy_to_guest(s, data, len); + } + break; + case CCID_INT_IN_EP: + if (s->notify_slot_change) { + /* page 56, RDR_to_PC_NotifySlotChange */ + data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange; + data[1] = s->bmSlotICCState; + ret = 2; + s->notify_slot_change = false; + s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK; + DPRINTF(s, D_INFO, + "handle_data: int_in: notify_slot_change %X, " + "requested len %d\n", + s->bmSlotICCState, len); + } + break; + default: + DPRINTF(s, 1, "Bad endpoint\n"); + break; + } + break; + default: + DPRINTF(s, 1, "Bad token\n"); + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void ccid_handle_destroy(USBDevice *dev) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + + ccid_bulk_in_clear(s); +} + +static void ccid_flush_pending_answers(USBCCIDState *s) +{ + while (ccid_has_pending_answers(s)) { + ccid_write_data_block_answer(s, NULL, 0); + } +} + +static Answer *ccid_peek_next_answer(USBCCIDState *s) +{ + return s->pending_answers_num == 0 + ? NULL + : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM]; +} + +static void ccid_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) +{ + CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev); + CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info); + + if (info->print) { + info->print(mon, card, indent); + } +} + +struct CCIDBus { + BusState qbus; +}; + +static struct BusInfo ccid_bus_info = { + .name = "ccid-bus", + .size = sizeof(CCIDBus), + .print_dev = ccid_bus_dev_print, + .props = (Property[]) { + DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static CCIDBus *ccid_bus_new(DeviceState *dev) +{ + CCIDBus *bus; + + bus = FROM_QBUS(CCIDBus, qbus_create(&ccid_bus_info, dev, NULL)); + bus->qbus.allow_hotplug = 1; + + return bus; +} + +void ccid_card_send_apdu_to_guest(CCIDCardState *card, + uint8_t *apdu, uint32_t len) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev, + card->qdev.parent_bus->parent); + Answer *answer; + + if (!ccid_has_pending_answers(s)) { + DPRINTF(s, 1, "CCID ERROR: got an APDU without pending answers\n"); + return; + } + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + answer = ccid_peek_next_answer(s); + if (answer == NULL) { + abort(); + } + DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n", + len, answer->seq, answer->slot); + ccid_write_data_block_answer(s, apdu, len); +} + +void ccid_card_card_removed(CCIDCardState *card) +{ + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + ccid_on_slot_change(s, false); + ccid_flush_pending_answers(s); + ccid_reset(s); +} + +int ccid_card_ccid_attach(CCIDCardState *card) +{ + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + DPRINTF(s, 1, "CCID Attach\n"); + if (s->migration_state == MIGRATION_MIGRATED) { + s->migration_state = MIGRATION_NONE; + } + return 0; +} + +void ccid_card_ccid_detach(CCIDCardState *card) +{ + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + DPRINTF(s, 1, "CCID Detach\n"); + if (ccid_card_inserted(s)) { + ccid_on_slot_change(s, false); + } + ccid_detach(s); +} + +void ccid_card_card_error(CCIDCardState *card, uint64_t error) +{ + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->last_answer_error = error; + DPRINTF(s, 1, "VSC_Error: %lX\n", s->last_answer_error); + /* TODO: these error's should be more verbose and propogated to the guest.*/ + /* + * We flush all pending answers on CardRemove message in ccid-card-passthru, + * so check that first to not trigger abort + */ + if (ccid_has_pending_answers(s)) { + ccid_write_data_block_answer(s, NULL, 0); + } +} + +void ccid_card_card_inserted(CCIDCardState *card) +{ + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + ccid_flush_pending_answers(s); + ccid_on_slot_change(s, true); +} + +static int ccid_card_exit(DeviceState *qdev) +{ + int ret = 0; + CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev); + CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info); + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + + if (ccid_card_inserted(s)) { + ccid_card_card_removed(card); + } + if (info->exitfn) { + ret = info->exitfn(card); + } + s->card = NULL; + s->cardinfo = NULL; + return ret; +} + +static int ccid_card_init(DeviceState *qdev, DeviceInfo *base) +{ + CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev); + CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base); + USBCCIDState *s = + DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); + int ret = 0; + + if (card->slot != 0) { + error_report("Warning: usb-ccid supports one slot, can't add %d", + card->slot); + return -1; + } + if (s->card != NULL) { + error_report("Warning: usb-ccid card already full, not adding\n"); + return -1; + } + ret = info->initfn ? info->initfn(card) : ret; + if (ret == 0) { + s->card = card; + s->cardinfo = info; + } + return ret; +} + +void ccid_card_qdev_register(CCIDCardInfo *card) +{ + card->qdev.bus_info = &ccid_bus_info; + card->qdev.init = ccid_card_init; + card->qdev.exit = ccid_card_exit; + qdev_register(&card->qdev); +} + +static int ccid_initfn(USBDevice *dev) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + + s->bus = ccid_bus_new(&dev->qdev); + s->card = NULL; + s->cardinfo = NULL; + s->migration_state = MIGRATION_NONE; + s->migration_target_ip = 0; + s->migration_target_port = 0; + s->dev.speed = USB_SPEED_FULL; + s->notify_slot_change = false; + s->powered = true; + s->pending_answers_num = 0; + s->last_answer_error = 0; + s->bulk_in_pending_start = 0; + s->bulk_in_pending_end = 0; + s->current_bulk_in = NULL; + ccid_reset_error_status(s); + s->bulk_out_pos = 0; + ccid_reset_parameters(s); + ccid_reset(s); + return 0; +} + +static int ccid_post_load(void *opaque, int version_id) +{ + USBCCIDState *s = opaque; + + /* + * This must be done after usb_device_attach, which sets state to ATTACHED, + * while it must be DEFAULT in order to accept packets (like it is after + * reset, but reset will reset our addr and call our reset handler which + * may change state, and we don't want to do that when migrating). + */ + s->dev.state = s->state_vmstate; + return 0; +} + +static void ccid_pre_save(void *opaque) +{ + USBCCIDState *s = opaque; + + s->state_vmstate = s->dev.state; + if (s->dev.attached) { + /* + * Migrating an open device, ignore reconnection CHR_EVENT to avoid an + * erronous detach. + */ + s->migration_state = MIGRATION_MIGRATED; + } +} + +static VMStateDescription bulk_in_vmstate = { + .name = "CCID BulkIn state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BUFFER(data, BulkIn), + VMSTATE_UINT32(len, BulkIn), + VMSTATE_UINT32(pos, BulkIn), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription answer_vmstate = { + .name = "CCID Answer state", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(slot, Answer), + VMSTATE_UINT8(seq, Answer), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription usb_device_vmstate = { + .name = "usb_device", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(addr, USBDevice), + VMSTATE_BUFFER(setup_buf, USBDevice), + VMSTATE_BUFFER(data_buf, USBDevice), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription ccid_vmstate = { + .name = CCID_DEV_NAME, + .version_id = 1, + .minimum_version_id = 1, + .post_load = ccid_post_load, + .pre_save = ccid_pre_save, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice), + VMSTATE_UINT8(debug, USBCCIDState), + VMSTATE_BUFFER(bulk_out_data, USBCCIDState), + VMSTATE_UINT32(bulk_out_pos, USBCCIDState), + VMSTATE_UINT8(bmSlotICCState, USBCCIDState), + VMSTATE_UINT8(powered, USBCCIDState), + VMSTATE_UINT8(notify_slot_change, USBCCIDState), + VMSTATE_UINT64(last_answer_error, USBCCIDState), + VMSTATE_UINT8(bError, USBCCIDState), + VMSTATE_UINT8(bmCommandStatus, USBCCIDState), + VMSTATE_UINT8(bProtocolNum, USBCCIDState), + VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState), + VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState), + VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState, + BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn), + VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState), + VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState), + VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState, + PENDING_ANSWERS_NUM, 1, answer_vmstate, Answer), + VMSTATE_UINT32(pending_answers_num, USBCCIDState), + VMSTATE_UINT8(migration_state, USBCCIDState), + VMSTATE_UINT32(state_vmstate, USBCCIDState), + VMSTATE_END_OF_LIST() + } +}; + +static struct USBDeviceInfo ccid_info = { + .product_desc = "QEMU USB CCID", + .qdev.name = CCID_DEV_NAME, + .qdev.desc = "CCID Rev 1.1 smartcard reader", + .qdev.size = sizeof(USBCCIDState), + .init = ccid_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = ccid_handle_reset, + .handle_control = ccid_handle_control, + .handle_data = ccid_handle_data, + .handle_destroy = ccid_handle_destroy, + .usbdevice_name = "ccid", + .qdev.props = (Property[]) { + DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0), + DEFINE_PROP_END_OF_LIST(), + }, + .qdev.vmsd = &ccid_vmstate, +}; + +static void ccid_register_devices(void) +{ + usb_qdev_register(&ccid_info); +} +device_init(ccid_register_devices) From 0c16524709f38bb529f68c0921e72207606c57b1 Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Wed, 2 Feb 2011 21:48:04 +0200 Subject: [PATCH 048/386] introduce libcacard/vscard_common.h --- Signed-off-by: Alon Levy <alevy@redhat.com> v20->v21 changes: (Jes Sorensen review) * license set to 2+ * long comment fixes, remove empty line at eof. * add reference to COPYING v19->v20 changes: * checkpatch.pl v15->v16 changes: Protocol change: * VSCMsgInit capabilities and magic * removed ReaderResponse, will use Error instead with code==VSC_SUCCESS. * adaded Flush and FlushComplete, remove Reconnect. * define VSCARD_MAGIC * added error code VSC_SUCCESS. Fixes: * update VSCMsgInit comment * fix message type enum * remove underscore from wrapping define * update copyright * updated comments. * Header comment updated * remove C++ style comment * fix comment for VSCMsgError * give names to enums in typedefs --- libcacard/vscard_common.h | 178 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 libcacard/vscard_common.h diff --git a/libcacard/vscard_common.h b/libcacard/vscard_common.h new file mode 100644 index 0000000000..bebd52db17 --- /dev/null +++ b/libcacard/vscard_common.h @@ -0,0 +1,178 @@ +/* Virtual Smart Card protocol definition + * + * This protocol is between a host using virtual smart card readers, + * and a client providing the smart cards, perhaps by emulating them or by + * access to real cards. + * + * Definitions for this protocol: + * Host - user of the card + * Client - owner of the card + * + * The current implementation passes the raw APDU's from 7816 and additionally + * contains messages to setup and teardown readers, handle insertion and + * removal of cards, negotiate the protocol via capabilities and provide + * for error responses. + * + * Copyright (c) 2011 Red Hat. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef VSCARD_COMMON_H +#define VSCARD_COMMON_H + +#include <stdint.h> + +#define VERSION_MAJOR_BITS 11 +#define VERSION_MIDDLE_BITS 11 +#define VERSION_MINOR_BITS 10 + +#define MAKE_VERSION(major, middle, minor) \ + ((major << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \ + | (middle << VERSION_MINOR_BITS) \ + | (minor)) + +/* + * IMPORTANT NOTE on VERSION + * + * The version below MUST be changed whenever a change in this file is made. + * + * The last digit, the minor, is for bug fix changes only. + * + * The middle digit is for backward / forward compatible changes, updates + * to the existing messages, addition of fields. + * + * The major digit is for a breaking change of protocol, presumably + * something that cannot be accomodated with the existing protocol. + */ + +#define VSCARD_VERSION MAKE_VERSION(0, 0, 2) + +typedef enum VSCMsgType { + VSC_Init = 1, + VSC_Error, + VSC_ReaderAdd, + VSC_ReaderRemove, + VSC_ATR, + VSC_CardRemove, + VSC_APDU, + VSC_Flush, + VSC_FlushComplete +} VSCMsgType; + +typedef enum VSCErrorCode { + VSC_SUCCESS = 0, + VSC_GENERAL_ERROR = 1, + VSC_CANNOT_ADD_MORE_READERS, + VSC_CARD_ALREAY_INSERTED, +} VSCErrorCode; + +#define VSCARD_UNDEFINED_READER_ID 0xffffffff +#define VSCARD_MINIMAL_READER_ID 0 + +#define VSCARD_MAGIC (*(uint32_t *)"VSCD") + +/* + * Header + * Each message starts with the header. + * type - message type + * reader_id - used by messages that are reader specific + * length - length of payload (not including header, i.e. zero for + * messages containing empty payloads) + */ +typedef struct VSCMsgHeader { + uint32_t type; + uint32_t reader_id; + uint32_t length; + uint8_t data[0]; +} VSCMsgHeader; + +/* + * VSCMsgInit Client <-> Host + * Client sends it on connection, with its own capabilities. + * Host replies with VSCMsgInit filling in its capabilities. + * + * It is not meant to be used for negotiation, i.e. sending more then + * once from any side, but could be used for that in the future. + */ +typedef struct VSCMsgInit { + uint32_t magic; + uint32_t version; + uint32_t capabilities[1]; /* receiver must check length, + array may grow in the future*/ +} VSCMsgInit; + +/* + * VSCMsgError Client <-> Host + * This message is a response to any of: + * Reader Add + * Reader Remove + * Card Remove + * If the operation was successful then VSC_SUCCESS + * is returned, other wise a specific error code. + */ +typedef struct VSCMsgError { + uint32_t code; +} VSCMsgError; + +/* + * VSCMsgReaderAdd Client -> Host + * Host replies with allocated reader id in VSCMsgError with code==SUCCESS. + * + * name - name of the reader on client side, UTF-8 encoded. Only used + * for client presentation (may be translated to the device presented to the + * guest), protocol wise only reader_id is important. + */ +typedef struct VSCMsgReaderAdd { + uint8_t name[0]; +} VSCMsgReaderAdd; + +/* + * VSCMsgReaderRemove Client -> Host + * The client's reader has been removed. + */ +typedef struct VSCMsgReaderRemove { +} VSCMsgReaderRemove; + +/* + * VSCMsgATR Client -> Host + * Answer to reset. Sent for card insertion or card reset. The reset/insertion + * happens on the client side, they do not require any action from the host. + */ +typedef struct VSCMsgATR { + uint8_t atr[0]; +} VSCMsgATR; + +/* + * VSCMsgCardRemove Client -> Host + * The client card has been removed. + */ +typedef struct VSCMsgCardRemove { +} VSCMsgCardRemove; + +/* + * VSCMsgAPDU Client <-> Host + * Main reason of existance. Transfer a single APDU in either direction. + */ +typedef struct VSCMsgAPDU { + uint8_t data[0]; +} VSCMsgAPDU; + +/* + * VSCMsgFlush Host -> Client + * Request client to send a FlushComplete message when it is done + * servicing all outstanding APDUs + */ +typedef struct VSCMsgFlush { +} VSCMsgFlush; + +/* + * VSCMsgFlush Client -> Host + * Client response to Flush after all APDUs have been processed and + * responses sent. + */ +typedef struct VSCMsgFlushComplete { +} VSCMsgFlushComplete; + +#endif /* VSCARD_COMMON_H */ From edbb21363fbfe40e050f583df921484cbc31c79d Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Sun, 17 Oct 2010 13:10:32 +0200 Subject: [PATCH 049/386] ccid: add passthru card device The passthru ccid card is a device sitting on the usb-ccid bus and using a chardevice to communicate with a remote device using the VSCard protocol defined in libcacard/vscard_common.h Usage docs available in following patch in docs/ccid.txt Signed-off-by: Alon Levy <alevy@redhat.com> --- Changes from v23->v24: * fixed double license line in header. Changes from v20->v21: (Jes Sorensen review) * add reference to COPYING in header * long comment reformatting Changes from v19->v20: * checkpatch.pl Changes from v18->v19: * add qdev.desc * remove .qdev.unplug (no hot unplug support for ccid bus) Changes from v16->v17: * fix wrong cast when receiving VSC_Error * ccid-card-passthru: force chardev user wakeup by sending Init see lengthy comment below. Changes from v15->v16: Behavioral changes: * return correct size * return error instead of assert if client sent too large ATR * don't assert if client sent too large a size, but add asserts for indices to buffer * reset vscard_in indices on chardev disconnect * handle init from client * error if no chardev supplied * use ntoh, hton * eradicate reader_id_t * remove Reconnect usage (removed from VSCARD protocol) * send VSC_SUCCESS on card insert/remove and reader add/remove Style fixes: * width of line fix * update copyright * remove old TODO's * update file header comment * use macros for debug levels * c++ style comment replacement * update copyright license * fix ATR size comment * fix whitespace in struct def * fix DPRINTF prefix * line width fix ccid-card-passthru: force chardev user wakeup by sending Init The problem: how to wakeup the user of the smartcard when the smartcard device is initialized? Long term solution: have a callback interface. This was done via the deprecated so called chardev ioctl interface. Short term solution: do a write. Specifically we write an Init message. And we change the client to send it's own Init message regardless of receiving this one. Additional Init messages will be regarded as acceptable, the first one received after connection establishment is the determining one wrt capabilities. --- Makefile.objs | 2 +- hw/ccid-card-passthru.c | 340 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 hw/ccid-card-passthru.c diff --git a/Makefile.objs b/Makefile.objs index 7fdfc487fb..07063f1933 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -200,7 +200,7 @@ hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o hw-obj-$(CONFIG_DMA) += dma.o hw-obj-$(CONFIG_HPET) += hpet.o hw-obj-$(CONFIG_APPLESMC) += applesmc.o -hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o +hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c new file mode 100644 index 0000000000..8506fed4fc --- /dev/null +++ b/hw/ccid-card-passthru.c @@ -0,0 +1,340 @@ +/* + * CCID Passthru Card Device emulation + * + * Copyright (c) 2011 Red Hat. + * Written by Alon Levy. + * + * This work is licensed under the terms of the GNU GPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#include <arpa/inet.h> + +#include "qemu-char.h" +#include "monitor.h" +#include "hw/ccid.h" +#include "libcacard/vscard_common.h" + +#define DPRINTF(card, lvl, fmt, ...) \ +do { \ + if (lvl <= card->debug) { \ + printf("ccid-card-passthru: " fmt , ## __VA_ARGS__); \ + } \ +} while (0) + +#define D_WARN 1 +#define D_INFO 2 +#define D_MORE_INFO 3 +#define D_VERBOSE 4 + +/* TODO: do we still need this? */ +uint8_t DEFAULT_ATR[] = { +/* + * From some example somewhere + * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28 + */ + +/* From an Athena smart card */ + 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21, + 0x13, 0x08 +}; + + +#define PASSTHRU_DEV_NAME "ccid-card-passthru" +#define VSCARD_IN_SIZE 65536 + +/* maximum size of ATR - from 7816-3 */ +#define MAX_ATR_SIZE 40 + +typedef struct PassthruState PassthruState; + +struct PassthruState { + CCIDCardState base; + CharDriverState *cs; + uint8_t vscard_in_data[VSCARD_IN_SIZE]; + uint32_t vscard_in_pos; + uint32_t vscard_in_hdr; + uint8_t atr[MAX_ATR_SIZE]; + uint8_t atr_length; + uint8_t debug; +}; + +/* + * VSCard protocol over chardev + * This code should not depend on the card type. + */ + +static void ccid_card_vscard_send_msg(PassthruState *s, + VSCMsgType type, uint32_t reader_id, + const uint8_t *payload, uint32_t length) +{ + VSCMsgHeader scr_msg_header; + + scr_msg_header.type = htonl(type); + scr_msg_header.reader_id = htonl(reader_id); + scr_msg_header.length = htonl(length); + qemu_chr_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader)); + qemu_chr_write(s->cs, payload, length); +} + +static void ccid_card_vscard_send_apdu(PassthruState *s, + const uint8_t *apdu, uint32_t length) +{ + ccid_card_vscard_send_msg( + s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length); +} + +static void ccid_card_vscard_send_error(PassthruState *s, + uint32_t reader_id, VSCErrorCode code) +{ + VSCMsgError msg = {.code = htonl(code)}; + + ccid_card_vscard_send_msg( + s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg)); +} + +static void ccid_card_vscard_send_init(PassthruState *s) +{ + VSCMsgInit msg = { + .version = htonl(VSCARD_VERSION), + .magic = VSCARD_MAGIC, + .capabilities = {0} + }; + + ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID, + (uint8_t *)&msg, sizeof(msg)); +} + +static int ccid_card_vscard_can_read(void *opaque) +{ + PassthruState *card = opaque; + + return VSCARD_IN_SIZE >= card->vscard_in_pos ? + VSCARD_IN_SIZE - card->vscard_in_pos : 0; +} + +static void ccid_card_vscard_handle_init( + PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init) +{ + uint32_t *capabilities; + int num_capabilities; + int i; + + capabilities = init->capabilities; + num_capabilities = + 1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); + init->version = ntohl(init->version); + for (i = 0 ; i < num_capabilities; ++i) { + capabilities[i] = ntohl(capabilities[i]); + } + if (init->magic != VSCARD_MAGIC) { + error_report("wrong magic"); + /* we can't disconnect the chardev */ + } + if (init->version != VSCARD_VERSION) { + DPRINTF(card, D_WARN, + "got version %d, have %d", init->version, VSCARD_VERSION); + } + /* future handling of capabilities, none exist atm */ + ccid_card_vscard_send_init(card); +} + +static void ccid_card_vscard_handle_message(PassthruState *card, + VSCMsgHeader *scr_msg_header) +{ + uint8_t *data = (uint8_t *)&scr_msg_header[1]; + + switch (scr_msg_header->type) { + case VSC_ATR: + DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length); + if (scr_msg_header->length > MAX_ATR_SIZE) { + error_report("ATR size exceeds spec, ignoring"); + ccid_card_vscard_send_error(card, scr_msg_header->reader_id, + VSC_GENERAL_ERROR); + } + memcpy(card->atr, data, scr_msg_header->length); + card->atr_length = scr_msg_header->length; + ccid_card_card_inserted(&card->base); + ccid_card_vscard_send_error(card, scr_msg_header->reader_id, + VSC_SUCCESS); + break; + case VSC_APDU: + ccid_card_send_apdu_to_guest( + &card->base, data, scr_msg_header->length); + break; + case VSC_CardRemove: + DPRINTF(card, D_INFO, "VSC_CardRemove\n"); + ccid_card_card_removed(&card->base); + ccid_card_vscard_send_error(card, + scr_msg_header->reader_id, VSC_SUCCESS); + break; + case VSC_Init: + ccid_card_vscard_handle_init( + card, scr_msg_header, (VSCMsgInit *)data); + break; + case VSC_Error: + ccid_card_card_error(&card->base, *(uint32_t *)data); + break; + case VSC_ReaderAdd: + if (ccid_card_ccid_attach(&card->base) < 0) { + ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID, + VSC_CANNOT_ADD_MORE_READERS); + } else { + ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID, + VSC_SUCCESS); + } + break; + case VSC_ReaderRemove: + ccid_card_ccid_detach(&card->base); + ccid_card_vscard_send_error(card, + scr_msg_header->reader_id, VSC_SUCCESS); + break; + default: + printf("usb-ccid: chardev: unexpected message of type %X\n", + scr_msg_header->type); + ccid_card_vscard_send_error(card, scr_msg_header->reader_id, + VSC_GENERAL_ERROR); + } +} + +static void ccid_card_vscard_drop_connection(PassthruState *card) +{ + qemu_chr_close(card->cs); + card->vscard_in_pos = card->vscard_in_hdr = 0; +} + +static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size) +{ + PassthruState *card = opaque; + VSCMsgHeader *hdr; + + if (card->vscard_in_pos + size > VSCARD_IN_SIZE) { + error_report( + "no room for data: pos %d + size %d > %d. dropping connection.", + card->vscard_in_pos, size, VSCARD_IN_SIZE); + ccid_card_vscard_drop_connection(card); + return; + } + assert(card->vscard_in_pos < VSCARD_IN_SIZE); + assert(card->vscard_in_hdr < VSCARD_IN_SIZE); + memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size); + card->vscard_in_pos += size; + hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr); + + while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader)) + &&(card->vscard_in_pos - card->vscard_in_hdr >= + sizeof(VSCMsgHeader) + ntohl(hdr->length))) { + hdr->reader_id = ntohl(hdr->reader_id); + hdr->length = ntohl(hdr->length); + hdr->type = ntohl(hdr->type); + ccid_card_vscard_handle_message(card, hdr); + card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader); + hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr); + } + if (card->vscard_in_hdr == card->vscard_in_pos) { + card->vscard_in_pos = card->vscard_in_hdr = 0; + } +} + +static void ccid_card_vscard_event(void *opaque, int event) +{ + PassthruState *card = opaque; + + switch (event) { + case CHR_EVENT_BREAK: + card->vscard_in_pos = card->vscard_in_hdr = 0; + break; + case CHR_EVENT_FOCUS: + break; + case CHR_EVENT_OPENED: + DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__); + break; + } +} + +/* End VSCard handling */ + +static void passthru_apdu_from_guest( + CCIDCardState *base, const uint8_t *apdu, uint32_t len) +{ + PassthruState *card = DO_UPCAST(PassthruState, base, base); + + if (!card->cs) { + printf("ccid-passthru: no chardev, discarding apdu length %d\n", len); + return; + } + ccid_card_vscard_send_apdu(card, apdu, len); +} + +static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) +{ + PassthruState *card = DO_UPCAST(PassthruState, base, base); + + *len = card->atr_length; + return card->atr; +} + +static int passthru_initfn(CCIDCardState *base) +{ + PassthruState *card = DO_UPCAST(PassthruState, base, base); + + card->vscard_in_pos = 0; + card->vscard_in_hdr = 0; + if (card->cs) { + DPRINTF(card, D_INFO, "initing chardev\n"); + qemu_chr_add_handlers(card->cs, + ccid_card_vscard_can_read, + ccid_card_vscard_read, + ccid_card_vscard_event, card); + ccid_card_vscard_send_init(card); + } else { + error_report("missing chardev"); + return -1; + } + assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE); + memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR)); + card->atr_length = sizeof(DEFAULT_ATR); + return 0; +} + +static int passthru_exitfn(CCIDCardState *base) +{ + return 0; +} + +static VMStateDescription passthru_vmstate = { + .name = PASSTHRU_DEV_NAME, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BUFFER(vscard_in_data, PassthruState), + VMSTATE_UINT32(vscard_in_pos, PassthruState), + VMSTATE_UINT32(vscard_in_hdr, PassthruState), + VMSTATE_BUFFER(atr, PassthruState), + VMSTATE_UINT8(atr_length, PassthruState), + VMSTATE_END_OF_LIST() + } +}; + +static CCIDCardInfo passthru_card_info = { + .qdev.name = PASSTHRU_DEV_NAME, + .qdev.desc = "passthrough smartcard", + .qdev.size = sizeof(PassthruState), + .qdev.vmsd = &passthru_vmstate, + .initfn = passthru_initfn, + .exitfn = passthru_exitfn, + .get_atr = passthru_get_atr, + .apdu_from_guest = passthru_apdu_from_guest, + .qdev.props = (Property[]) { + DEFINE_PROP_CHR("chardev", PassthruState, cs), + DEFINE_PROP_UINT8("debug", PassthruState, debug, 0), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void ccid_card_passthru_register_devices(void) +{ + ccid_card_qdev_register(&passthru_card_info); +} + +device_init(ccid_card_passthru_register_devices) From 111a38b018c86e6651750c5a548ad534f80b5bb5 Mon Sep 17 00:00:00 2001 From: Robert Relyea <rrelyea@redhat.com> Date: Sun, 28 Nov 2010 16:36:38 +0200 Subject: [PATCH 050/386] libcacard: initial commit libcacard emulates a Common Access Card (CAC) which is a standard for smartcards. It is used by the emulated ccid card introduced in a following patch. Docs are available in docs/libcacard.txt Signed-off-by: Alon Levy <alevy@redhat.com> --- changes from v24->v25: * Fix out of tree builds. * Fix build with linux-user targets. changes from v23->v24: (Jes Sorensen review 2) * Makefile.target: use obj-$(CONFIG_*) += * remove unrequired includes, include qemu-common before qemu-thread * required adding #define NO_NSPR_10_SUPPORT (harmless) changes from v22->v23: * configure fixes: (reported by Stefan Hajnoczi) * test a = b, not a == b (second isn't portable) * quote $source_path in case it contains spaces - this doesn't really help since there are many other places that need similar fixes, not introduced by this patch. changes from v21->v22: * fix configure to not link libcacard if nss not found (reported by Stefan Hajnoczi) * fix vscclient linkage with simpletrace backend (reported by Stefan Hajnoczi) * card_7816.c: add missing break in ERROR_DATA_NOT_FOUND (reported by William van de Velde) changes from v20->v21: (Jes Sorensen review) * use qemu infrastructure: qemu-thread, qemu-common (qemu_malloc and qemu_free), error_report * assert instead of ASSERT * cosmetic fixes * use strpbrk and isspace * add --disable-nss --enable-nss here, instead of in the final patch. * split vscclient, passthru and docs to following patches. changes from v19->v20: * checkpatch.pl changes from v15->v16: Build: * don't erase self with distclean * fix make clean after make distclean * Makefile: make vscclient link quiet Behavioral: * vcard_emul_nss: load coolkey in more situations * vscclient: * use hton,ntoh * send init on connect, only start vevent thread on response * read payload after header check, before type switch * remove Reconnect * update for vscard_common changes, empty Flush implementation Style/Whitespace: * fix wrong variable usage * remove unused variable * use only C style comments * add copyright header * fix tabulation Signed-off-by: Alon Levy <alevy@redhat.com> libcacard: fix out of tree builds --- Makefile | 6 +- Makefile.objs | 5 + Makefile.target | 6 + configure | 49 ++ libcacard/Makefile | 20 + libcacard/cac.c | 403 ++++++++++++ libcacard/cac.h | 23 + libcacard/card_7816.c | 763 +++++++++++++++++++++++ libcacard/card_7816.h | 62 ++ libcacard/card_7816t.h | 165 +++++ libcacard/event.c | 106 ++++ libcacard/eventt.h | 29 + libcacard/link_test.c | 22 + libcacard/vcard.c | 339 ++++++++++ libcacard/vcard.h | 86 +++ libcacard/vcard_emul.h | 65 ++ libcacard/vcard_emul_nss.c | 1157 +++++++++++++++++++++++++++++++++++ libcacard/vcard_emul_type.c | 57 ++ libcacard/vcard_emul_type.h | 32 + libcacard/vcardt.h | 64 ++ libcacard/vevent.h | 27 + libcacard/vreader.c | 513 ++++++++++++++++ libcacard/vreader.h | 55 ++ libcacard/vreadert.h | 24 + 24 files changed, 4076 insertions(+), 2 deletions(-) create mode 100644 libcacard/Makefile create mode 100644 libcacard/cac.c create mode 100644 libcacard/cac.h create mode 100644 libcacard/card_7816.c create mode 100644 libcacard/card_7816.h create mode 100644 libcacard/card_7816t.h create mode 100644 libcacard/event.c create mode 100644 libcacard/eventt.h create mode 100644 libcacard/link_test.c create mode 100644 libcacard/vcard.c create mode 100644 libcacard/vcard.h create mode 100644 libcacard/vcard_emul.h create mode 100644 libcacard/vcard_emul_nss.c create mode 100644 libcacard/vcard_emul_type.c create mode 100644 libcacard/vcard_emul_type.h create mode 100644 libcacard/vcardt.h create mode 100644 libcacard/vevent.h create mode 100644 libcacard/vreader.c create mode 100644 libcacard/vreader.h create mode 100644 libcacard/vreadert.h diff --git a/Makefile b/Makefile index 1e3f51a881..fa93be5ed7 100644 --- a/Makefile +++ b/Makefile @@ -141,6 +141,8 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS) check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS) check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS) +QEMULIBS=libhw32 libhw64 libuser libdis libdis-user + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h @@ -152,7 +154,7 @@ clean: rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp rm -f trace-dtrace.h trace-dtrace.h-timestamp $(MAKE) -C tests clean - for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ + for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ rm -f $$d/qemu-options.def; \ done @@ -163,7 +165,7 @@ distclean: clean rm -f roms/seabios/config.mak roms/vgabios/config.mak rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr - for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \ + for d in $(TARGET_DIRS) $(QEMULIBS); do \ rm -rf $$d || exit 1 ; \ done diff --git a/Makefile.objs b/Makefile.objs index 07063f1933..8c425241fc 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -352,6 +352,11 @@ user-obj-y += qemu-timer-common.o endif endif +###################################################################### +# smartcard + +libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o + vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) diff --git a/Makefile.target b/Makefile.target index 565e1fbd04..ace5608016 100644 --- a/Makefile.target +++ b/Makefile.target @@ -358,6 +358,12 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) endif # CONFIG_SOFTMMU +ifndef CONFIG_LINUX_USER +# libcacard needs qemu-thread support, and besides is only needed by devices +# so not requires with linux-user targets +obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y)) +endif # CONFIG_LINUX_USER + obj-y += $(addprefix ../, $(trace-obj-y)) obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o diff --git a/configure b/configure index 01ee94d009..2ef5c75054 100755 --- a/configure +++ b/configure @@ -176,6 +176,7 @@ trace_file="trace" spice="" rbd="" smartcard="" +smartcard_nss="" # parse CC options first for opt do @@ -729,6 +730,10 @@ for opt do ;; --enable-smartcard) smartcard="yes" ;; + --disable-smartcard-nss) smartcard_nss="no" + ;; + --enable-smartcard-nss) smartcard_nss="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -928,6 +933,8 @@ echo " --enable-spice enable spice" echo " --enable-rbd enable building the rados block device (rbd)" echo " --disable-smartcard disable smartcard support" echo " --enable-smartcard enable smartcard support" +echo " --disable-smartcard-nss disable smartcard nss support" +echo " --enable-smartcard-nss enable smartcard nss support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -2311,6 +2318,31 @@ EOF fi fi +# check for libcacard for smartcard support +if test "$smartcard" != "no" ; then + smartcard="yes" + smartcard_cflags="" + # TODO - what's the minimal nss version we support? + if test "$smartcard_nss" != "no"; then + if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then + smartcard_nss="yes" + smartcard_cflags="-I\$(SRC_PATH)/libcacard" + libcacard_libs=$($pkg_config --libs nss 2>/dev/null) + libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null) + QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags" + LIBS="$libcacard_libs $LIBS" + else + if test "$smartcard_nss" = "yes"; then + feature_not_found "nss" + fi + smartcard_nss="no" + fi + fi +fi +if test "$smartcard" = "no" ; then + smartcard_nss="no" +fi + ########################################## ########################################## @@ -2549,6 +2581,7 @@ echo "Trace output file $trace_file-<pid>" echo "spice support $spice" echo "rbd support $rbd" echo "xfsctl support $xfs" +echo "nss used $smartcard_nss" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -2835,6 +2868,10 @@ if test "$smartcard" = "yes" ; then echo "CONFIG_SMARTCARD=y" >> $config_host_mak fi +if test "$smartcard_nss" = "yes" ; then + echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak @@ -3183,6 +3220,11 @@ fi if test "$target_darwin_user" = "yes" ; then echo "CONFIG_DARWIN_USER=y" >> $config_target_mak fi +if test "$smartcard_nss" = "yes" ; then + echo "subdir-$target: subdir-libcacard" >> $config_host_mak + echo "libcacard_libs=$libcacard_libs" >> $config_host_mak + echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak +fi list="" if test ! -z "$gdb_xml_files" ; then for x in $gdb_xml_files; do @@ -3396,6 +3438,13 @@ for hwlib in 32 64; do echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak done +if [ "$source_path" != `pwd` ]; then + # out of tree build + mkdir -p libcacard + rm -f libcacard/Makefile + ln -s "$source_path/libcacard/Makefile" libcacard/Makefile +fi + d=libuser mkdir -p $d symlink $source_path/Makefile.user $d/Makefile diff --git a/libcacard/Makefile b/libcacard/Makefile new file mode 100644 index 0000000000..0211eacb64 --- /dev/null +++ b/libcacard/Makefile @@ -0,0 +1,20 @@ +-include ../config-host.mak +-include $(SRC_PATH)/Makefile.objs +-include $(SRC_PATH)/rules.mak + +$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard) + +ifeq ($(CONFIG_WIN32),y) +QEMU_THREAD=qemu-thread-win32.o +else +QEMU_THREAD=qemu-thread-posix.o +endif + + +QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o) + +QEMU_CFLAGS+=-I../ + +clean: + rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ + diff --git a/libcacard/cac.c b/libcacard/cac.c new file mode 100644 index 0000000000..f34f63ac78 --- /dev/null +++ b/libcacard/cac.c @@ -0,0 +1,403 @@ +/* + * implement the applets for the CAC card. + * + * This code is licensed under the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu-common.h" + +#include "cac.h" +#include "vcard.h" +#include "vcard_emul.h" +#include "card_7816.h" + +#define CAC_GET_PROPERTIES 0x56 +#define CAC_GET_ACR 0x4c +#define CAC_READ_BUFFER 0x52 +#define CAC_UPDATE_BUFFER 0x58 +#define CAC_SIGN_DECRYPT 0x42 +#define CAC_GET_CERTIFICATE 0x36 + +/* private data for PKI applets */ +typedef struct CACPKIAppletDataStruct { + unsigned char *cert; + int cert_len; + unsigned char *cert_buffer; + int cert_buffer_len; + unsigned char *sign_buffer; + int sign_buffer_len; + VCardKey *key; +} CACPKIAppletData; + +/* + * CAC applet private data + */ +struct VCardAppletPrivateStruct { + union { + CACPKIAppletData pki_data; + void *reserved; + } u; +}; + +/* + * handle all the APDU's that are common to all CAC applets + */ +static VCardStatus +cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) +{ + int ef; + + switch (apdu->a_ins) { + case VCARD7816_INS_SELECT_FILE: + if (apdu->a_p1 != 0x02) { + /* let the 7816 code handle applet switches */ + return VCARD_NEXT; + } + /* handle file id setting */ + if (apdu->a_Lc != 2) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_DATA_INVALID); + return VCARD_DONE; + } + /* CAC 1.0 only supports ef = 0 */ + ef = apdu->a_body[0] | (apdu->a_body[1] << 8); + if (ef != 0) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); + return VCARD_DONE; + } + *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); + return VCARD_DONE; + case VCARD7816_INS_GET_RESPONSE: + case VCARD7816_INS_VERIFY: + /* let the 7816 code handle these */ + return VCARD_NEXT; + case CAC_GET_PROPERTIES: + case CAC_GET_ACR: + /* skip these for now, this will probably be needed */ + *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); + return VCARD_DONE; + } + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; +} + +/* + * reset the inter call state between applet selects + */ +static VCardStatus +cac_applet_pki_reset(VCard *card, int channel) +{ + VCardAppletPrivate *applet_private = NULL; + CACPKIAppletData *pki_applet = NULL; + applet_private = vcard_get_current_applet_private(card, channel); + assert(applet_private); + pki_applet = &(applet_private->u.pki_data); + + pki_applet->cert_buffer = NULL; + if (pki_applet->sign_buffer) { + qemu_free(pki_applet->sign_buffer); + pki_applet->sign_buffer = NULL; + } + pki_applet->cert_buffer_len = 0; + pki_applet->sign_buffer_len = 0; + return VCARD_DONE; +} + +static VCardStatus +cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + CACPKIAppletData *pki_applet = NULL; + VCardAppletPrivate *applet_private = NULL; + int size, next; + unsigned char *sign_buffer; + vcard_7816_status_t status; + + applet_private = vcard_get_current_applet_private(card, apdu->a_channel); + assert(applet_private); + pki_applet = &(applet_private->u.pki_data); + + switch (apdu->a_ins) { + case CAC_UPDATE_BUFFER: + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); + return VCARD_DONE; + case CAC_GET_CERTIFICATE: + if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); + break; + } + assert(pki_applet->cert != NULL); + size = apdu->a_Le; + if (pki_applet->cert_buffer == NULL) { + pki_applet->cert_buffer = pki_applet->cert; + pki_applet->cert_buffer_len = pki_applet->cert_len; + } + size = MIN(size, pki_applet->cert_buffer_len); + next = MIN(255, pki_applet->cert_buffer_len - size); + *response = vcard_response_new_bytes( + card, pki_applet->cert_buffer, size, + apdu->a_Le, next ? + VCARD7816_SW1_WARNING_CHANGE : + VCARD7816_SW1_SUCCESS, + next); + pki_applet->cert_buffer += size; + pki_applet->cert_buffer_len -= size; + if ((*response == NULL) || (next == 0)) { + pki_applet->cert_buffer = NULL; + } + if (*response == NULL) { + *response = vcard_make_response( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } + return VCARD_DONE; + case CAC_SIGN_DECRYPT: + if (apdu->a_p2 != 0) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); + break; + } + size = apdu->a_Lc; + + sign_buffer = realloc(pki_applet->sign_buffer, + pki_applet->sign_buffer_len+size); + if (sign_buffer == NULL) { + qemu_free(pki_applet->sign_buffer); + pki_applet->sign_buffer = NULL; + pki_applet->sign_buffer_len = 0; + *response = vcard_make_response( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + return VCARD_DONE; + } + memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size); + size += pki_applet->sign_buffer_len; + switch (apdu->a_p1) { + case 0x80: + /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for + * the rest */ + pki_applet->sign_buffer = sign_buffer; + pki_applet->sign_buffer_len = size; + *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); + return VCARD_DONE; + case 0x00: + /* we now have the whole buffer, do the operation, result will be + * in the sign_buffer */ + status = vcard_emul_rsa_op(card, pki_applet->key, + sign_buffer, size); + if (status != VCARD7816_STATUS_SUCCESS) { + *response = vcard_make_response(status); + break; + } + *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, + VCARD7816_STATUS_SUCCESS); + if (*response == NULL) { + *response = vcard_make_response( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } + break; + default: + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); + break; + } + qemu_free(sign_buffer); + pki_applet->sign_buffer = NULL; + pki_applet->sign_buffer_len = 0; + return VCARD_DONE; + case CAC_READ_BUFFER: + /* new CAC call, go ahead and use the old version for now */ + /* TODO: implement */ + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; + } + return cac_common_process_apdu(card, apdu, response); +} + + +static VCardStatus +cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + switch (apdu->a_ins) { + case CAC_UPDATE_BUFFER: + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); + return VCARD_DONE; + case CAC_READ_BUFFER: + /* new CAC call, go ahead and use the old version for now */ + /* TODO: implement */ + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; + } + return cac_common_process_apdu(card, apdu, response); +} + + +/* + * TODO: if we ever want to support general CAC middleware, we will need to + * implement the various containers. + */ +static VCardStatus +cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + switch (apdu->a_ins) { + case CAC_READ_BUFFER: + case CAC_UPDATE_BUFFER: + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; + default: + break; + } + return cac_common_process_apdu(card, apdu, response); +} + +/* + * utilities for creating and destroying the private applet data + */ +static void +cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) +{ + CACPKIAppletData *pki_applet_data = NULL; + if (pki_applet_data == NULL) { + return; + } + pki_applet_data = &(applet_private->u.pki_data); + if (pki_applet_data->cert != NULL) { + qemu_free(pki_applet_data->cert); + } + if (pki_applet_data->sign_buffer != NULL) { + qemu_free(pki_applet_data->sign_buffer); + } + if (pki_applet_data->key != NULL) { + vcard_emul_delete_key(pki_applet_data->key); + } + qemu_free(applet_private); +} + +static VCardAppletPrivate * +cac_new_pki_applet_private(const unsigned char *cert, + int cert_len, VCardKey *key) +{ + CACPKIAppletData *pki_applet_data = NULL; + VCardAppletPrivate *applet_private = NULL; + applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate)); + + pki_applet_data = &(applet_private->u.pki_data); + pki_applet_data->cert_buffer = NULL; + pki_applet_data->cert_buffer_len = 0; + pki_applet_data->sign_buffer = NULL; + pki_applet_data->sign_buffer_len = 0; + pki_applet_data->key = NULL; + pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1); + /* + * if we want to support compression, then we simply change the 0 to a 1 + * and compress the cert data with libz + */ + pki_applet_data->cert[0] = 0; /* not compressed */ + memcpy(&pki_applet_data->cert[1], cert, cert_len); + pki_applet_data->cert_len = cert_len+1; + + pki_applet_data->key = key; + return applet_private; +} + + +/* + * create a new cac applet which links to a given cert + */ +static VCardApplet * +cac_new_pki_applet(int i, const unsigned char *cert, + int cert_len, VCardKey *key) +{ + VCardAppletPrivate *applet_private = NULL; + VCardApplet *applet = NULL; + unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; + int pki_aid_len = sizeof(pki_aid); + + pki_aid[pki_aid_len-1] = i; + + applet_private = cac_new_pki_applet_private(cert, cert_len, key); + if (applet_private == NULL) { + goto failure; + } + applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, + pki_aid, pki_aid_len); + if (applet == NULL) { + goto failure; + } + vcard_set_applet_private(applet, applet_private, + cac_delete_pki_applet_private); + applet_private = NULL; + + return applet; + +failure: + if (applet_private != NULL) { + cac_delete_pki_applet_private(applet_private); + } + return NULL; +} + + +static unsigned char cac_default_container_aid[] = { + 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; +static unsigned char cac_id_aid[] = { + 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; +/* + * Initialize the cac card. This is the only public function in this file. All + * the rest are connected through function pointers. + */ +VCardStatus +cac_card_init(VReader *reader, VCard *card, + const char *params, + unsigned char * const *cert, + int cert_len[], + VCardKey *key[] /* adopt the keys*/, + int cert_count) +{ + int i; + VCardApplet *applet; + + /* CAC Cards are VM Cards */ + vcard_set_type(card, VCARD_VM); + + /* create one PKI applet for each cert */ + for (i = 0; i < cert_count; i++) { + applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); + if (applet == NULL) { + goto failure; + } + vcard_add_applet(card, applet); + } + + /* create a default blank container applet */ + applet = vcard_new_applet(cac_applet_container_process_apdu, + NULL, cac_default_container_aid, + sizeof(cac_default_container_aid)); + if (applet == NULL) { + goto failure; + } + vcard_add_applet(card, applet); + + /* create a default blank container applet */ + applet = vcard_new_applet(cac_applet_id_process_apdu, + NULL, cac_id_aid, + sizeof(cac_id_aid)); + if (applet == NULL) { + goto failure; + } + vcard_add_applet(card, applet); + return VCARD_DONE; + +failure: + return VCARD_FAIL; +} + diff --git a/libcacard/cac.h b/libcacard/cac.h new file mode 100644 index 0000000000..15a61be980 --- /dev/null +++ b/libcacard/cac.h @@ -0,0 +1,23 @@ +/* + * defines the entry point for the cac card. Only used by cac.c anc + * vcard_emul_type.c + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef CAC_H +#define CAC_H 1 +#include "vcard.h" +#include "vreader.h" +/* + * Initialize the cac card. This is the only public function in this file. All + * the rest are connected through function pointers. + */ +VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params, + unsigned char * const *cert, int cert_len[], + VCardKey *key[] /* adopt the keys*/, + int cert_count); + +/* not yet implemented */ +VCardStatus cac_is_cac_card(VReader *reader); +#endif diff --git a/libcacard/card_7816.c b/libcacard/card_7816.c new file mode 100644 index 0000000000..eeea849895 --- /dev/null +++ b/libcacard/card_7816.c @@ -0,0 +1,763 @@ +/* + * Implement the 7816 portion of the card spec + * + * This code is licensed under the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu-common.h" + +#include "vcard.h" +#include "vcard_emul.h" +#include "card_7816.h" + +/* + * set the status bytes based on the status word + */ +static void +vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status) +{ + unsigned char sw1, sw2; + response->b_status = status; /* make sure the status and swX representations + * are consistent */ + sw1 = (status >> 8) & 0xff; + sw2 = status & 0xff; + response->b_sw1 = sw1; + response->b_sw2 = sw2; + response->b_data[response->b_len] = sw1; + response->b_data[response->b_len+1] = sw2; +} + +/* + * set the status bytes in a response buffer + */ +static void +vcard_response_set_status_bytes(VCardResponse *response, + unsigned char sw1, unsigned char sw2) +{ + response->b_status = sw1 << 8 | sw2; + response->b_sw1 = sw1; + response->b_sw2 = sw2; + response->b_data[response->b_len] = sw1; + response->b_data[response->b_len+1] = sw2; +} + +/* + * allocate a VCardResponse structure, plus space for the data buffer, and + * set up everything but the resonse bytes. + */ +VCardResponse * +vcard_response_new_data(unsigned char *buf, int len) +{ + VCardResponse *new_response; + + new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); + new_response->b_data = qemu_malloc(len + 2); + memcpy(new_response->b_data, buf, len); + new_response->b_total_len = len+2; + new_response->b_len = len; + new_response->b_type = VCARD_MALLOC; + return new_response; +} + +static VCardResponse * +vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) +{ + VCardResponse *response; + VCardBufferResponse *buffer_response; + + buffer_response = vcard_get_buffer_response(card); + if (buffer_response) { + vcard_set_buffer_response(card, NULL); + vcard_buffer_response_delete(buffer_response); + } + buffer_response = vcard_buffer_response_new(buf, len); + if (buffer_response == NULL) { + return NULL; + } + response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, + len > 255 ? 0 : len); + if (response == NULL) { + return NULL; + } + vcard_set_buffer_response(card, buffer_response); + return response; +} + +/* + * general buffer to hold results from APDU calls + */ +VCardResponse * +vcard_response_new(VCard *card, unsigned char *buf, + int len, int Le, vcard_7816_status_t status) +{ + VCardResponse *new_response; + + if (len > Le) { + return vcard_init_buffer_response(card, buf, len); + } + new_response = vcard_response_new_data(buf, len); + if (new_response == NULL) { + return NULL; + } + vcard_response_set_status(new_response, status); + return new_response; +} + +/* + * general buffer to hold results from APDU calls + */ +VCardResponse * +vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, + unsigned char sw1, unsigned char sw2) +{ + VCardResponse *new_response; + + if (len > Le) { + return vcard_init_buffer_response(card, buf, len); + } + new_response = vcard_response_new_data(buf, len); + if (new_response == NULL) { + return NULL; + } + vcard_response_set_status_bytes(new_response, sw1, sw2); + return new_response; +} + +/* + * get a new Reponse buffer that only has a status. + */ +static VCardResponse * +vcard_response_new_status(vcard_7816_status_t status) +{ + VCardResponse *new_response; + + new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); + new_response->b_data = &new_response->b_sw1; + new_response->b_len = 0; + new_response->b_total_len = 2; + new_response->b_type = VCARD_MALLOC_STRUCT; + vcard_response_set_status(new_response, status); + return new_response; +} + +/* + * same as above, but specify the status as separate bytes + */ +VCardResponse * +vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) +{ + VCardResponse *new_response; + + new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); + new_response->b_data = &new_response->b_sw1; + new_response->b_len = 0; + new_response->b_total_len = 2; + new_response->b_type = VCARD_MALLOC_STRUCT; + vcard_response_set_status_bytes(new_response, sw1, sw2); + return new_response; +} + + +/* + * free the response buffer. The Buffer has a type to handle the buffer + * allocated in other ways than through malloc. + */ +void +vcard_response_delete(VCardResponse *response) +{ + if (response == NULL) { + return; + } + switch (response->b_type) { + case VCARD_MALLOC: + /* everything was malloc'ed */ + if (response->b_data) { + qemu_free(response->b_data); + } + qemu_free(response); + break; + case VCARD_MALLOC_DATA: + /* only the data buffer was malloc'ed */ + if (response->b_data) { + qemu_free(response->b_data); + } + break; + case VCARD_MALLOC_STRUCT: + /* only the structure was malloc'ed */ + qemu_free(response); + break; + case VCARD_STATIC: + break; + } +} + +/* + * decode the class bit and set our generic type field, channel, and + * secure messaging values. + */ +static vcard_7816_status_t +vcard_apdu_set_class(VCardAPDU *apdu) { + apdu->a_channel = 0; + apdu->a_secure_messaging = 0; + apdu->a_type = apdu->a_cla & 0xf0; + apdu->a_gen_type = VCARD_7816_ISO; + + /* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */ + switch (apdu->a_type) { + /* we only support the basic types */ + case 0x00: + case 0x80: + case 0x90: + case 0xa0: + apdu->a_channel = apdu->a_cla & 3; + apdu->a_secure_messaging = apdu->a_cla & 0xe; + break; + case 0xb0: + case 0xc0: + break; + + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: + /* Reserved for future use */ + apdu->a_gen_type = VCARD_7816_RFU; + break; + case 0xd0: + case 0xe0: + case 0xf0: + default: + apdu->a_gen_type = + (apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY; + break; + } + return VCARD7816_STATUS_SUCCESS; +} + +/* + * set the Le and Lc fiels according to table 5 of the + * 7816-4 part 4 spec + */ +static vcard_7816_status_t +vcard_apdu_set_length(VCardAPDU *apdu) +{ + int L, Le; + + /* process according to table 5 of the 7816-4 Part 4 spec. + * variable names match the variables in the spec */ + L = apdu->a_len-4; /* fixed APDU header */ + apdu->a_Lc = 0; + apdu->a_Le = 0; + apdu->a_body = NULL; + switch (L) { + case 0: + /* 1 minimal apdu */ + return VCARD7816_STATUS_SUCCESS; + case 1: + /* 2S only return values apdu */ + /* zero maps to 256 here */ + apdu->a_Le = apdu->a_header->ah_Le ? + apdu->a_header->ah_Le : 256; + return VCARD7816_STATUS_SUCCESS; + default: + /* if the ah_Le byte is zero and we have more than + * 1 byte in the header, then we must be using extended Le and Lc. + * process the extended now. */ + if (apdu->a_header->ah_Le == 0) { + if (L < 3) { + /* coding error, need at least 3 bytes */ + return VCARD7816_STATUS_ERROR_WRONG_LENGTH; + } + /* calculate the first extended value. Could be either Le or Lc */ + Le = (apdu->a_header->ah_body[0] << 8) + || apdu->a_header->ah_body[1]; + if (L == 3) { + /* 2E extended, return data only */ + /* zero maps to 65536 */ + apdu->a_Le = Le ? Le : 65536; + return VCARD7816_STATUS_SUCCESS; + } + if (Le == 0) { + /* reserved for future use, probably for next time we need + * to extend the lengths */ + return VCARD7816_STATUS_ERROR_WRONG_LENGTH; + } + /* we know that the first extended value is Lc now */ + apdu->a_Lc = Le; + apdu->a_body = &apdu->a_header->ah_body[2]; + if (L == Le+3) { + /* 3E extended, only body parameters */ + return VCARD7816_STATUS_SUCCESS; + } + if (L == Le+5) { + /* 4E extended, parameters and return data */ + Le = (apdu->a_data[apdu->a_len-2] << 8) + || apdu->a_data[apdu->a_len-1]; + apdu->a_Le = Le ? Le : 65536; + return VCARD7816_STATUS_SUCCESS; + } + return VCARD7816_STATUS_ERROR_WRONG_LENGTH; + } + /* not extended */ + apdu->a_Lc = apdu->a_header->ah_Le; + apdu->a_body = &apdu->a_header->ah_body[0]; + if (L == apdu->a_Lc + 1) { + /* 3S only body parameters */ + return VCARD7816_STATUS_SUCCESS; + } + if (L == apdu->a_Lc + 2) { + /* 4S parameters and return data */ + Le = apdu->a_data[apdu->a_len-1]; + apdu->a_Le = Le ? Le : 256; + return VCARD7816_STATUS_SUCCESS; + } + break; + } + return VCARD7816_STATUS_ERROR_WRONG_LENGTH; +} + +/* + * create a new APDU from a raw set of bytes. This will decode all the + * above fields. users of VCARDAPDU's can then depend on the already decoded + * values. + */ +VCardAPDU * +vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status) +{ + VCardAPDU *new_apdu; + + *status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; + if (len < 4) { + *status = VCARD7816_STATUS_ERROR_WRONG_LENGTH; + return NULL; + } + + new_apdu = (VCardAPDU *)qemu_malloc(sizeof(VCardAPDU)); + new_apdu->a_data = qemu_malloc(len); + memcpy(new_apdu->a_data, raw_apdu, len); + new_apdu->a_len = len; + *status = vcard_apdu_set_class(new_apdu); + if (*status != VCARD7816_STATUS_SUCCESS) { + qemu_free(new_apdu); + return NULL; + } + *status = vcard_apdu_set_length(new_apdu); + if (*status != VCARD7816_STATUS_SUCCESS) { + qemu_free(new_apdu); + new_apdu = NULL; + } + return new_apdu; +} + +void +vcard_apdu_delete(VCardAPDU *apdu) +{ + if (apdu == NULL) { + return; + } + if (apdu->a_data) { + qemu_free(apdu->a_data); + } + qemu_free(apdu); +} + + +/* + * declare response buffers for all the 7816 defined error codes + */ +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) +VCARD_RESPONSE_NEW_STATIC_STATUS( + VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) +VCARD_RESPONSE_NEW_STATIC_STATUS( + VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) +VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) + +/* + * return a single response code. This function cannot fail. It will always + * return a response. + */ +VCardResponse * +vcard_make_response(vcard_7816_status_t status) +{ + VCardResponse *response = NULL; + + switch (status) { + /* known 7816 response codes */ + case VCARD7816_STATUS_SUCCESS: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_SUCCESS); + case VCARD7816_STATUS_WARNING: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING); + case VCARD7816_STATUS_WARNING_RET_CORUPT: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_RET_CORUPT); + case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); + case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); + case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); + case VCARD7816_STATUS_WARNING_CHANGE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_CHANGE); + case VCARD7816_STATUS_WARNING_FILE_FILLED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_WARNING_FILE_FILLED); + case VCARD7816_STATUS_EXC_ERROR: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_EXC_ERROR); + case VCARD7816_STATUS_EXC_ERROR_CHANGE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_EXC_ERROR_CHANGE); + case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + case VCARD7816_STATUS_ERROR_WRONG_LENGTH: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_WRONG_LENGTH); + case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); + case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); + case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); + case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); + case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); + case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); + case VCARD7816_STATUS_ERROR_DATA_INVALID: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_DATA_INVALID); + case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); + case VCARD7816_STATUS_ERROR_DATA_NO_EF: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_DATA_NO_EF); + case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); + case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); + case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); + case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); + case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); + case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); + case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); + case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); + case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); + case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); + case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); + case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); + case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); + case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_INS_CODE_INVALID); + case VCARD7816_STATUS_ERROR_CLA_INVALID: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_CLA_INVALID); + case VCARD7816_STATUS_ERROR_GENERAL: + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_ERROR_GENERAL); + default: + /* we don't know this status code, create a response buffer to + * hold it */ + response = vcard_response_new_status(status); + if (response == NULL) { + /* couldn't allocate the buffer, return memmory error */ + return VCARD_RESPONSE_GET_STATIC( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } + } + assert(response); + return response; +} + +/* + * Add File card support here if you need it. + */ +static VCardStatus +vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + /* TODO: if we want to support a virtual file system card, we do it here. + * It would probably be a pkcs #15 card type */ + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; +} + +/* + * VM card (including java cards) + */ +static VCardStatus +vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + int bytes_to_copy, next_byte_count, count; + VCardApplet *current_applet; + VCardBufferResponse *buffer_response; + vcard_7816_status_t status; + + /* parse the class first */ + if (apdu->a_gen_type != VCARD_7816_ISO) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; + } + + /* use a switch so that if we need to support secure channel stuff later, + * we know where to put it */ + switch (apdu->a_secure_messaging) { + case 0x0: /* no SM */ + break; + case 0x4: /* proprietary SM */ + case 0x8: /* header not authenticated */ + case 0xc: /* header authenticated */ + default: + /* for now, don't try to support secure channel stuff in the + * virtual card. */ + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); + return VCARD_DONE; + } + + /* now parse the instruction */ + switch (apdu->a_ins) { + case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ + case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ + case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ + case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ + case VCARD7816_INS_ERASE_BINARY: /* applet control op */ + case VCARD7816_INS_READ_BINARY: /* applet control op */ + case VCARD7816_INS_WRITE_BINARY: /* applet control op */ + case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ + case VCARD7816_INS_READ_RECORD: /* file op */ + case VCARD7816_INS_WRITE_RECORD: /* file op */ + case VCARD7816_INS_UPDATE_RECORD: /* file op */ + case VCARD7816_INS_APPEND_RECORD: /* file op */ + case VCARD7816_INS_ENVELOPE: + case VCARD7816_INS_PUT_DATA: + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + break; + + case VCARD7816_INS_SELECT_FILE: + if (apdu->a_p1 != 0x04) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); + break; + } + + /* side effect, deselect the current applet if no applet has been found + * */ + current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); + vcard_select_applet(card, apdu->a_channel, current_applet); + if (current_applet) { + unsigned char *aid; + int aid_len; + aid = vcard_applet_get_aid(current_applet, &aid_len); + *response = vcard_response_new(card, aid, aid_len, apdu->a_Le, + VCARD7816_STATUS_SUCCESS); + } else { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); + } + break; + + case VCARD7816_INS_VERIFY: + if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); + } else { + if (apdu->a_Lc == 0) { + /* handle pin count if possible */ + count = vcard_emul_get_login_count(card); + if (count < 0) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); + } else { + if (count > 0xf) { + count = 0xf; + } + *response = vcard_response_new_status_bytes( + VCARD7816_SW1_WARNING_CHANGE, + 0xc0 | count); + if (*response == NULL) { + *response = vcard_make_response( + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } + } + } else { + status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); + *response = vcard_make_response(status); + } + } + break; + + case VCARD7816_INS_GET_RESPONSE: + buffer_response = vcard_get_buffer_response(card); + if (!buffer_response) { + *response = vcard_make_response( + VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); + /* handle error */ + break; + } + bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); + next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); + *response = vcard_response_new_bytes( + card, buffer_response->current, bytes_to_copy, + apdu->a_Le, + next_byte_count ? + VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, + next_byte_count); + buffer_response->current += bytes_to_copy; + buffer_response->len -= bytes_to_copy; + if (*response == NULL || (next_byte_count == 0)) { + vcard_set_buffer_response(card, NULL); + vcard_buffer_response_delete(buffer_response); + } + if (*response == NULL) { + *response = + vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); + } + break; + + case VCARD7816_INS_GET_DATA: + *response = + vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + break; + + default: + *response = + vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + break; + } + + /* response should have been set somewhere */ + assert(*response != NULL); + return VCARD_DONE; +} + + +/* + * APDU processing starts here. This routes the card processing stuff to the + * right location. + */ +VCardStatus +vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) +{ + VCardStatus status; + VCardBufferResponse *buffer_response; + + /* first handle any PTS commands, which aren't really APDU's */ + if (apdu->a_type == VCARD_7816_PTS) { + /* the PTS responses aren't really responses either */ + *response = vcard_response_new_data(apdu->a_data, apdu->a_len); + /* PTS responses have no status bytes */ + (*response)->b_total_len = (*response)->b_len; + return VCARD_DONE; + } + buffer_response = vcard_get_buffer_response(card); + if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { + /* clear out buffer_response, return an error */ + vcard_set_buffer_response(card, NULL); + vcard_buffer_response_delete(buffer_response); + *response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); + return VCARD_DONE; + } + + status = vcard_process_applet_apdu(card, apdu, response); + if (status != VCARD_NEXT) { + return status; + } + switch (vcard_get_type(card)) { + case VCARD_FILE_SYSTEM: + return vcard7816_file_system_process_apdu(card, apdu, response); + case VCARD_VM: + return vcard7816_vm_process_apdu(card, apdu, response); + case VCARD_DIRECT: + /* if we are type direct, then the applet should handle everything */ + assert("VCARD_DIRECT: applet failure"); + break; + } + *response = + vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); + return VCARD_DONE; +} diff --git a/libcacard/card_7816.h b/libcacard/card_7816.h new file mode 100644 index 0000000000..2bb2a0d8aa --- /dev/null +++ b/libcacard/card_7816.h @@ -0,0 +1,62 @@ +/* + * Implement the 7816 portion of the card spec + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef CARD_7816_H +#define CARD_7816_H 1 + +#include "card_7816t.h" +#include "vcardt.h" + +/* + * constructors for VCardResponse's + */ +/* response from a return buffer and a status */ +VCardResponse *vcard_response_new(VCard *card, unsigned char *buf, int len, + int Le, vcard_7816_status_t status); +/* response from a return buffer and status bytes */ +VCardResponse *vcard_response_new_bytes(VCard *card, unsigned char *buf, + int len, int Le, + unsigned char sw1, unsigned char sw2); +/* response from just status bytes */ +VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, + unsigned char sw2); +/* response from just status: NOTE this cannot fail, it will alwyas return a + * valid response, if it can't allocate memory, the response will be + * VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE */ +VCardResponse *vcard_make_response(vcard_7816_status_t status); + +/* create a raw response (status has already been encoded */ +VCardResponse *vcard_response_new_data(unsigned char *buf, int len); + + + + +/* + * destructor for VCardResponse. + * Can be called with a NULL response + */ +void vcard_response_delete(VCardResponse *response); + +/* + * constructor for VCardAPDU + */ +VCardAPDU *vcard_apdu_new(unsigned char *raw_apdu, int len, + unsigned short *status); + +/* + * destructor for VCardAPDU + * Can be called with a NULL apdu + */ +void vcard_apdu_delete(VCardAPDU *apdu); + +/* + * APDU processing starts here. This routes the card processing stuff to the + * right location. Always returns a valid response. + */ +VCardStatus vcard_process_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response); + +#endif diff --git a/libcacard/card_7816t.h b/libcacard/card_7816t.h new file mode 100644 index 0000000000..9333285d73 --- /dev/null +++ b/libcacard/card_7816t.h @@ -0,0 +1,165 @@ +/* + * Implement the 7816 portion of the card spec + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef CARD_7816T_H +#define CARD_7816T_H 1 + +typedef unsigned short vcard_7816_status_t; + +struct VCardResponseStruct { + unsigned char *b_data; + vcard_7816_status_t b_status; + unsigned char b_sw1; + unsigned char b_sw2; + int b_len; + int b_total_len; + enum VCardResponseBufferType { + VCARD_MALLOC, + VCARD_MALLOC_DATA, + VCARD_MALLOC_STRUCT, + VCARD_STATIC + } b_type; +}; + +#define VCARD_RESPONSE_NEW_STATIC_STATUS(stat) \ +static const VCardResponse VCardResponse##stat = \ + {(unsigned char *)&VCardResponse##stat.b_sw1, (stat), ((stat) >> 8), \ + ((stat) & 0xff), 0, 2, VCARD_STATIC}; + +#define VCARD_RESPONSE_NEW_STATIC_STATUS_BYTES(sw1, sw2) \ +static const VCardResponse VCARDResponse##sw1 = \ + {(unsigned char *)&VCardResponse##name.b_sw1, ((sw1) << 8 | (sw2)), \ + (sw1), (sw2), 0, 2, VCARD_STATIC}; + +/* cast away the const, callers need may need to 'free' the + * result, and const implies that they don't */ +#define VCARD_RESPONSE_GET_STATIC(name) \ + ((VCardResponse *)(&VCardResponse##name)) + +typedef enum { + VCARD_7816_ISO, + VCARD_7816_RFU, + VCARD_7816_PTS, + VCARD_7816_PROPIETARY +} VCardAPDUType; + + +/* + * 7816 header. All APDU's have this header. + * They must be laid out in this order. + */ +struct VCardAPDUHeader { + unsigned char ah_cla; + unsigned char ah_ins; + unsigned char ah_p1; + unsigned char ah_p2; + unsigned char ah_Le; + unsigned char ah_body[1]; /* indefinate length */ +}; + +/* + * 7816 APDU structure. The raw bytes are stored in the union and can be + * accessed directly through u.data (which is aliased as a_data). + * + * Names of the fields match the 7816 documentation. + */ +struct VCardAPDUStruct { + int a_len; /* length of the whole buffer, including header */ + int a_Lc; /* 7816 Lc (parameter length) value */ + int a_Le; /* 7816 Le (expected result length) value */ + unsigned char *a_body; /* pointer to the parameter */ + int a_channel; /* decoded channel */ + int a_secure_messaging; /* decoded secure messaging type */ + int a_type; /* decoded type from cla (top nibble of class) */ + VCardAPDUType a_gen_type; /* generic type (7816, PROPRIETARY, RFU, etc) */ + union { + struct VCardAPDUHeader *header; + unsigned char *data; + } u; +/* give the subfields a unified look */ +#define a_header u.header +#define a_data u.data +#define a_cla a_header->ah_cla /* class */ +#define a_ins a_header->ah_ins /* instruction */ +#define a_p1 a_header->ah_p1 /* parameter 1 */ +#define a_p2 a_header->ah_p2 /* parameter 2 */ +}; + +/* 7816 status codes */ +#define VCARD7816_STATUS_SUCCESS 0x9000 +#define VCARD7816_STATUS_WARNING 0x6200 +#define VCARD7816_STATUS_WARNING_RET_CORUPT 0x6281 +#define VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE 0x6282 +#define VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED 0x6283 +#define VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID 0x6284 +#define VCARD7816_STATUS_WARNING_CHANGE 0x6300 +#define VCARD7816_STATUS_WARNING_FILE_FILLED 0x6381 +#define VCARD7816_STATUS_EXC_ERROR 0x6400 +#define VCARD7816_STATUS_EXC_ERROR_CHANGE 0x6500 +#define VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE 0x6581 +#define VCARD7816_STATUS_ERROR_WRONG_LENGTH 0x6700 +#define VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED 0x6800 +#define VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED 0x6881 +#define VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED 0x6882 +#define VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED 0x6900 +#define VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE 0x6981 +#define VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED 0x6982 +#define VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED 0x6983 +#define VCARD7816_STATUS_ERROR_DATA_INVALID 0x6984 +#define VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED 0x6985 +#define VCARD7816_STATUS_ERROR_DATA_NO_EF 0x6986 +#define VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING 0x6987 +#define VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT 0x6988 +#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS 0x6a00 +#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA 0x6a80 +#define VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED 0x6a81 +#define VCARD7816_STATUS_ERROR_FILE_NOT_FOUND 0x6a82 +#define VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND 0x6a83 +#define VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE 0x6a84 +#define VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT 0x6a85 +#define VCARD7816_STATUS_ERROR_P1_P2_INCORRECT 0x6a86 +#define VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT 0x6a87 +#define VCARD7816_STATUS_ERROR_DATA_NOT_FOUND 0x6a88 +#define VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2 0x6b00 +#define VCARD7816_STATUS_ERROR_INS_CODE_INVALID 0x6d00 +#define VCARD7816_STATUS_ERROR_CLA_INVALID 0x6e00 +#define VCARD7816_STATUS_ERROR_GENERAL 0x6f00 +/* 7816 sw1 codes */ +#define VCARD7816_SW1_SUCCESS 0x90 +#define VCARD7816_SW1_RESPONSE_BYTES 0x61 +#define VCARD7816_SW1_WARNING 0x62 +#define VCARD7816_SW1_WARNING_CHANGE 0x63 +#define VCARD7816_SW1_EXC_ERROR 0x64 +#define VCARD7816_SW1_EXC_ERROR_CHANGE 0x65 +#define VCARD7816_SW1_ERROR_WRONG_LENGTH 0x67 +#define VCARD7816_SW1_CLA_ERROR 0x68 +#define VCARD7816_SW1_COMMAND_ERROR 0x69 +#define VCARD7816_SW1_P1_P2_ERROR 0x6a +#define VCARD7816_SW1_LE_ERROR 0x6c +#define VCARD7816_SW1_INS_ERROR 0x6d +#define VCARD7816_SW1_CLA_NOT_SUPPORTED 0x6e + +/* 7816 Instructions */ +#define VCARD7816_INS_MANAGE_CHANNEL 0x70 +#define VCARD7816_INS_EXTERNAL_AUTHENTICATE 0x82 +#define VCARD7816_INS_GET_CHALLENGE 0x84 +#define VCARD7816_INS_INTERNAL_AUTHENTICATE 0x88 +#define VCARD7816_INS_ERASE_BINARY 0x0e +#define VCARD7816_INS_READ_BINARY 0xb0 +#define VCARD7816_INS_WRITE_BINARY 0xd0 +#define VCARD7816_INS_UPDATE_BINARY 0xd6 +#define VCARD7816_INS_READ_RECORD 0xb2 +#define VCARD7816_INS_WRITE_RECORD 0xd2 +#define VCARD7816_INS_UPDATE_RECORD 0xdc +#define VCARD7816_INS_APPEND_RECORD 0xe2 +#define VCARD7816_INS_ENVELOPE 0xc2 +#define VCARD7816_INS_PUT_DATA 0xda +#define VCARD7816_INS_GET_DATA 0xca +#define VCARD7816_INS_SELECT_FILE 0xa4 +#define VCARD7816_INS_VERIFY 0x20 +#define VCARD7816_INS_GET_RESPONSE 0xc0 + +#endif diff --git a/libcacard/event.c b/libcacard/event.c new file mode 100644 index 0000000000..bb2f9219f9 --- /dev/null +++ b/libcacard/event.c @@ -0,0 +1,106 @@ +/* + * event queue implementation. + * + * This code is licensed under the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu-common.h" +#include "qemu-thread.h" + +#include "vcard.h" +#include "vreader.h" +#include "vevent.h" + +VEvent * +vevent_new(VEventType type, VReader *reader, VCard *card) +{ + VEvent *new_vevent; + + new_vevent = (VEvent *)qemu_malloc(sizeof(VEvent)); + new_vevent->next = NULL; + new_vevent->type = type; + new_vevent->reader = vreader_reference(reader); + new_vevent->card = vcard_reference(card); + + return new_vevent; +} + +void +vevent_delete(VEvent *vevent) +{ + if (vevent == NULL) { + return; + } + vreader_free(vevent->reader); + vcard_free(vevent->card); + qemu_free(vevent); +} + +/* + * VEvent queue management + */ + +static VEvent *vevent_queue_head; +static VEvent *vevent_queue_tail; +static QemuMutex vevent_queue_lock; +static QemuCond vevent_queue_condition; + +void vevent_queue_init(void) +{ + qemu_mutex_init(&vevent_queue_lock); + qemu_cond_init(&vevent_queue_condition); + vevent_queue_head = vevent_queue_tail = NULL; +} + +void +vevent_queue_vevent(VEvent *vevent) +{ + vevent->next = NULL; + qemu_mutex_lock(&vevent_queue_lock); + if (vevent_queue_head) { + assert(vevent_queue_tail); + vevent_queue_tail->next = vevent; + } else { + vevent_queue_head = vevent; + } + vevent_queue_tail = vevent; + qemu_cond_signal(&vevent_queue_condition); + qemu_mutex_unlock(&vevent_queue_lock); +} + +/* must have lock */ +static VEvent * +vevent_dequeue_vevent(void) +{ + VEvent *vevent = NULL; + if (vevent_queue_head) { + vevent = vevent_queue_head; + vevent_queue_head = vevent->next; + vevent->next = NULL; + } + return vevent; +} + +VEvent *vevent_wait_next_vevent(void) +{ + VEvent *vevent; + + qemu_mutex_lock(&vevent_queue_lock); + while ((vevent = vevent_dequeue_vevent()) == NULL) { + qemu_cond_wait(&vevent_queue_condition, &vevent_queue_lock); + } + qemu_mutex_unlock(&vevent_queue_lock); + return vevent; +} + +VEvent *vevent_get_next_vevent(void) +{ + VEvent *vevent; + + qemu_mutex_lock(&vevent_queue_lock); + vevent = vevent_dequeue_vevent(); + qemu_mutex_unlock(&vevent_queue_lock); + return vevent; +} + diff --git a/libcacard/eventt.h b/libcacard/eventt.h new file mode 100644 index 0000000000..0dc7bd468c --- /dev/null +++ b/libcacard/eventt.h @@ -0,0 +1,29 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef EVENTT_H +#define EVENTT_H 1 +#include "vreadert.h" +#include "vcardt.h" + +typedef struct VEventStruct VEvent; + +typedef enum { + VEVENT_READER_INSERT, + VEVENT_READER_REMOVE, + VEVENT_CARD_INSERT, + VEVENT_CARD_REMOVE, + VEVENT_LAST, +} VEventType; + +struct VEventStruct { + VEvent *next; + VEventType type; + VReader *reader; + VCard *card; +}; +#endif + + diff --git a/libcacard/link_test.c b/libcacard/link_test.c new file mode 100644 index 0000000000..6f67a23d95 --- /dev/null +++ b/libcacard/link_test.c @@ -0,0 +1,22 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include <stdio.h> +#include "vcard.h" + +VCardStatus cac_card_init(const char *flags, VCard *card, + const unsigned char *cert[], + int cert_len[], VCardKey *key[] /* adopt the keys*/, + int cert_count); +/* + * this will crash... just test the linkage right now + */ + +main(int argc, char **argv) +{ + VCard *card; /* no constructor yet */ + cac_card_init("", card, NULL, 0, NULL, 0); +} + diff --git a/libcacard/vcard.c b/libcacard/vcard.c new file mode 100644 index 0000000000..29b4cce6e5 --- /dev/null +++ b/libcacard/vcard.c @@ -0,0 +1,339 @@ +/* + * implement the Java card standard. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu-common.h" + +#include "vcard.h" +#include "vcard_emul.h" +#include "card_7816t.h" + +struct VCardAppletStruct { + VCardApplet *next; + VCardProcessAPDU process_apdu; + VCardResetApplet reset_applet; + unsigned char *aid; + int aid_len; + void *applet_private; + VCardAppletPrivateFree applet_private_free; +}; + +struct VCardStruct { + int reference_count; + VCardApplet *applet_list; + VCardApplet *current_applet[MAX_CHANNEL]; + VCardBufferResponse *vcard_buffer_response; + VCardType type; + VCardEmul *vcard_private; + VCardEmulFree vcard_private_free; + VCardGetAtr vcard_get_atr; +}; + +VCardBufferResponse * +vcard_buffer_response_new(unsigned char *buffer, int size) +{ + VCardBufferResponse *new_buffer; + + new_buffer = (VCardBufferResponse *)qemu_malloc(sizeof(VCardBufferResponse)); + new_buffer->buffer = (unsigned char *)qemu_malloc(size); + memcpy(new_buffer->buffer, buffer, size); + new_buffer->buffer_len = size; + new_buffer->current = new_buffer->buffer; + new_buffer->len = size; + return new_buffer; +} + +void +vcard_buffer_response_delete(VCardBufferResponse *buffer_response) +{ + if (buffer_response == NULL) { + return; + } + if (buffer_response->buffer) { + qemu_free(buffer_response->buffer); + } + qemu_free(buffer_response); +} + + +/* + * clean up state after a reset + */ +void +vcard_reset(VCard *card, VCardPower power) +{ + int i; + VCardApplet *applet = NULL; + + if (card->type == VCARD_DIRECT) { + /* select the last applet */ + VCardApplet *current_applet = NULL; + for (current_applet = card->applet_list; current_applet; + current_applet = current_applet->next) { + applet = current_applet; + } + } + for (i = 0; i < MAX_CHANNEL; i++) { + card->current_applet[i] = applet; + } + if (card->vcard_buffer_response) { + vcard_buffer_response_delete(card->vcard_buffer_response); + card->vcard_buffer_response = NULL; + } + vcard_emul_reset(card, power); + if (applet) { + applet->reset_applet(card, 0); + } +} + +/* applet utilities */ + +/* + * applet utilities + */ +/* constructor */ +VCardApplet * +vcard_new_applet(VCardProcessAPDU applet_process_function, + VCardResetApplet applet_reset_function, + unsigned char *aid, int aid_len) +{ + VCardApplet *applet; + + applet = (VCardApplet *)qemu_malloc(sizeof(VCardApplet)); + applet->next = NULL; + applet->applet_private = NULL; + applet->applet_private_free = NULL; + applet->process_apdu = applet_process_function; + applet->reset_applet = applet_reset_function; + + applet->aid = qemu_malloc(aid_len); + memcpy(applet->aid, aid, aid_len); + applet->aid_len = aid_len; + return applet; +} + +/* destructor */ +void +vcard_delete_applet(VCardApplet *applet) +{ + if (applet == NULL) { + return; + } + if (applet->applet_private_free) { + applet->applet_private_free(applet->applet_private); + applet->applet_private = NULL; + } + if (applet->aid) { + qemu_free(applet->aid); + applet->aid = NULL; + } + qemu_free(applet); +} + +/* accessor */ +void +vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, + VCardAppletPrivateFree private_free) +{ + if (applet->applet_private_free) { + applet->applet_private_free(applet->applet_private); + } + applet->applet_private = private; + applet->applet_private_free = private_free; +} + +VCard * +vcard_new(VCardEmul *private, VCardEmulFree private_free) +{ + VCard *new_card; + int i; + + new_card = (VCard *)qemu_malloc(sizeof(VCard)); + new_card->applet_list = NULL; + for (i = 0; i < MAX_CHANNEL; i++) { + new_card->current_applet[i] = NULL; + } + new_card->vcard_buffer_response = NULL; + new_card->type = VCARD_VM; + new_card->vcard_private = private; + new_card->vcard_private_free = private_free; + new_card->vcard_get_atr = NULL; + new_card->reference_count = 1; + return new_card; +} + +VCard * +vcard_reference(VCard *vcard) +{ + if (vcard == NULL) { + return NULL; + } + vcard->reference_count++; + return vcard; +} + +void +vcard_free(VCard *vcard) +{ + VCardApplet *current_applet = NULL; + VCardApplet *next_applet = NULL; + + if (vcard == NULL) { + return; + } + vcard->reference_count--; + if (vcard->reference_count != 0) { + return; + } + if (vcard->vcard_private_free) { + (*vcard->vcard_private_free)(vcard->vcard_private); + vcard->vcard_private_free = 0; + vcard->vcard_private = 0; + } + for (current_applet = vcard->applet_list; current_applet; + current_applet = next_applet) { + next_applet = current_applet->next; + vcard_delete_applet(current_applet); + } + vcard_buffer_response_delete(vcard->vcard_buffer_response); + qemu_free(vcard); + return; +} + +void +vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len) +{ + if (vcard->vcard_get_atr) { + (*vcard->vcard_get_atr)(vcard, atr, atr_len); + return; + } + vcard_emul_get_atr(vcard, atr, atr_len); +} + +void +vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr) +{ + card->vcard_get_atr = vcard_get_atr; +} + + +VCardStatus +vcard_add_applet(VCard *card, VCardApplet *applet) +{ + applet->next = card->applet_list; + card->applet_list = applet; + /* if our card-type is direct, always call the applet */ + if (card->type == VCARD_DIRECT) { + int i; + + for (i = 0; i < MAX_CHANNEL; i++) { + card->current_applet[i] = applet; + } + } + return VCARD_DONE; +} + +/* + * manage applets + */ +VCardApplet * +vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) +{ + VCardApplet *current_applet; + + for (current_applet = card->applet_list; current_applet; + current_applet = current_applet->next) { + if (current_applet->aid_len != aid_len) { + continue; + } + if (memcmp(current_applet->aid, aid, aid_len) == 0) { + break; + } + } + return current_applet; +} + +unsigned char * +vcard_applet_get_aid(VCardApplet *applet, int *aid_len) +{ + if (applet == NULL) { + return NULL; + } + *aid_len = applet->aid_len; + return applet->aid; +} + + +void +vcard_select_applet(VCard *card, int channel, VCardApplet *applet) +{ + assert(channel < MAX_CHANNEL); + card->current_applet[channel] = applet; + /* reset the applet */ + if (applet && applet->reset_applet) { + applet->reset_applet(card, channel); + } +} + +VCardAppletPrivate * +vcard_get_current_applet_private(VCard *card, int channel) +{ + VCardApplet *applet = card->current_applet[channel]; + + if (applet == NULL) { + return NULL; + } + return applet->applet_private; +} + +VCardStatus +vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response) +{ + if (card->current_applet[apdu->a_channel]) { + return card->current_applet[apdu->a_channel]->process_apdu( + card, apdu, response); + } + return VCARD_NEXT; +} + +/* + * Accessor functions + */ +/* accessor functions for the response buffer */ +VCardBufferResponse * +vcard_get_buffer_response(VCard *card) +{ + return card->vcard_buffer_response; +} + +void +vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer) +{ + card->vcard_buffer_response = buffer; +} + + +/* accessor functions for the type */ +VCardType +vcard_get_type(VCard *card) +{ + return card->type; +} + +void +vcard_set_type(VCard *card, VCardType type) +{ + card->type = type; +} + +/* accessor for private data */ +VCardEmul * +vcard_get_private(VCard *vcard) +{ + return vcard->vcard_private; +} + diff --git a/libcacard/vcard.h b/libcacard/vcard.h new file mode 100644 index 0000000000..47dc70382b --- /dev/null +++ b/libcacard/vcard.h @@ -0,0 +1,86 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef VCARD_H +#define VCARD_H 1 + +#include "vcardt.h" + +/* + * response buffer constructors and destructors. + * + * response buffers are used when we need to return more data than will fit in + * a normal APDU response (nominally 254 bytes). + */ +VCardBufferResponse *vcard_buffer_response_new(unsigned char *buffer, int size); +void vcard_buffer_response_delete(VCardBufferResponse *buffer_response); + + +/* + * clean up state on reset + */ +void vcard_reset(VCard *card, VCardPower power); + +/* + * applet utilities + */ +/* + * Constructor for a VCardApplet + */ +VCardApplet *vcard_new_applet(VCardProcessAPDU applet_process_function, + VCardResetApplet applet_reset_function, + unsigned char *aid, int aid_len); + +/* + * destructor for a VCardApplet + * Can be called with a NULL applet + */ +void vcard_delete_applet(VCardApplet *applet); + +/* accessor - set the card type specific private data */ +void vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *_private, + VCardAppletPrivateFree private_free); + +/* set type of vcard */ +void vcard_set_type(VCard *card, VCardType type); + +/* + * utilities interacting with the current applet + */ +/* add a new applet to a card */ +VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet); +/* find the applet on the card with the given aid */ +VCardApplet *vcard_find_applet(VCard *card, unsigned char *aid, int aid_len); +/* set the following applet to be current on the given channel */ +void vcard_select_applet(VCard *card, int channel, VCardApplet *applet); +/* get the card type specific private data on the given channel */ +VCardAppletPrivate *vcard_get_current_applet_private(VCard *card, int channel); +/* fetch the applet's id */ +unsigned char *vcard_applet_get_aid(VCardApplet *applet, int *aid_len); + +/* process the apdu for the current selected applet/file */ +VCardStatus vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, + VCardResponse **response); +/* + * VCard utilities + */ +/* constructor */ +VCard *vcard_new(VCardEmul *_private, VCardEmulFree private_free); +/* get a reference */ +VCard *vcard_reference(VCard *); +/* destructor (reference counted) */ +void vcard_free(VCard *); +/* get the atr from the card */ +void vcard_get_atr(VCard *card, unsigned char *atr, int *atr_len); +void vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr); + +/* accessor functions for the response buffer */ +VCardBufferResponse *vcard_get_buffer_response(VCard *card); +void vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer); +/* accessor functions for the type */ +VCardType vcard_get_type(VCard *card); +/* get the private data */ +VCardEmul *vcard_get_private(VCard *card); + +#endif diff --git a/libcacard/vcard_emul.h b/libcacard/vcard_emul.h new file mode 100644 index 0000000000..963563f86d --- /dev/null +++ b/libcacard/vcard_emul.h @@ -0,0 +1,65 @@ +/* + * This is the actual card emulator. + * + * These functions can be implemented in different ways on different platforms + * using the underlying system primitives. For Linux it uses NSS, though direct + * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be + * used. On Windows CAPI could be used. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef VCARD_EMUL_H +#define VCARD_EMUL_H 1 + +#include "card_7816t.h" +#include "vcard.h" +#include "vcard_emul_type.h" + +/* + * types + */ +typedef enum { + VCARD_EMUL_OK = 0, + VCARD_EMUL_FAIL, + /* return values by vcard_emul_init */ + VCARD_EMUL_INIT_ALREADY_INITED, +} VCardEmulError; + +/* options are emul specific. call card_emul_parse_args to change a string + * To an options struct */ +typedef struct VCardEmulOptionsStruct VCardEmulOptions; + +/* + * Login functions + */ +/* return the number of login attempts still possible on the card. if unknown, + * return -1 */ +int vcard_emul_get_login_count(VCard *card); +/* login into the card, return the 7816 status word (sw2 || sw1) */ +vcard_7816_status_t vcard_emul_login(VCard *card, unsigned char *pin, + int pin_len); + +/* + * key functions + */ +/* delete a key */ +void vcard_emul_delete_key(VCardKey *key); +/* RSA sign/decrypt with the key, signature happens 'in place' */ +vcard_7816_status_t vcard_emul_rsa_op(VCard *card, VCardKey *key, + unsigned char *buffer, int buffer_size); + +void vcard_emul_reset(VCard *card, VCardPower power); +void vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len); + +/* Re-insert of a card that has been removed by force removal */ +VCardEmulError vcard_emul_force_card_insert(VReader *vreader); +/* Force a card removal even if the card is not physically removed */ +VCardEmulError vcard_emul_force_card_remove(VReader *vreader); + +VCardEmulOptions *vcard_emul_options(const char *args); +VCardEmulError vcard_emul_init(const VCardEmulOptions *options); +void vcard_emul_replay_insertion_events(void); +void vcard_emul_usage(void); +#endif diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c new file mode 100644 index 0000000000..71f2ba3ae5 --- /dev/null +++ b/libcacard/vcard_emul_nss.c @@ -0,0 +1,1157 @@ +/* + * This is the actual card emulator. + * + * These functions can be implemented in different ways on different platforms + * using the underlying system primitives. For Linux it uses NSS, though direct + * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be + * used. On Windows CAPI could be used. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +/* + * NSS headers + */ + +/* avoid including prototypes.h that redefines uint32 */ +#define NO_NSPR_10_SUPPORT + +#include <nss.h> +#include <pk11pub.h> +#include <cert.h> +#include <key.h> +#include <secmod.h> +#include <prthread.h> +#include <secerr.h> + +#include "qemu-common.h" + +#include "vcard.h" +#include "card_7816t.h" +#include "vcard_emul.h" +#include "vreader.h" +#include "vevent.h" + +struct VCardKeyStruct { + CERTCertificate *cert; + PK11SlotInfo *slot; + SECKEYPrivateKey *key; +}; + + +typedef struct VirtualReaderOptionsStruct VirtualReaderOptions; + +struct VReaderEmulStruct { + PK11SlotInfo *slot; + VCardEmulType default_type; + char *type_params; + PRBool present; + int series; + VCard *saved_vcard; +}; + +/* + * NSS Specific options + */ +struct VirtualReaderOptionsStruct { + char *name; + char *vname; + VCardEmulType card_type; + char *type_params; + char **cert_name; + int cert_count; +}; + +struct VCardEmulOptionsStruct { + void *nss_db; + VirtualReaderOptions *vreader; + int vreader_count; + VCardEmulType hw_card_type; + const char *hw_type_params; + PRBool use_hw; +}; + +static int nss_emul_init; + +/* if we have more that just the slot, define + * VCardEmulStruct here */ + +/* + * allocate the set of arrays for certs, cert_len, key + */ +static PRBool +vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp, + VCardKey ***keysp, int cert_count) +{ + *certsp = NULL; + *cert_lenp = NULL; + *keysp = NULL; + *certsp = (unsigned char **)qemu_malloc(sizeof(unsigned char *)*cert_count); + *cert_lenp = (int *)qemu_malloc(sizeof(int)*cert_count); + *keysp = (VCardKey **)qemu_malloc(sizeof(VCardKey *)*cert_count); + return PR_TRUE; +} + +/* + * Emulator specific card information + */ +typedef struct CardEmulCardStruct CardEmulPrivate; + +static VCardEmul * +vcard_emul_new_card(PK11SlotInfo *slot) +{ + PK11_ReferenceSlot(slot); + /* currently we don't need anything other than the slot */ + return (VCardEmul *)slot; +} + +static void +vcard_emul_delete_card(VCardEmul *vcard_emul) +{ + PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul; + if (slot == NULL) { + return; + } + PK11_FreeSlot(slot); +} + +static PK11SlotInfo * +vcard_emul_card_get_slot(VCard *card) +{ + /* note, the card is holding the reference, no need to get another one */ + return (PK11SlotInfo *)vcard_get_private(card); +} + + +/* + * key functions + */ +/* private constructure */ +static VCardKey * +vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert) +{ + VCardKey *key; + + key = (VCardKey *)qemu_malloc(sizeof(VCardKey)); + key->slot = PK11_ReferenceSlot(slot); + key->cert = CERT_DupCertificate(cert); + /* NOTE: if we aren't logged into the token, this could return NULL */ + /* NOTE: the cert is a temp cert, not necessarily the cert in the token, + * use the DER version of this function */ + key->key = PK11_FindKeyByDERCert(slot, cert, NULL); + return key; +} + +/* destructor */ +void +vcard_emul_delete_key(VCardKey *key) +{ + if (!nss_emul_init || (key == NULL)) { + return; + } + if (key->key) { + SECKEY_DestroyPrivateKey(key->key); + key->key = NULL; + } + if (key->cert) { + CERT_DestroyCertificate(key->cert); + } + if (key->slot) { + PK11_FreeSlot(key->slot); + } + return; +} + +/* + * grab the nss key from a VCardKey. If it doesn't exist, try to look it up + */ +static SECKEYPrivateKey * +vcard_emul_get_nss_key(VCardKey *key) +{ + if (key->key) { + return key->key; + } + /* NOTE: if we aren't logged into the token, this could return NULL */ + key->key = PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL); + return key->key; +} + +/* + * Map NSS errors to 7816 errors + */ +static vcard_7816_status_t +vcard_emul_map_error(int error) +{ + switch (error) { + case SEC_ERROR_TOKEN_NOT_LOGGED_IN: + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; + case SEC_ERROR_BAD_DATA: + case SEC_ERROR_OUTPUT_LEN: + case SEC_ERROR_INPUT_LEN: + case SEC_ERROR_INVALID_ARGS: + case SEC_ERROR_INVALID_ALGORITHM: + case SEC_ERROR_NO_KEY: + case SEC_ERROR_INVALID_KEY: + case SEC_ERROR_DECRYPTION_DISALLOWED: + return VCARD7816_STATUS_ERROR_DATA_INVALID; + case SEC_ERROR_NO_MEMORY: + return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; + } + return VCARD7816_STATUS_EXC_ERROR_CHANGE; +} + +/* RSA sign/decrypt with the key, signature happens 'in place' */ +vcard_7816_status_t +vcard_emul_rsa_op(VCard *card, VCardKey *key, + unsigned char *buffer, int buffer_size) +{ + SECKEYPrivateKey *priv_key; + unsigned signature_len; + SECStatus rv; + + if ((!nss_emul_init) || (key == NULL)) { + /* couldn't get the key, indicate that we aren't logged in */ + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; + } + priv_key = vcard_emul_get_nss_key(key); + + /* + * this is only true of the rsa signature + */ + signature_len = PK11_SignatureLen(priv_key); + if (buffer_size != signature_len) { + return VCARD7816_STATUS_ERROR_DATA_INVALID; + } + rv = PK11_PrivDecryptRaw(priv_key, buffer, &signature_len, signature_len, + buffer, buffer_size); + if (rv != SECSuccess) { + return vcard_emul_map_error(PORT_GetError()); + } + assert(buffer_size == signature_len); + return VCARD7816_STATUS_SUCCESS; +} + +/* + * Login functions + */ +/* return the number of login attempts still possible on the card. if unknown, + * return -1 */ +int +vcard_emul_get_login_count(VCard *card) +{ + return -1; +} + +/* login into the card, return the 7816 status word (sw2 || sw1) */ +vcard_7816_status_t +vcard_emul_login(VCard *card, unsigned char *pin, int pin_len) +{ + PK11SlotInfo *slot; + unsigned char *pin_string = NULL; + int i; + SECStatus rv; + + if (!nss_emul_init) { + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; + } + slot = vcard_emul_card_get_slot(card); + /* We depend on the PKCS #11 module internal login state here because we + * create a separate process to handle each guest instance. If we needed + * to handle multiple guests from one process, then we would need to keep + * a lot of extra state in our card structure + * */ + pin_string = qemu_malloc(pin_len+1); + memcpy(pin_string, pin, pin_len); + pin_string[pin_len] = 0; + + /* handle CAC expanded pins correctly */ + for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) { + pin_string[i] = 0; + } + + rv = PK11_Authenticate(slot, PR_FALSE, pin_string); + memset(pin_string, 0, pin_len); /* don't let the pin hang around in memory + to be snooped */ + qemu_free(pin_string); + if (rv == SECSuccess) { + return VCARD7816_STATUS_SUCCESS; + } + /* map the error from port get error */ + return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED; +} + +void +vcard_emul_reset(VCard *card, VCardPower power) +{ + PK11SlotInfo *slot; + + if (!nss_emul_init) { + return; + } + + /* + * if we reset the card (either power on or power off), we lose our login + * state + */ + /* TODO: we may also need to send insertion/removal events? */ + slot = vcard_emul_card_get_slot(card); + PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */ + return; +} + + +static VReader * +vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot) +{ + VReaderList *reader_list = vreader_get_reader_list(); + VReaderListEntry *current_entry = NULL; + + if (reader_list == NULL) { + return NULL; + } + for (current_entry = vreader_list_get_first(reader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *reader = vreader_list_get_reader(current_entry); + VReaderEmul *reader_emul = vreader_get_private(reader); + if (reader_emul->slot == slot) { + return reader; + } + vreader_free(reader); + } + + return NULL; +} + +/* + * create a new reader emul + */ +static VReaderEmul * +vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params) +{ + VReaderEmul *new_reader_emul; + + new_reader_emul = (VReaderEmul *)qemu_malloc(sizeof(VReaderEmul)); + + new_reader_emul->slot = PK11_ReferenceSlot(slot); + new_reader_emul->default_type = type; + new_reader_emul->type_params = strdup(params); + new_reader_emul->present = PR_FALSE; + new_reader_emul->series = 0; + new_reader_emul->saved_vcard = NULL; + return new_reader_emul; +} + +static void +vreader_emul_delete(VReaderEmul *vreader_emul) +{ + if (vreader_emul == NULL) { + return; + } + if (vreader_emul->slot) { + PK11_FreeSlot(vreader_emul->slot); + } + if (vreader_emul->type_params) { + qemu_free(vreader_emul->type_params); + } + qemu_free(vreader_emul); +} + +/* + * TODO: move this to emulater non-specific file + */ +static VCardEmulType +vcard_emul_get_type(VReader *vreader) +{ + VReaderEmul *vreader_emul; + + vreader_emul = vreader_get_private(vreader); + if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) { + return vreader_emul->default_type; + } + + return vcard_emul_type_select(vreader); +} +/* + * TODO: move this to emulater non-specific file + */ +static const char * +vcard_emul_get_type_params(VReader *vreader) +{ + VReaderEmul *vreader_emul; + + vreader_emul = vreader_get_private(vreader); + if (vreader_emul && vreader_emul->type_params) { + return vreader_emul->type_params; + } + + return ""; +} + +/* pull the slot out of the reader private data */ +static PK11SlotInfo * +vcard_emul_reader_get_slot(VReader *vreader) +{ + VReaderEmul *vreader_emul = vreader_get_private(vreader); + if (vreader_emul == NULL) { + return NULL; + } + return vreader_emul->slot; +} + +/* + * Card ATR's map to physical cards. VCARD_ATR_PREFIX will set appropriate + * historical bytes for any software emulated card. The remaining bytes can be + * used to indicate the actual emulator + */ +static const unsigned char nss_atr[] = { VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }; + +void +vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) +{ + int len = MIN(sizeof(nss_atr), *atr_len); + assert(atr != NULL); + + memcpy(atr, nss_atr, len); + *atr_len = len; + return; +} + +/* + * create a new card from certs and keys + */ +static VCard * +vcard_emul_make_card(VReader *reader, + unsigned char * const *certs, int *cert_len, + VCardKey *keys[], int cert_count) +{ + VCardEmul *vcard_emul; + VCard *vcard; + PK11SlotInfo *slot; + VCardEmulType type; + const char *params; + + type = vcard_emul_get_type(reader); + + /* ignore the inserted card */ + if (type == VCARD_EMUL_NONE) { + return NULL; + } + slot = vcard_emul_reader_get_slot(reader); + if (slot == NULL) { + return NULL; + } + + params = vcard_emul_get_type_params(reader); + /* params these can be NULL */ + + vcard_emul = vcard_emul_new_card(slot); + if (vcard_emul == NULL) { + return NULL; + } + vcard = vcard_new(vcard_emul, vcard_emul_delete_card); + if (vcard == NULL) { + vcard_emul_delete_card(vcard_emul); + return NULL; + } + vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count); + return vcard; +} + + +/* + * 'clone' a physical card as a virtual card + */ +static VCard * +vcard_emul_mirror_card(VReader *vreader) +{ + /* + * lookup certs using the C_FindObjects. The Stan Cert handle won't give + * us the real certs until we log in. + */ + PK11GenericObject *firstObj, *thisObj; + int cert_count; + unsigned char **certs; + int *cert_len; + VCardKey **keys; + PK11SlotInfo *slot; + PRBool ret; + + slot = vcard_emul_reader_get_slot(vreader); + if (slot == NULL) { + return NULL; + } + + firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE); + if (firstObj == NULL) { + return NULL; + } + + /* count the certs */ + cert_count = 0; + for (thisObj = firstObj; thisObj; + thisObj = PK11_GetNextGenericObject(thisObj)) { + cert_count++; + } + + if (cert_count == 0) { + PK11_DestroyGenericObjects(firstObj); + return NULL; + } + + /* allocate the arrays */ + ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count); + if (ret == PR_FALSE) { + return NULL; + } + + /* fill in the arrays */ + cert_count = 0; + for (thisObj = firstObj; thisObj; + thisObj = PK11_GetNextGenericObject(thisObj)) { + SECItem derCert; + CERTCertificate *cert; + SECStatus rv; + + rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, + CKA_VALUE, &derCert); + if (rv != SECSuccess) { + continue; + } + /* create floating temp cert. This gives us a cert structure even if + * the token isn't logged in */ + cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, + NULL, PR_FALSE, PR_TRUE); + SECITEM_FreeItem(&derCert, PR_FALSE); + if (cert == NULL) { + continue; + } + + certs[cert_count] = cert->derCert.data; + cert_len[cert_count] = cert->derCert.len; + keys[cert_count] = vcard_emul_make_key(slot, cert); + cert_count++; + CERT_DestroyCertificate(cert); /* key obj still has a reference */ + } + + /* now create the card */ + return vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count); +} + +static VCardEmulType default_card_type = VCARD_EMUL_NONE; +static const char *default_type_params = ""; + +/* + * This thread looks for card and reader insertions and puts events on the + * event queue + */ +static void +vcard_emul_event_thread(void *arg) +{ + PK11SlotInfo *slot; + VReader *vreader; + VReaderEmul *vreader_emul; + VCard *vcard; + SECMODModule *module = (SECMODModule *)arg; + + do { + slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500); + if (slot == NULL) { + break; + } + vreader = vcard_emul_find_vreader_from_slot(slot); + if (vreader == NULL) { + /* new vreader */ + vreader_emul = vreader_emul_new(slot, default_card_type, + default_type_params); + vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, + vreader_emul_delete); + PK11_FreeSlot(slot); + slot = NULL; + vreader_add_reader(vreader); + vreader_free(vreader); + continue; + } + /* card remove/insert */ + vreader_emul = vreader_get_private(vreader); + if (PK11_IsPresent(slot)) { + int series = PK11_GetSlotSeries(slot); + if (series != vreader_emul->series) { + if (vreader_emul->present) { + vreader_insert_card(vreader, NULL); + } + vcard = vcard_emul_mirror_card(vreader); + vreader_insert_card(vreader, vcard); + vcard_free(vcard); + } + vreader_emul->series = series; + vreader_emul->present = 1; + vreader_free(vreader); + PK11_FreeSlot(slot); + continue; + } + if (vreader_emul->present) { + vreader_insert_card(vreader, NULL); + } + vreader_emul->series = 0; + vreader_emul->present = 0; + PK11_FreeSlot(slot); + vreader_free(vreader); + } while (1); +} + +/* if the card is inserted when we start up, make sure our state is correct */ +static void +vcard_emul_init_series(VReader *vreader, VCard *vcard) +{ + VReaderEmul *vreader_emul = vreader_get_private(vreader); + PK11SlotInfo *slot = vreader_emul->slot; + + vreader_emul->present = PK11_IsPresent(slot); + vreader_emul->series = PK11_GetSlotSeries(slot); + if (vreader_emul->present == 0) { + vreader_insert_card(vreader, NULL); + } +} + +/* + * each module has a separate wait call, create a thread for each module that + * we are using. + */ +static void +vcard_emul_new_event_thread(SECMODModule *module) +{ + PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread, + module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); +} + +static const VCardEmulOptions default_options = { + .nss_db = NULL, + .vreader = NULL, + .vreader_count = 0, + .hw_card_type = VCARD_EMUL_CAC, + .hw_type_params = "", + .use_hw = PR_TRUE +}; + + +/* + * NSS needs the app to supply a password prompt. In our case the only time + * the password is supplied is as part of the Login APDU. The actual password + * is passed in the pw_arg in that case. In all other cases pw_arg should be + * NULL. + */ +static char * +vcard_emul_get_password(PK11SlotInfo *slot, PRBool retries, void *pw_arg) +{ + /* if it didn't work the first time, don't keep trying */ + if (retries) { + return NULL; + } + /* we are looking up a password when we don't have one in hand */ + if (pw_arg == NULL) { + return NULL; + } + /* TODO: we really should verify that were are using the right slot */ + return PORT_Strdup(pw_arg); +} + +/* Force a card removal even if the card is not physically removed */ +VCardEmulError +vcard_emul_force_card_remove(VReader *vreader) +{ + if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) { + return VCARD_EMUL_FAIL; /* card is already removed */ + } + + /* OK, remove it */ + vreader_insert_card(vreader, NULL); + return VCARD_EMUL_OK; +} + +/* Re-insert of a card that has been removed by force removal */ +VCardEmulError +vcard_emul_force_card_insert(VReader *vreader) +{ + VReaderEmul *vreader_emul; + VCard *vcard; + + if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) { + return VCARD_EMUL_FAIL; /* card is already removed */ + } + vreader_emul = vreader_get_private(vreader); + + /* if it's a softcard, get the saved vcard from the reader emul structure */ + if (vreader_emul->saved_vcard) { + vcard = vcard_reference(vreader_emul->saved_vcard); + } else { + /* it must be a physical card, rebuild it */ + if (!PK11_IsPresent(vreader_emul->slot)) { + /* physical card has been removed, not way to reinsert it */ + return VCARD_EMUL_FAIL; + } + vcard = vcard_emul_mirror_card(vreader); + } + vreader_insert_card(vreader, vcard); + vcard_free(vcard); + + return VCARD_EMUL_OK; +} + + +static PRBool +module_has_removable_hw_slots(SECMODModule *mod) +{ + int i; + PRBool ret = PR_FALSE; + SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); + + if (!moduleLock) { + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); + return ret; + } + SECMOD_GetReadLock(moduleLock); + for (i = 0; i < mod->slotCount; i++) { + PK11SlotInfo *slot = mod->slots[i]; + if (PK11_IsRemovable(slot) && PK11_IsHW(slot)) { + ret = PR_TRUE; + break; + } + } + SECMOD_ReleaseReadLock(moduleLock); + return ret; +} + +/* Previously we returned FAIL if no readers found. This makes + * no sense when using hardware, since there may be no readers connected + * at the time vcard_emul_init is called, but they will be properly + * recognized later. So Instead return FAIL only if no_hw==1 and no + * vcards can be created (indicates error with certificates provided + * or db), or if any other higher level error (NSS error, missing coolkey). */ +static int vcard_emul_init_called; + +VCardEmulError +vcard_emul_init(const VCardEmulOptions *options) +{ + SECStatus rv; + PRBool ret, has_readers = PR_FALSE, need_coolkey_module; + VReader *vreader; + VReaderEmul *vreader_emul; + SECMODListLock *module_lock; + SECMODModuleList *module_list; + SECMODModuleList *mlp; + int i; + + if (vcard_emul_init_called) { + return VCARD_EMUL_INIT_ALREADY_INITED; + } + vcard_emul_init_called = 1; + vreader_init(); + vevent_queue_init(); + + if (options == NULL) { + options = &default_options; + } + + /* first initialize NSS */ + if (options->nss_db) { + rv = NSS_Init(options->nss_db); + } else { + rv = NSS_Init("sql:/etc/pki/nssdb"); + } + if (rv != SECSuccess) { + return VCARD_EMUL_FAIL; + } + /* Set password callback function */ + PK11_SetPasswordFunc(vcard_emul_get_password); + + /* set up soft cards emulated by software certs rather than physical cards + * */ + for (i = 0; i < options->vreader_count; i++) { + int j; + int cert_count; + unsigned char **certs; + int *cert_len; + VCardKey **keys; + PK11SlotInfo *slot; + + slot = PK11_FindSlotByName(options->vreader[i].name); + if (slot == NULL) { + continue; + } + vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type, + options->vreader[i].type_params); + vreader = vreader_new(options->vreader[i].vname, vreader_emul, + vreader_emul_delete); + vreader_add_reader(vreader); + cert_count = options->vreader[i].cert_count; + + ret = vcard_emul_alloc_arrays(&certs, &cert_len, &keys, + options->vreader[i].cert_count); + if (ret == PR_FALSE) { + continue; + } + cert_count = 0; + for (j = 0; j < options->vreader[i].cert_count; j++) { + /* we should have a better way of identifying certs than by + * nickname here */ + CERTCertificate *cert = PK11_FindCertFromNickname( + options->vreader[i].cert_name[j], + NULL); + if (cert == NULL) { + continue; + } + certs[cert_count] = cert->derCert.data; + cert_len[cert_count] = cert->derCert.len; + keys[cert_count] = vcard_emul_make_key(slot, cert); + /* this is safe because the key is still holding a cert reference */ + CERT_DestroyCertificate(cert); + cert_count++; + } + if (cert_count) { + VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len, + keys, cert_count); + vreader_insert_card(vreader, vcard); + vcard_emul_init_series(vreader, vcard); + /* allow insertion and removal of soft cards */ + vreader_emul->saved_vcard = vcard_reference(vcard); + vcard_free(vcard); + vreader_free(vreader); + has_readers = PR_TRUE; + } + } + + /* if we aren't suppose to use hw, skip looking up hardware tokens */ + if (!options->use_hw) { + nss_emul_init = has_readers; + return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL; + } + + /* make sure we have some PKCS #11 module loaded */ + module_lock = SECMOD_GetDefaultModuleListLock(); + module_list = SECMOD_GetDefaultModuleList(); + need_coolkey_module = !has_readers; + SECMOD_GetReadLock(module_lock); + for (mlp = module_list; mlp; mlp = mlp->next) { + SECMODModule *module = mlp->module; + if (module_has_removable_hw_slots(module)) { + need_coolkey_module = PR_FALSE; + break; + } + } + SECMOD_ReleaseReadLock(module_lock); + + if (need_coolkey_module) { + SECMODModule *module; + module = SECMOD_LoadUserModule( + (char *)"library=libcoolkeypk11.so name=Coolkey", + NULL, PR_FALSE); + if (module == NULL) { + return VCARD_EMUL_FAIL; + } + SECMOD_DestroyModule(module); /* free our reference, Module will still + * be on the list. + * until we destroy it */ + } + + /* now examine all the slots, finding which should be readers */ + /* We should control this with options. For now we mirror out any + * removable hardware slot */ + default_card_type = options->hw_card_type; + default_type_params = strdup(options->hw_type_params); + + SECMOD_GetReadLock(module_lock); + for (mlp = module_list; mlp; mlp = mlp->next) { + SECMODModule *module = mlp->module; + PRBool has_emul_slots = PR_FALSE; + + if (module == NULL) { + continue; + } + + for (i = 0; i < module->slotCount; i++) { + PK11SlotInfo *slot = module->slots[i]; + + /* only map removable HW slots */ + if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) { + continue; + } + vreader_emul = vreader_emul_new(slot, options->hw_card_type, + options->hw_type_params); + vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul, + vreader_emul_delete); + vreader_add_reader(vreader); + + has_readers = PR_TRUE; + has_emul_slots = PR_TRUE; + + if (PK11_IsPresent(slot)) { + VCard *vcard; + vcard = vcard_emul_mirror_card(vreader); + vreader_insert_card(vreader, vcard); + vcard_emul_init_series(vreader, vcard); + vcard_free(vcard); + } + } + if (has_emul_slots) { + vcard_emul_new_event_thread(module); + } + } + SECMOD_ReleaseReadLock(module_lock); + nss_emul_init = has_readers; + + return VCARD_EMUL_OK; +} + +/* Recreate card insert events for all readers (user should + * deduce implied reader insert. perhaps do a reader insert as well?) + */ +void +vcard_emul_replay_insertion_events(void) +{ + VReaderListEntry *current_entry; + VReaderListEntry *next_entry = NULL; + VReaderList *list = vreader_get_reader_list(); + + for (current_entry = vreader_list_get_first(list); current_entry; + current_entry = next_entry) { + VReader *vreader = vreader_list_get_reader(current_entry); + next_entry = vreader_list_get_next(current_entry); + vreader_queue_card_event(vreader); + } +} + +/* + * Silly little functions to help parsing our argument string + */ +static char * +copy_string(const char *str, int str_len) +{ + char *new_str; + + new_str = qemu_malloc(str_len+1); + memcpy(new_str, str, str_len); + new_str[str_len] = 0; + return new_str; +} + +static int +count_tokens(const char *str, char token, char token_end) +{ + int count = 0; + + for (; *str; str++) { + if (*str == token) { + count++; + } + if (*str == token_end) { + break; + } + } + return count; +} + +static const char * +strip(const char *str) +{ + for (; *str && !isspace(*str); str++) { + } + return str; +} + +static const char * +find_blank(const char *str) +{ + for (; *str && isspace(*str); str++) { + } + return str; +} + + +/* + * We really want to use some existing argument parsing library here. That + * would give us a consistant look */ +static VCardEmulOptions options; +#define READER_STEP 4 + +VCardEmulOptions * +vcard_emul_options(const char *args) +{ + int reader_count = 0; + VCardEmulOptions *opts; + char type_str[100]; + int type_len; + + /* Allow the future use of allocating the options structure on the fly */ + memcpy(&options, &default_options, sizeof(options)); + opts = &options; + + do { + args = strip(args); /* strip off the leading spaces */ + if (*args == ',') { + continue; + } + /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol) + * cert_2,cert_3...) */ + if (strncmp(args, "soft=", 5) == 0) { + const char *name; + const char *vname; + const char *type_params; + VCardEmulType type; + int name_length, vname_length, type_params_length, count, i; + VirtualReaderOptions *vreaderOpt = NULL; + + args = strip(args + 5); + if (*args != '(') { + continue; + } + name = args; + args = strpbrk(args + 1, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + args = strip(args+1); + name_length = args - name - 2; + vname = args; + args = strpbrk(args + 1, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + vname_length = args - name - 2; + args = strip(args+1); + type_len = strpbrk(args, ",)") - args; + assert(sizeof(type_str) > type_len); + strncpy(type_str, args, type_len); + type_str[type_len] = 0; + type = vcard_emul_type_from_string(type_str); + args = strpbrk(args, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + args = strip(args++); + type_params = args; + args = strpbrk(args + 1, ",)"); + if (*args == 0) { + break; + } + if (*args == ')') { + args++; + continue; + } + type_params_length = args - name; + args = strip(args++); + if (*args == 0) { + break; + } + + if (opts->vreader_count >= reader_count) { + reader_count += READER_STEP; + vreaderOpt = realloc(opts->vreader, + reader_count * sizeof(*vreaderOpt)); + if (vreaderOpt == NULL) { + return opts; /* we're done */ + } + } + opts->vreader = vreaderOpt; + vreaderOpt = &vreaderOpt[opts->vreader_count]; + vreaderOpt->name = copy_string(name, name_length); + vreaderOpt->vname = copy_string(vname, vname_length); + vreaderOpt->card_type = type; + vreaderOpt->type_params = + copy_string(type_params, type_params_length); + count = count_tokens(args, ',', ')'); + vreaderOpt->cert_count = count; + vreaderOpt->cert_name = (char **)qemu_malloc(count*sizeof(char *)); + for (i = 0; i < count; i++) { + const char *cert = args + 1; + args = strpbrk(args + 1, ",)"); + vreaderOpt->cert_name[i] = copy_string(cert, args - cert); + } + if (*args == ')') { + args++; + } + opts->vreader_count++; + /* use_hw= */ + } else if (strncmp(args, "use_hw=", 7) == 0) { + args = strip(args+7); + if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') { + opts->use_hw = PR_FALSE; + } else { + opts->use_hw = PR_TRUE; + } + args = find_blank(args); + /* hw_type= */ + } else if (strncmp(args, "hw_type=", 8) == 0) { + args = strip(args+8); + opts->hw_card_type = vcard_emul_type_from_string(args); + args = find_blank(args); + /* hw_params= */ + } else if (strncmp(args, "hw_params=", 10) == 0) { + const char *params; + args = strip(args+10); + params = args; + args = find_blank(args); + opts->hw_type_params = copy_string(params, args-params); + /* db="/data/base/path" */ + } else if (strncmp(args, "db=", 3) == 0) { + const char *db; + args = strip(args+3); + if (*args != '"') { + continue; + } + args++; + db = args; + args = strpbrk(args, "\"\n"); + opts->nss_db = copy_string(db, args-db); + if (*args != 0) { + args++; + } + } else { + args = find_blank(args); + } + } while (*args != 0); + + return opts; +} + +void +vcard_emul_usage(void) +{ + fprintf(stderr, +"emul args: comma separated list of the following arguments\n" +" db={nss_database} (default sql:/etc/pki/nssdb)\n" +" use_hw=[yes|no] (default yes)\n" +" hw_type={card_type_to_emulate} (default CAC)\n" +" hw_param={param_for_card} (default \"\")\n" +" soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n" +" {cert1},{cert2},{cert3} (default none)\n" +"\n" +" {nss_database} The location of the NSS cert & key database\n" +" {card_type_to_emulate} What card interface to present to the guest\n" +" {param_for_card} Card interface specific parameters\n" +" {slot_name} NSS slot that contains the certs\n" +" {vreader_name} Virutal reader name to present to the guest\n" +" {certN} Nickname of the certificate n on the virtual card\n" +"\n" +"These parameters come as a single string separated by blanks or newlines." +"\n" +"Unless use_hw is set to no, all tokens that look like removable hardware\n" +"tokens will be presented to the guest using the emulator specified by\n" +"hw_type, and parameters of hw_param.\n" +"\n" +"If more one or more soft= parameters are specified, these readers will be\n" +"presented to the guest\n"); +} diff --git a/libcacard/vcard_emul_type.c b/libcacard/vcard_emul_type.c new file mode 100644 index 0000000000..59a1458201 --- /dev/null +++ b/libcacard/vcard_emul_type.c @@ -0,0 +1,57 @@ +/* + * This file contains utility functions which abstract the different card + * types. The goal is that new card types can easily be added by simply + * changing this file and vcard_emul_type.h. It is currently not a requirement + * to dynamically add new card types. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include <strings.h> +#include "vcardt.h" +#include "vcard_emul_type.h" +#include "cac.h" + +VCardStatus vcard_init(VReader *vreader, VCard *vcard, + VCardEmulType type, const char *params, + unsigned char *const *cert, int cert_len[], + VCardKey *key[], int cert_count) +{ + switch (type) { + case VCARD_EMUL_NONE: + break; + case VCARD_EMUL_CAC: + return cac_card_init(vreader, vcard, params, + cert, cert_len, key, cert_count); + /* add new ones here */ + default: + break; + } + return VCARD_FAIL; +} + +VCardEmulType vcard_emul_type_select(VReader *vreader) +{ +#ifdef notdef + /* since there is only one emulator no need to call this function */ + if (cac_is_cac_card(vreader) == VCARD_DONE) { + return VCARD_EMUL_CAC; + } +#endif + /* return the default */ + return VCARD_EMUL_CAC; +} + +VCardEmulType vcard_emul_type_from_string(const char *type_string) +{ + if (strcasecmp(type_string, "CAC") == 0) { + return VCARD_EMUL_CAC; + } +#ifdef USE_PASSTHRU + if (strcasecmp(type_string, "PASSTHRU") == 0) { + return VCARD_EMUL_PASSTHRU; + } +#endif + return VCARD_EMUL_NONE; +} diff --git a/libcacard/vcard_emul_type.h b/libcacard/vcard_emul_type.h new file mode 100644 index 0000000000..0242f40eb1 --- /dev/null +++ b/libcacard/vcard_emul_type.h @@ -0,0 +1,32 @@ +/* + * This header file abstracts the different card types. The goal is new card + * types can easily be added by simply changing this file and + * vcard_emul_type.c. It is currently not a requirement to dynamically add new + * card types. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef VCARD_EMUL_TYPE_H +#define VCARD_EMUL_TYPE_H 1 +#include "vcardt.h" +#include "vreadert.h" + +/* + * types + */ +typedef enum { + VCARD_EMUL_NONE = 0, + VCARD_EMUL_CAC, + VCARD_EMUL_PASSTHRU +} VCardEmulType; + +/* functions used by the rest of the emulator */ +VCardStatus vcard_init(VReader *vreader, VCard *vcard, VCardEmulType type, + const char *params, unsigned char * const *cert, + int cert_len[], VCardKey *key[], int cert_count); +VCardEmulType vcard_emul_type_select(VReader *vreader); +VCardEmulType vcard_emul_type_from_string(const char *type_string); + +#endif diff --git a/libcacard/vcardt.h b/libcacard/vcardt.h new file mode 100644 index 0000000000..538bdde3df --- /dev/null +++ b/libcacard/vcardt.h @@ -0,0 +1,64 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef VCARDT_H +#define VCARDT_H 1 + +/* + * these should come from some common spice header file + */ +#include <assert.h> +#ifndef MIN +#define MIN(x, y) ((x) > (y) ? (y) : (x)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +typedef struct VCardStruct VCard; +typedef struct VCardAPDUStruct VCardAPDU; +typedef struct VCardResponseStruct VCardResponse; +typedef struct VCardBufferResponseStruct VCardBufferResponse; +typedef struct VCardAppletStruct VCardApplet; +typedef struct VCardAppletPrivateStruct VCardAppletPrivate; +typedef struct VCardKeyStruct VCardKey; /* opaque */ +typedef struct VCardEmulStruct VCardEmul; + +#define MAX_CHANNEL 4 + +/* create an ATR with appropriate historical bytes */ +#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \ + 'V', 'C', 'A', 'R', 'D', '_' + + +typedef enum { + VCARD_DONE, + VCARD_NEXT, + VCARD_FAIL +} VCardStatus; + +typedef enum { + VCARD_FILE_SYSTEM, + VCARD_VM, + VCARD_DIRECT +} VCardType; + +typedef enum { + VCARD_POWER_ON, + VCARD_POWER_OFF +} VCardPower; + +typedef VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, + VCardResponse **response); +typedef VCardStatus (*VCardResetApplet)(VCard *card, int channel); +typedef void (*VCardAppletPrivateFree) (VCardAppletPrivate *); +typedef void (*VCardEmulFree) (VCardEmul *); +typedef void (*VCardGetAtr) (VCard *, unsigned char *atr, int *atr_len); + +struct VCardBufferResponseStruct { + unsigned char *buffer; + int buffer_len; + unsigned char *current; + int len; +}; + +#endif diff --git a/libcacard/vevent.h b/libcacard/vevent.h new file mode 100644 index 0000000000..38c3482c35 --- /dev/null +++ b/libcacard/vevent.h @@ -0,0 +1,27 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#ifndef EVENT_H +#define EVENT_H 1 +#include "eventt.h" +#include "vreadert.h" +#include "vcardt.h" + +VEvent *vevent_new(VEventType type, VReader *reader, VCard *card); +void vevent_delete(VEvent *); + +/* + * VEvent queueing services + */ +void vevent_queue_vevent(VEvent *); +void vevent_queue_init(void); + +/* + * VEvent dequeing services + */ +VEvent *vevent_wait_next_vevent(void); +VEvent *vevent_get_next_vevent(void); + + +#endif diff --git a/libcacard/vreader.c b/libcacard/vreader.c new file mode 100644 index 0000000000..4a0125b0e2 --- /dev/null +++ b/libcacard/vreader.c @@ -0,0 +1,513 @@ +/* + * emulate the reader + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu-common.h" +#include "qemu-thread.h" + +#include "vcard.h" +#include "vcard_emul.h" +#include "card_7816.h" +#include "vreader.h" +#include "vevent.h" + +struct VReaderStruct { + int reference_count; + VCard *card; + char *name; + vreader_id_t id; + QemuMutex lock; + VReaderEmul *reader_private; + VReaderEmulFree reader_private_free; +}; + +/* manage locking */ +static inline void +vreader_lock(VReader *reader) +{ + qemu_mutex_lock(&reader->lock); +} + +static inline void +vreader_unlock(VReader *reader) +{ + qemu_mutex_unlock(&reader->lock); +} + +/* + * vreader constructor + */ +VReader * +vreader_new(const char *name, VReaderEmul *private, + VReaderEmulFree private_free) +{ + VReader *reader; + + reader = (VReader *)qemu_malloc(sizeof(VReader)); + qemu_mutex_init(&reader->lock); + reader->reference_count = 1; + reader->name = name ? strdup(name) : NULL; + reader->card = NULL; + reader->id = (vreader_id_t)-1; + reader->reader_private = private; + reader->reader_private_free = private_free; + return reader; +} + +/* get a reference */ +VReader* +vreader_reference(VReader *reader) +{ + if (reader == NULL) { + return NULL; + } + vreader_lock(reader); + reader->reference_count++; + vreader_unlock(reader); + return reader; +} + +/* free a reference */ +void +vreader_free(VReader *reader) +{ + if (reader == NULL) { + return; + } + vreader_lock(reader); + if (reader->reference_count-- > 1) { + vreader_unlock(reader); + return; + } + vreader_unlock(reader); + if (reader->card) { + vcard_free(reader->card); + } + if (reader->name) { + qemu_free(reader->name); + } + if (reader->reader_private_free) { + reader->reader_private_free(reader->reader_private); + } + qemu_free(reader); + return; +} + +static VCard * +vreader_get_card(VReader *reader) +{ + VCard *card; + + vreader_lock(reader); + card = vcard_reference(reader->card); + vreader_unlock(reader); + return card; +} + +VReaderStatus +vreader_card_is_present(VReader *reader) +{ + VCard *card = vreader_get_card(reader); + + if (card == NULL) { + return VREADER_NO_CARD; + } + vcard_free(card); + return VREADER_OK; +} + +vreader_id_t +vreader_get_id(VReader *reader) +{ + if (reader == NULL) { + return (vreader_id_t)-1; + } + return reader->id; +} + +VReaderStatus +vreader_set_id(VReader *reader, vreader_id_t id) +{ + if (reader == NULL) { + return VREADER_NO_CARD; + } + reader->id = id; + return VREADER_OK; +} + +const char * +vreader_get_name(VReader *reader) +{ + if (reader == NULL) { + return NULL; + } + return reader->name; +} + +VReaderEmul * +vreader_get_private(VReader *reader) +{ + return reader->reader_private; +} + +static VReaderStatus +vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) +{ + VCard *card = vreader_get_card(reader); + + if (card == NULL) { + return VREADER_NO_CARD; + } + /* + * clean up our state + */ + vcard_reset(card, power); + if (atr) { + vcard_get_atr(card, atr, len); + } + vcard_free(card); /* free our reference */ + return VREADER_OK; +} + +VReaderStatus +vreader_power_on(VReader *reader, unsigned char *atr, int *len) +{ + return vreader_reset(reader, VCARD_POWER_ON, atr, len); +} + +VReaderStatus +vreader_power_off(VReader *reader) +{ + return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0); +} + + +VReaderStatus +vreader_xfr_bytes(VReader *reader, + unsigned char *send_buf, int send_buf_len, + unsigned char *receive_buf, int *receive_buf_len) +{ + VCardAPDU *apdu; + VCardResponse *response = NULL; + VCardStatus card_status; + unsigned short status; + VCard *card = vreader_get_card(reader); + + if (card == NULL) { + return VREADER_NO_CARD; + } + + apdu = vcard_apdu_new(send_buf, send_buf_len, &status); + if (apdu == NULL) { + response = vcard_make_response(status); + card_status = VCARD_DONE; + } else { + card_status = vcard_process_apdu(card, apdu, &response); + } + assert(card_status == VCARD_DONE); + if (card_status == VCARD_DONE) { + int size = MIN(*receive_buf_len, response->b_total_len); + memcpy(receive_buf, response->b_data, size); + *receive_buf_len = size; + } + vcard_response_delete(response); + vcard_apdu_delete(apdu); + vcard_free(card); /* free our reference */ + return VREADER_OK; +} + +struct VReaderListStruct { + VReaderListEntry *head; + VReaderListEntry *tail; +}; + +struct VReaderListEntryStruct { + VReaderListEntry *next; + VReaderListEntry *prev; + VReader *reader; +}; + + +static VReaderListEntry * +vreader_list_entry_new(VReader *reader) +{ + VReaderListEntry *new_reader_list_entry; + + new_reader_list_entry = (VReaderListEntry *) + qemu_malloc(sizeof(VReaderListEntry)); + new_reader_list_entry->next = NULL; + new_reader_list_entry->prev = NULL; + new_reader_list_entry->reader = vreader_reference(reader); + return new_reader_list_entry; +} + +static void +vreader_list_entry_delete(VReaderListEntry *entry) +{ + if (entry == NULL) { + return; + } + vreader_free(entry->reader); + qemu_free(entry); +} + + +static VReaderList * +vreader_list_new(void) +{ + VReaderList *new_reader_list; + + new_reader_list = (VReaderList *)qemu_malloc(sizeof(VReaderList)); + new_reader_list->head = NULL; + new_reader_list->tail = NULL; + return new_reader_list; +} + +void +vreader_list_delete(VReaderList *list) +{ + VReaderListEntry *current_entry; + VReaderListEntry *next_entry = NULL; + for (current_entry = vreader_list_get_first(list); current_entry; + current_entry = next_entry) { + next_entry = vreader_list_get_next(current_entry); + vreader_list_entry_delete(current_entry); + } + list->head = NULL; + list->tail = NULL; + qemu_free(list); +} + + +VReaderListEntry * +vreader_list_get_first(VReaderList *list) +{ + return list ? list->head : NULL; +} + +VReaderListEntry * +vreader_list_get_next(VReaderListEntry *current) +{ + return current ? current->next : NULL; +} + +VReader * +vreader_list_get_reader(VReaderListEntry *entry) +{ + return entry ? vreader_reference(entry->reader) : NULL; +} + +static void +vreader_queue(VReaderList *list, VReaderListEntry *entry) +{ + if (entry == NULL) { + return; + } + entry->next = NULL; + entry->prev = list->tail; + if (list->head) { + list->tail->next = entry; + } else { + list->head = entry; + } + list->tail = entry; +} + +static void +vreader_dequeue(VReaderList *list, VReaderListEntry *entry) +{ + if (entry == NULL) { + return; + } + if (entry->next == NULL) { + list->tail = entry->prev; + } else if (entry->prev == NULL) { + list->head = entry->next; + } else { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + } + if ((list->tail == NULL) || (list->head == NULL)) { + list->head = list->tail = NULL; + } + entry->next = entry->prev = NULL; +} + +static VReaderList *vreader_list; +static QemuMutex vreader_list_mutex; + +static void +vreader_list_init(void) +{ + vreader_list = vreader_list_new(); + qemu_mutex_init(&vreader_list_mutex); +} + +static void +vreader_list_lock(void) +{ + qemu_mutex_lock(&vreader_list_mutex); +} + +static void +vreader_list_unlock(void) +{ + qemu_mutex_unlock(&vreader_list_mutex); +} + +static VReaderList * +vreader_copy_list(VReaderList *list) +{ + VReaderList *new_list = NULL; + VReaderListEntry *current_entry = NULL; + + new_list = vreader_list_new(); + if (new_list == NULL) { + return NULL; + } + for (current_entry = vreader_list_get_first(list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *reader = vreader_list_get_reader(current_entry); + VReaderListEntry *new_entry = vreader_list_entry_new(reader); + + vreader_free(reader); + vreader_queue(new_list, new_entry); + } + return new_list; +} + +VReaderList * +vreader_get_reader_list(void) +{ + VReaderList *new_reader_list; + + vreader_list_lock(); + new_reader_list = vreader_copy_list(vreader_list); + vreader_list_unlock(); + return new_reader_list; +} + +VReader * +vreader_get_reader_by_id(vreader_id_t id) +{ + VReader *reader = NULL; + VReaderListEntry *current_entry = NULL; + + if (id == (vreader_id_t) -1) { + return NULL; + } + + vreader_list_lock(); + for (current_entry = vreader_list_get_first(vreader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *creader = vreader_list_get_reader(current_entry); + if (creader->id == id) { + reader = creader; + break; + } + vreader_free(creader); + } + vreader_list_unlock(); + return reader; +} + +VReader * +vreader_get_reader_by_name(const char *name) +{ + VReader *reader = NULL; + VReaderListEntry *current_entry = NULL; + + vreader_list_lock(); + for (current_entry = vreader_list_get_first(vreader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + VReader *creader = vreader_list_get_reader(current_entry); + if (strcmp(creader->name, name) == 0) { + reader = creader; + break; + } + vreader_free(creader); + } + vreader_list_unlock(); + return reader; +} + +/* called from card_emul to initialize the readers */ +VReaderStatus +vreader_add_reader(VReader *reader) +{ + VReaderListEntry *reader_entry; + + reader_entry = vreader_list_entry_new(reader); + if (reader_entry == NULL) { + return VREADER_OUT_OF_MEMORY; + } + vreader_list_lock(); + vreader_queue(vreader_list, reader_entry); + vreader_list_unlock(); + vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL)); + return VREADER_OK; +} + + +VReaderStatus +vreader_remove_reader(VReader *reader) +{ + VReaderListEntry *current_entry; + + vreader_list_lock(); + for (current_entry = vreader_list_get_first(vreader_list); current_entry; + current_entry = vreader_list_get_next(current_entry)) { + if (current_entry->reader == reader) { + break; + } + } + vreader_dequeue(vreader_list, current_entry); + vreader_list_unlock(); + vreader_list_entry_delete(current_entry); + vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL)); + return VREADER_OK; +} + +/* + * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader + * state. Separated from vreader_insert_card to allow replaying events + * for a given state. + */ +void +vreader_queue_card_event(VReader *reader) +{ + vevent_queue_vevent(vevent_new( + reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader, + reader->card)); +} + +/* + * insert/remove a new card. for removal, card == NULL + */ +VReaderStatus +vreader_insert_card(VReader *reader, VCard *card) +{ + vreader_lock(reader); + if (reader->card) { + /* decrement reference count */ + vcard_free(reader->card); + reader->card = NULL; + } + reader->card = vcard_reference(card); + vreader_unlock(reader); + vreader_queue_card_event(reader); + return VREADER_OK; +} + +/* + * initialize all the static reader structures + */ +void +vreader_init(void) +{ + vreader_list_init(); +} + diff --git a/libcacard/vreader.h b/libcacard/vreader.h new file mode 100644 index 0000000000..ec2042136c --- /dev/null +++ b/libcacard/vreader.h @@ -0,0 +1,55 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef VREADER_H +#define VREADER_H 1 + +#include "eventt.h" +#include "vreadert.h" +#include "vcardt.h" + +/* + * calls for reader front end + */ +VReaderStatus vreader_power_on(VReader *reader, unsigned char *atr, int *len); +VReaderStatus vreader_power_off(VReader *reader); +VReaderStatus vreader_xfr_bytes(VReader *reader, unsigned char *send_buf, + int send_buf_len, unsigned char *receive_buf, + int *receive_buf_len); + +/* constructor */ +VReader *vreader_new(const char *readerName, VReaderEmul *emul_private, + VReaderEmulFree private_free); +/* get a new reference to a reader */ +VReader *vreader_reference(VReader *reader); +/* "destructor" (readers are reference counted) */ +void vreader_free(VReader *reader); + +/* accessors */ +VReaderEmul *vreader_get_private(VReader *); +VReaderStatus vreader_card_is_present(VReader *reader); +void vreader_queue_card_event(VReader *reader); +const char *vreader_get_name(VReader *reader); +vreader_id_t vreader_get_id(VReader *reader); +VReaderStatus vreader_set_id(VReader *reader, vreader_id_t id); + +/* list operations */ +VReaderList *vreader_get_reader_list(void); +void vreader_list_delete(VReaderList *list); +VReader *vreader_list_get_reader(VReaderListEntry *entry); +VReaderListEntry *vreader_list_get_first(VReaderList *list); +VReaderListEntry *vreader_list_get_next(VReaderListEntry *list); +VReader *vreader_get_reader_by_id(vreader_id_t id); +VReader *vreader_get_reader_by_name(const char *name); + +/* + * list tools for vcard_emul + */ +void vreader_init(void); +VReaderStatus vreader_add_reader(VReader *reader); +VReaderStatus vreader_remove_reader(VReader *reader); +VReaderStatus vreader_insert_card(VReader *reader, VCard *card); + +#endif diff --git a/libcacard/vreadert.h b/libcacard/vreadert.h new file mode 100644 index 0000000000..f97e0a79ec --- /dev/null +++ b/libcacard/vreadert.h @@ -0,0 +1,24 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#ifndef VREADERT_H +#define VREADERT_H 1 + +typedef enum { + VREADER_OK = 0, + VREADER_NO_CARD, + VREADER_OUT_OF_MEMORY +} VReaderStatus; + +typedef unsigned int vreader_id_t; +typedef struct VReaderStruct VReader; +typedef struct VReaderListStruct VReaderList; +typedef struct VReaderListEntryStruct VReaderListEntry; + +typedef struct VReaderEmulStruct VReaderEmul; +typedef void (*VReaderEmulFree)(VReaderEmul *); + +#endif + From 2ac85b93b0487b362188a62eef685e6f9e7729ce Mon Sep 17 00:00:00 2001 From: Robert Relyea <rrelyea@redhat.com> Date: Thu, 17 Mar 2011 16:38:30 +0200 Subject: [PATCH 051/386] libcacard: add vscclient client to talk to ccid-card-passthru and use smartcard on client to perform actual operations. v23->v24 changes: (Jes Sorensen review 2) * use qemu_socket instead of socket * use fprintf(stderr,..) for errors * remove unneccessary includes since using qemu_common.h --- libcacard/Makefile | 9 +- libcacard/vscclient.c | 652 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 659 insertions(+), 2 deletions(-) create mode 100644 libcacard/vscclient.c diff --git a/libcacard/Makefile b/libcacard/Makefile index 0211eacb64..4010029173 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -15,6 +15,11 @@ QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-mal QEMU_CFLAGS+=-I../ -clean: - rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ +vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o + $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $(TARGET_DIR)$@") + +all: vscclient + +clean: + rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c new file mode 100644 index 0000000000..ce33f5a92e --- /dev/null +++ b/libcacard/vscclient.c @@ -0,0 +1,652 @@ +/* + * Tester for VSCARD protocol, client side. + * + * Can be used with ccid-card-passthru. + * + * Copyright (c) 2011 Red Hat. + * Written by Alon Levy. + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include <netdb.h> + +#include "qemu-common.h" +#include "qemu-thread.h" +#include "qemu_socket.h" + +#include "vscard_common.h" + +#include "vreader.h" +#include "vcard_emul.h" +#include "vevent.h" + +int verbose; + +int sock; + +static void +print_byte_array( + uint8_t *arrBytes, + unsigned int nSize +) { + int i; + for (i = 0; i < nSize; i++) { + printf("%02X ", arrBytes[i]); + } + printf("\n"); +} + +static void +print_usage(void) { + printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] " + "<host> <port>\n", +#ifdef USE_PASSTHRU + " -p"); + printf(" -p use passthrough mode\n"); +#else + ""); +#endif + vcard_emul_usage(); +} + +static QemuMutex write_lock; + +static int +send_msg( + VSCMsgType type, + uint32_t reader_id, + const void *msg, + unsigned int length +) { + int rv; + VSCMsgHeader mhHeader; + + qemu_mutex_lock(&write_lock); + + if (verbose > 10) { + printf("sending type=%d id=%d, len =%d (0x%x)\n", + type, reader_id, length, length); + } + + mhHeader.type = htonl(type); + mhHeader.reader_id = 0; + mhHeader.length = htonl(length); + rv = write(sock, &mhHeader, sizeof(mhHeader)); + if (rv < 0) { + /* Error */ + fprintf(stderr, "write header error\n"); + close(sock); + qemu_mutex_unlock(&write_lock); + return 16; + } + rv = write(sock, msg, length); + if (rv < 0) { + /* Error */ + fprintf(stderr, "write error\n"); + close(sock); + qemu_mutex_unlock(&write_lock); + return 16; + } + qemu_mutex_unlock(&write_lock); + + return 0; +} + +static VReader *pending_reader; +static QemuMutex pending_reader_lock; +static QemuCond pending_reader_condition; + +#define MAX_ATR_LEN 40 +static void * +event_thread(void *arg) +{ + unsigned char atr[MAX_ATR_LEN]; + int atr_len = MAX_ATR_LEN; + VEvent *event = NULL; + unsigned int reader_id; + + + while (1) { + const char *reader_name; + + event = vevent_wait_next_vevent(); + if (event == NULL) { + break; + } + reader_id = vreader_get_id(event->reader); + if (reader_id == VSCARD_UNDEFINED_READER_ID && + event->type != VEVENT_READER_INSERT) { + /* ignore events from readers qemu has rejected */ + /* if qemu is still deciding on this reader, wait to see if need to + * forward this event */ + qemu_mutex_lock(&pending_reader_lock); + if (!pending_reader || (pending_reader != event->reader)) { + /* wasn't for a pending reader, this reader has already been + * rejected by qemu */ + qemu_mutex_unlock(&pending_reader_lock); + vevent_delete(event); + continue; + } + /* this reader hasn't been told it's status from qemu yet, wait for + * that status */ + while (pending_reader != NULL) { + qemu_cond_wait(&pending_reader_condition, &pending_reader_lock); + } + qemu_mutex_unlock(&pending_reader_lock); + /* now recheck the id */ + reader_id = vreader_get_id(event->reader); + if (reader_id == VSCARD_UNDEFINED_READER_ID) { + /* this reader was rejected */ + vevent_delete(event); + continue; + } + /* reader was accepted, now forward the event */ + } + switch (event->type) { + case VEVENT_READER_INSERT: + /* tell qemu to insert a new CCID reader */ + /* wait until qemu has responded to our first reader insert + * before we send a second. That way we won't confuse the responses + * */ + qemu_mutex_lock(&pending_reader_lock); + while (pending_reader != NULL) { + qemu_cond_wait(&pending_reader_condition, &pending_reader_lock); + } + pending_reader = vreader_reference(event->reader); + qemu_mutex_unlock(&pending_reader_lock); + reader_name = vreader_get_name(event->reader); + if (verbose > 10) { + printf(" READER INSERT: %s\n", reader_name); + } + send_msg(VSC_ReaderAdd, + reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */ + NULL, 0 /* TODO reader_name, strlen(reader_name) */); + break; + case VEVENT_READER_REMOVE: + /* future, tell qemu that an old CCID reader has been removed */ + if (verbose > 10) { + printf(" READER REMOVE: %d\n", reader_id); + } + send_msg(VSC_ReaderRemove, reader_id, NULL, 0); + break; + case VEVENT_CARD_INSERT: + /* get the ATR (intended as a response to a power on from the + * reader */ + atr_len = MAX_ATR_LEN; + vreader_power_on(event->reader, atr, &atr_len); + /* ATR call functions as a Card Insert event */ + if (verbose > 10) { + printf(" CARD INSERT %d: ", reader_id); + print_byte_array(atr, atr_len); + } + send_msg(VSC_ATR, reader_id, atr, atr_len); + break; + case VEVENT_CARD_REMOVE: + /* Card removed */ + if (verbose > 10) { + printf(" CARD REMOVE %d:\n", reader_id); + } + send_msg(VSC_CardRemove, reader_id, NULL, 0); + break; + default: + break; + } + vevent_delete(event); + } + return NULL; +} + + +static unsigned int +get_id_from_string(char *string, unsigned int default_id) +{ + unsigned int id = atoi(string); + + /* don't accidentally swith to zero because no numbers have been supplied */ + if ((id == 0) && *string != '0') { + return default_id; + } + return id; +} + +static void +do_command(void) +{ + char inbuf[255]; + char *string; + VCardEmulError error; + static unsigned int default_reader_id; + unsigned int reader_id; + VReader *reader = NULL; + + reader_id = default_reader_id; + string = fgets(inbuf, sizeof(inbuf), stdin); + if (string != NULL) { + if (strncmp(string, "exit", 4) == 0) { + /* remove all the readers */ + VReaderList *list = vreader_get_reader_list(); + VReaderListEntry *reader_entry; + printf("Active Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + vreader_id_t reader_id; + reader_id = vreader_get_id(reader); + if (reader_id == -1) { + continue; + } + /* be nice and signal card removal first (qemu probably should + * do this itself) */ + if (vreader_card_is_present(reader) == VREADER_OK) { + send_msg(VSC_CardRemove, reader_id, NULL, 0); + } + send_msg(VSC_ReaderRemove, reader_id, NULL, 0); + } + exit(0); + } else if (strncmp(string, "insert", 6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], reader_id); + } + reader = vreader_get_reader_by_id(reader_id); + if (reader != NULL) { + error = vcard_emul_force_card_insert(reader); + printf("insert %s, returned %d\n", + reader ? vreader_get_name(reader) + : "invalid reader", error); + } else { + printf("no reader by id %d found\n", reader_id); + } + } else if (strncmp(string, "remove", 6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], reader_id); + } + reader = vreader_get_reader_by_id(reader_id); + if (reader != NULL) { + error = vcard_emul_force_card_remove(reader); + printf("remove %s, returned %d\n", + reader ? vreader_get_name(reader) + : "invalid reader", error); + } else { + printf("no reader by id %d found\n", reader_id); + } + } else if (strncmp(string, "select", 6) == 0) { + if (string[6] == ' ') { + reader_id = get_id_from_string(&string[7], + VSCARD_UNDEFINED_READER_ID); + } + if (reader_id != VSCARD_UNDEFINED_READER_ID) { + reader = vreader_get_reader_by_id(reader_id); + } + if (reader) { + printf("Selecting reader %d, %s\n", reader_id, + vreader_get_name(reader)); + default_reader_id = reader_id; + } else { + printf("Reader with id %d not found\n", reader_id); + } + } else if (strncmp(string, "debug", 5) == 0) { + if (string[5] == ' ') { + verbose = get_id_from_string(&string[6], 0); + } + printf("debug level = %d\n", verbose); + } else if (strncmp(string, "list", 4) == 0) { + VReaderList *list = vreader_get_reader_list(); + VReaderListEntry *reader_entry; + printf("Active Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + vreader_id_t reader_id; + reader_id = vreader_get_id(reader); + if (reader_id == -1) { + continue; + } + printf("%3d %s %s\n", reader_id, + vreader_card_is_present(reader) == VREADER_OK ? + "CARD_PRESENT" : " ", + vreader_get_name(reader)); + } + printf("Inactive Readers:\n"); + for (reader_entry = vreader_list_get_first(list); reader_entry; + reader_entry = vreader_list_get_next(reader_entry)) { + VReader *reader = vreader_list_get_reader(reader_entry); + vreader_id_t reader_id; + reader_id = vreader_get_id(reader); + if (reader_id != -1) { + continue; + } + + printf("INA %s %s\n", + vreader_card_is_present(reader) == VREADER_OK ? + "CARD_PRESENT" : " ", + vreader_get_name(reader)); + } + } else if (*string != 0) { + printf("valid commands:\n"); + printf("insert [reader_id]\n"); + printf("remove [reader_id]\n"); + printf("select reader_id\n"); + printf("list\n"); + printf("debug [level]\n"); + printf("exit\n"); + } + } + vreader_free(reader); + printf("> "); + fflush(stdout); +} + + +#define APDUBufSize 270 + +/* just for ease of parsing command line arguments. */ +#define MAX_CERTS 100 + +static int +connect_to_qemu( + const char *host, + const char *port +) { + struct addrinfo hints; + struct addrinfo *server; + int ret; + + sock = qemu_socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + /* Error */ + fprintf(stderr, "Error opening socket!\n"); + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + + ret = getaddrinfo(host, port, &hints, &server); + + if (ret != 0) { + /* Error */ + fprintf(stderr, "getaddrinfo failed\n"); + return 5; + } + + if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) { + /* Error */ + fprintf(stderr, "Could not connect\n"); + return 5; + } + if (verbose) { + printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader)); + } + return sock; +} + +static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) +{ + uint32_t *capabilities = (incoming->capabilities); + int num_capabilities = + 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); + int i; + int rv; + pthread_t thread_id; + + incoming->version = ntohl(incoming->version); + if (incoming->version != VSCARD_VERSION) { + if (verbose > 0) { + printf("warning: host has version %d, we have %d\n", + verbose, VSCARD_VERSION); + } + } + if (incoming->magic != VSCARD_MAGIC) { + printf("unexpected magic: got %d, expected %d\n", + incoming->magic, VSCARD_MAGIC); + return -1; + } + for (i = 0 ; i < num_capabilities; ++i) { + capabilities[i] = ntohl(capabilities[i]); + } + /* Future: check capabilities */ + /* remove whatever reader might be left in qemu, + * in case of an unclean previous exit. */ + send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); + /* launch the event_thread. This will trigger reader adds for all the + * existing readers */ + rv = pthread_create(&thread_id, NULL, event_thread, NULL); + if (rv < 0) { + perror("pthread_create"); + return rv; + } + return 0; +} + +int +main( + int argc, + char *argv[] +) { + char *qemu_host; + char *qemu_port; + VSCMsgHeader mhHeader; + VSCMsgError *error_msg; + + int rv; + int dwSendLength; + int dwRecvLength; + uint8_t pbRecvBuffer[APDUBufSize]; + uint8_t pbSendBuffer[APDUBufSize]; + VReaderStatus reader_status; + VReader *reader = NULL; + VCardEmulOptions *command_line_options = NULL; + + char *cert_names[MAX_CERTS]; + char *emul_args = NULL; + int cert_count = 0; + int c; + + while ((c = getopt(argc, argv, "c:e:pd:")) != -1) { + switch (c) { + case 'c': + if (cert_count >= MAX_CERTS) { + printf("too many certificates (max = %d)\n", MAX_CERTS); + exit(5); + } + cert_names[cert_count++] = optarg; + break; + case 'e': + emul_args = optarg; + break; + case 'p': + print_usage(); + exit(4); + break; + case 'd': + verbose = get_id_from_string(optarg, 1); + break; + } + } + + if (argc - optind != 2) { + print_usage(); + exit(4); + } + + if (cert_count > 0) { + char *new_args; + int len, i; + /* if we've given some -c options, we clearly we want do so some + * software emulation. add that emulation now. this is NSS Emulator + * specific */ + if (emul_args == NULL) { + emul_args = (char *)"db=\"/etc/pki/nssdb\""; + } +#define SOFT_STRING ",soft=(,Virtual Reader,CAC,," + /* 2 == close paren & null */ + len = strlen(emul_args) + strlen(SOFT_STRING) + 2; + for (i = 0; i < cert_count; i++) { + len += strlen(cert_names[i])+1; /* 1 == comma */ + } + new_args = qemu_malloc(len); + strcpy(new_args, emul_args); + strcat(new_args, SOFT_STRING); + for (i = 0; i < cert_count; i++) { + strcat(new_args, cert_names[i]); + strcat(new_args, ","); + } + strcat(new_args, ")"); + emul_args = new_args; + } + if (emul_args) { + command_line_options = vcard_emul_options(emul_args); + } + + qemu_host = strdup(argv[argc - 2]); + qemu_port = strdup(argv[argc - 1]); + sock = connect_to_qemu(qemu_host, qemu_port); + + qemu_mutex_init(&write_lock); + qemu_mutex_init(&pending_reader_lock); + qemu_cond_init(&pending_reader_condition); + + vcard_emul_init(command_line_options); + + printf("> "); + fflush(stdout); + + /* Send init message, Host responds (and then we send reader attachments) */ + VSCMsgInit init = { + .version = htonl(VSCARD_VERSION), + .magic = VSCARD_MAGIC, + .capabilities = {0} + }; + send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init)); + + do { + fd_set fds; + + FD_ZERO(&fds); + FD_SET(1, &fds); + FD_SET(sock, &fds); + + /* waiting on input from the socket */ + rv = select(sock+1, &fds, NULL, NULL, NULL); + if (rv < 0) { + /* handle error */ + perror("select"); + return 7; + } + if (FD_ISSET(1, &fds)) { + do_command(); + } + if (!FD_ISSET(sock, &fds)) { + continue; + } + + rv = read(sock, &mhHeader, sizeof(mhHeader)); + if (rv < sizeof(mhHeader)) { + /* Error */ + if (rv < 0) { + perror("header read error\n"); + } else { + fprintf(stderr, "header short read %d\n", rv); + } + return 8; + } + mhHeader.type = ntohl(mhHeader.type); + mhHeader.reader_id = ntohl(mhHeader.reader_id); + mhHeader.length = ntohl(mhHeader.length); + if (verbose) { + printf("Header: type=%d, reader_id=%d length=%d (0x%x)\n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); + } + switch (mhHeader.type) { + case VSC_APDU: + case VSC_Flush: + case VSC_Error: + case VSC_Init: + rv = read(sock, pbSendBuffer, mhHeader.length); + break; + default: + fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); + return 0; + } + switch (mhHeader.type) { + case VSC_APDU: + if (rv < 0) { + /* Error */ + fprintf(stderr, "read error\n"); + close(sock); + return 8; + } + if (verbose) { + printf(" recv APDU: "); + print_byte_array(pbSendBuffer, mhHeader.length); + } + /* Transmit recieved APDU */ + dwSendLength = mhHeader.length; + dwRecvLength = sizeof(pbRecvBuffer); + reader = vreader_get_reader_by_id(mhHeader.reader_id); + reader_status = vreader_xfr_bytes(reader, + pbSendBuffer, dwSendLength, + pbRecvBuffer, &dwRecvLength); + if (reader_status == VREADER_OK) { + mhHeader.length = dwRecvLength; + if (verbose) { + printf(" send response: "); + print_byte_array(pbRecvBuffer, mhHeader.length); + } + send_msg(VSC_APDU, mhHeader.reader_id, + pbRecvBuffer, dwRecvLength); + } else { + rv = reader_status; /* warning: not meaningful */ + send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t)); + } + vreader_free(reader); + reader = NULL; /* we've freed it, don't use it by accident + again */ + break; + case VSC_Flush: + /* TODO: actually flush */ + send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0); + break; + case VSC_Error: + error_msg = (VSCMsgError *) pbSendBuffer; + if (error_msg->code == VSC_SUCCESS) { + qemu_mutex_lock(&pending_reader_lock); + if (pending_reader) { + vreader_set_id(pending_reader, mhHeader.reader_id); + vreader_free(pending_reader); + pending_reader = NULL; + qemu_cond_signal(&pending_reader_condition); + } + qemu_mutex_unlock(&pending_reader_lock); + break; + } + printf("warning: qemu refused to add reader\n"); + if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) { + /* clear pending reader, qemu can't handle any more */ + qemu_mutex_lock(&pending_reader_lock); + if (pending_reader) { + pending_reader = NULL; + /* make sure the event loop doesn't hang */ + qemu_cond_signal(&pending_reader_condition); + } + qemu_mutex_unlock(&pending_reader_lock); + } + break; + case VSC_Init: + if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) { + return -1; + } + break; + default: + printf("Default\n"); + return 0; + } + } while (rv >= 0); + + return 0; +} From 65794b435c7a3e5945bd78fad8011e3f0f15f668 Mon Sep 17 00:00:00 2001 From: Robert Relyea <rrelyea@redhat.com> Date: Thu, 17 Mar 2011 16:39:46 +0200 Subject: [PATCH 052/386] libcacard: add docs --- docs/libcacard.txt | 483 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 docs/libcacard.txt diff --git a/docs/libcacard.txt b/docs/libcacard.txt new file mode 100644 index 0000000000..5dee6fa479 --- /dev/null +++ b/docs/libcacard.txt @@ -0,0 +1,483 @@ +This file documents the CAC (Common Access Card) library in the libcacard +subdirectory. + +Virtual Smart Card Emulator + +This emulator is designed to provide emulation of actual smart cards to a +virtual card reader running in a guest virtual machine. The emulated smart +cards can be representations of real smart cards, where the necessary functions +such as signing, card removal/insertion, etc. are mapped to real, physical +cards which are shared with the client machine the emulator is running on, or +the cards could be pure software constructs. + +The emulator is structured to allow multiple replacable or additional pieces, +so it can be easily modified for future requirements. The primary envisioned +modifications are: + +1) The socket connection to the virtual card reader (presumably a CCID reader, +but other ISO-7816 compatible readers could be used). The code that handles +this is in vscclient.c. + +2) The virtual card low level emulation. This is currently supplied by using +NSS. This emulation could be replaced by implementations based on other +security libraries, including but not limitted to openssl+pkcs#11 library, +raw pkcs#11, Microsoft CAPI, direct opensc calls, etc. The code that handles +this is in vcard_emul_nss.c. + +3) Emulation for new types of cards. The current implementation emulates the +original DoD CAC standard with separate pki containers. This emulator lives in +cac.c. More than one card type emulator could be included. Other cards could +be emulated as well, including PIV, newer versions of CAC, PKCS #15, etc. + +-------------------- +Replacing the Socket Based Virtual Reader Interface. + +The current implementation contains a replacable module vscclient.c. The +current vscclient.c implements a sockets interface to the virtual ccid reader +on the guest. CCID commands that are pertinent to emulation are passed +across the socket, and their responses are passed back along that same socket. +The protocol that vscclient uses is defined in vscard_common.h and connects +to a qemu ccid usb device. Since this socket runs as a client, vscclient.c +implements a program with a main entry. It also handles argument parsing for +the emulator. + +An application that wants to use the virtual reader can replace vscclient.c +with it's own implementation that connects to it's own CCID reader. The calls +that the CCID reader can call are: + + VReaderList * vreader_get_reader_list(); + + This function returns a list of virtual readers. These readers may map to + physical devices, or simulated devices depending on vcard the back end. Each + reader in the list should represent a reader to the virtual machine. Virtual + USB address mapping is left to the CCID reader front end. This call can be + made any time to get an updated list. The returned list is a copy of the + internal list that can be referenced by the caller without locking. This copy + must be freed by the caller with vreader_list_delete when it is no longer + needed. + + VReaderListEntry *vreader_list_get_first(VReaderList *); + + This function gets the first entry on the reader list. Along with + vreader_list_get_next(), vreader_list_get_first() can be used to walk the + reader list returned from vreader_get_reader_list(). VReaderListEntries are + part of the list themselves and do not need to be freed separately from the + list. If there are no entries on the list, it will return NULL. + + VReaderListEntry *vreader_list_get_next(VReaderListEntry *); + + This function gets the next entry in the list. If there are no more entries + it will return NULL. + + VReader * vreader_list_get_reader(VReaderListEntry *) + + This function returns the reader stored in the reader List entry. Caller gets + a new reference to a reader. The caller must free it's reference when it is + finished with vreader_free(). + + void vreader_free(VReader *reader); + + This function frees a reference to a reader. Reader's are reference counted + and are automatically deleted when the last reference is freed. + + void vreader_list_delete(VReaderList *list); + + This function frees the list, all the elements on the list, and all the + reader references held by the list. + + VReaderStatus vreader_power_on(VReader *reader, char *atr, int *len); + + This functions simulates a card power on. Virtual cards do not care about + the actual voltage and other physical parameters, but it does care that the + card is actually on or off. Cycling the card causes the card to reset. If + the caller provides enough space, vreader_power_on will return the ATR of + the virtual card. The amount of space provided in atr should be indicated + in *len. The function modifies *len to be the actual length of of the + returned ATR. + + VReaderStatus vreader_power_off(VReader *reader); + + This function simulates a power off of a virtual card. + + VReaderStatus vreader_xfer_bytes(VReader *reader, unsigne char *send_buf, + int send_buf_len, + unsigned char *receive_buf, + int receive_buf_len); + + This functions send a raw apdu to a card and returns the card's response. + The CCID front end should return the response back. Most of the emulation + is driven from these APDUs. + + VReaderStatus vreader_card_is_present(VReader *reader); + + This function returns whether or not the reader has a card inserted. The + vreader_power_on, vreader_power_off, and vreader_xfer_bytes will return + VREADER_NO_CARD. + + const char *vreader_get_name(VReader *reader); + + This function returns the name of the reader. The name comes from the card + emulator level and is usually related to the name of the physical reader. + + VReaderID vreader_get_id(VReader *reader); + + This function returns the id of a reader. All readers start out with an id + of -1. The application can set the id with vreader_set_id. + + VReaderStatus vreader_get_id(VReader *reader, VReaderID id); + + This function sets the reader id. The application is responsible for making + sure that the id is unique for all readers it is actively using. + + VReader *vreader_find_reader_by_id(VReaderID id); + + This function returns the reader which matches the id. If two readers match, + only one is returned. The function returns NULL if the id is -1. + + Event *vevent_wait_next_vevent(); + + This function blocks waiting for reader and card insertion events. There + will be one event for each card insertion, each card removal, each reader + insertion and each reader removal. At start up, events are created for all + the initial readers found, as well as all the cards that are inserted. + + Event *vevent_get_next_vevent(); + + This function returns a pending event if it exists, otherwise it returns + NULL. It does not block. + +---------------- +Card Type Emulator: Adding a New Virtual Card Type + +The ISO 7816 card spec describes 2 types of cards: + 1) File system cards, where the smartcard is managed by reading and writing +data to files in a file system. There is currently only boiler plate +implemented for file system cards. + 2) VM cards, where the card has loadable applets which perform the card +functions. The current implementation supports VM cards. + +In the case of VM cards, the difference between various types of cards is +really what applets have been installed in that card. This structure is +mirrored in card type emulators. The 7816 emulator already handles the basic +ISO 7186 commands. Card type emulators simply need to add the virtual applets +which emulate the real card applets. Card type emulators have exactly one +public entry point: + + VCARDStatus xxx_card_init(VCard *card, const char *flags, + const unsigned char *cert[], + int cert_len[], + VCardKey *key[], + int cert_count); + + The parameters for this are: + card - the virtual card structure which will prepresent this card. + flags - option flags that may be specific to this card type. + cert - array of binary certificates. + cert_len - array of lengths of each of the certificates specified in cert. + key - array of opaque key structures representing the private keys on + the card. + cert_count - number of entries in cert, cert_len, and key arrays. + + Any cert, cert_len, or key with the same index are matching sets. That is + cert[0] is cert_len[0] long and has the corresponsing private key of key[0]. + +The card type emulator is expected to own the VCardKeys, but it should copy +any raw cert data it wants to save. It can create new applets and add them to +the card using the following functions: + + VCardApplet *vcard_new_applet(VCardProcessAPDU apdu_func, + VCardResetApplet reset_func, + const unsigned char *aid, + int aid_len); + + This function creates a new applet. Applet structures store the following + information: + 1) the AID of the applet (set by aid and aid_len). + 2) a function to handle APDUs for this applet. (set by apdu_func, more on + this below). + 3) a function to reset the applet state when the applet is selected. + (set by reset_func, more on this below). + 3) applet private data, a data pointer used by the card type emulator to + store any data or state it needs to complete requests. (set by a + separate call). + 4) applet private data free, a function used to free the applet private + data when the applet itself is destroyed. + The created applet can be added to the card with vcard_add_applet below. + + void vcard_set_applet_private(VCardApplet *applet, + VCardAppletPrivate *private, + VCardAppletPrivateFree private_free); + This function sets the private data and the corresponding free function. + VCardAppletPrivate is an opaque data structure to the rest of the emulator. + The card type emulator can define it any way it wants by defining + struct VCardAppletPrivateStruct {};. If there is already a private data + structure on the applet, the old one is freed before the new one is set up. + passing two NULL clear any existing private data. + + VCardStatus vcard_add_applet(VCard *card, VCardApplet *applet); + + Add an applet onto the list of applets attached to the card. Once an applet + has been added, it can be selected by it's aid, and then commands will be + routed to it VCardProcessAPDU function. This function adopts the applet the + passed int applet. Note: 2 applets with the same AID should not be added to + the same card. It's permissible to add more than one applet. Multiple applets + may have the same VCardPRocessAPDU entry point. + +The certs and keys should be attached to private data associated with one or +more appropriate applets for that card. Control will come to the card type +emulators once one of its applets are selected through the VCardProcessAPDU +function it specified when it created the applet. + +The signature of VCardResetApplet is: + VCardStatus (*VCardResetApplet) (VCard *card, int channel); + This function will reset the any internal applet state that needs to be + cleared after a select applet call. It should return VCARD_DONE; + +The signature of VCardProcessAPDU is: + VCardStatus (*VCardProcessAPDU)(VCard *card, VCardAPDU *apdu, + VCardResponse **response); + This function examines the APDU and determines whether it should process + the apdu directly, reject the apdu as invalid, or pass the apdu on to + the basic 7816 emulator for processing. + If the 7816 emulator should process the apdu, then the VCardProcessAPDU + should return VCARD_NEXT. + If there is an error, then VCardProcessAPDU should return an error + response using vcard_make_response and the appropriate 7816 error code + (see card_7816t.h) or vcard_make_response with a card type specific error + code. It should then return VCARD_DONE. + If the apdu can be processed correctly, VCardProcessAPDU should do so, + set the response value appropriately for that APDU, and return VCARD_DONE. + VCardProcessAPDU should always set the response if it returns VCARD_DONE. + It should always either return VCARD_DONE or VCARD_NEXT. + +Parsing the APDU -- + +Prior to processing calling the card type emulator's VCardProcessAPDU function, the emulator has already decoded the APDU header and set several fields: + + apdu->a_data - The raw apdu data bytes. + apdu->a_len - The len of the raw apdu data. + apdu->a_body - The start of any post header parameter data. + apdu->a_Lc - The parameter length value. + apdu->a_Le - The expected length of any returned data. + apdu->a_cla - The raw apdu class. + apdu->a_channel - The channel (decoded from the class). + apdu->a_secure_messaging_type - The decoded secure messagin type + (from class). + apdu->a_type - The decode class type. + apdu->a_gen_type - the generic class type (7816, PROPRIETARY, RFU, PTS). + apdu->a_ins - The instruction byte. + apdu->a_p1 - Parameter 1. + apdu->a_p2 - Parameter 2. + +Creating a Response -- + +The expected result of any APDU call is a response. The card type emulator must +set *response with an appropriate VCardResponse value if it returns VCARD_DONE. +Reponses could be as simple as returning a 2 byte status word response, to as +complex as returning a block of data along with a 2 byte response. Which is +returned will depend on the semantics of the APDU. The following functions will +create card responses. + + VCardResponse *vcard_make_response(VCard7816Status status); + + This is the most basic function to get a response. This function will + return a response the consists soley one 2 byte status code. If that status + code is defined in card_7816t.h, then this function is guarrenteed to + return a response with that status. If a cart type specific status code + is passed and vcard_make_response fails to allocate the appropriate memory + for that response, then vcard_make_response will return a VCardResponse + of VCARD7816_STATUS_EXC_ERROR_MEMORY. In any case, this function is + guarrenteed to return a valid VCardResponse. + + VCardResponse *vcard_response_new(unsigned char *buf, int len, + VCard7816Status status); + + This function is similar to vcard_make_response except it includes some + returned data with the response. It could also fail to allocate enough + memory, in which case it will return NULL. + + VCardResponse *vcard_response_new_status_bytes(unsigned char sw1, + unsigned char sw2); + + Sometimes in 7816 the response bytes are treated as two separate bytes with + split meanings. This function allows you to create a response based on + two separate bytes. This function could fail, in which case it will return + NULL. + + VCardResponse *vcard_response_new_bytes(unsigned char *buf, int len, + unsigned char sw1, + unsigned char sw2); + + This function is the same as vcard_response_new except you may specify + the status as two separate bytes like vcard_response_new_status_bytes. + + +Implementing functionality --- + +The following helper functions access information about the current card +and applet. + + VCARDAppletPrivate *vcard_get_current_applet_private(VCard *card, + int channel); + + This function returns any private data set by the card type emulator on + the currently selected applet. The card type emulator keeps track of the + current applet state in this data structure. Any certs and keys associated + with a particular applet is also stored here. + + int vcard_emul_get_login_count(VCard *card); + + This function returns the the number of remaing login attempts for this + card. If the card emulator does not know, or the card does not have a + way of giving this information, this function returns -1. + + + VCard7816Status vcard_emul_login(VCard *card, unsigned char *pin, + int pin_len); + + This function logins into the card and return the standard 7816 status + word depending on the success or failure of the call. + + void vcard_emul_delete_key(VCardKey *key); + + This function frees the VCardKey passed in to xxxx_card_init. The card + type emulator is responsible for freeing this key when it no longer needs + it. + + VCard7816Status vcard_emul_rsa_op(VCard *card, VCardKey *key, + unsigned char *buffer, + int buffer_size); + + This function does a raw rsa op on the buffer with the given key. + +The sample card type emulator is found in cac.c. It implements the cac specific +applets. Only those applets needed by the coolkey pkcs#11 driver on the guest +have been implemented. To support the full range CAC middleware, a complete CAC +card according to the CAC specs should be implemented here. + +------------------------------ +Virtual Card Emulator + +This code accesses both real smart cards and simulated smart cards through +services provided on the client. The current implementation uses NSS, which +already knows how to talk to various PKCS #11 modules on the client, and is +portable to most operating systems. A particular emulator can have only one +virtual card implementation at a time. + +The virtual card emulator consists of a series of virtual card services. In +addition to the services describe above (services starting with +vcard_emul_xxxx), the virtual card emulator also provides the following +functions: + + VCardEmulError vcard_emul_init(cont VCardEmulOptions *options); + + The options structure is built by another function in the virtual card + interface where a string of virtual card emulator specific strings are + mapped to the options. The actual structure is defined by the virutal card + emulator and is used to determine the configuration of soft cards, or to + determine which physical cards to present to the guest. + + The vcard_emul_init function will build up sets of readers, create any + threads that are needed to watch for changes in the reader state. If readers + have cards present in them, they are also initialized. + + Readers are created with the function. + + VReader *vreader_new(VReaderEmul *reader_emul, + VReaderEmulFree reader_emul_free); + + The freeFunc is used to free the VReaderEmul * when the reader is + destroyed. The VReaderEmul structure is an opaque structure to the + rest of the code, but defined by the virtual card emulator, which can + use it to store any reader specific state. + + Once the reader has been created, it can be added to the front end with the + call: + + VReaderStatus vreader_add_reader(VReader *reader); + + This function will automatically generate the appropriate new reader + events and add the reader to the list. + + To create a new card, the virtual card emulator will call a similiar + function. + + VCard *vcard_new(VCardEmul *card_emul, + VCardEmulFree card_emul_free); + + Like vreader_new, this function takes a virtual card emulator specific + structure which it uses to keep track of the card state. + + Once the card is created, it is attached to a card type emulator with the + following function: + + VCardStatus vcard_init(VCard *vcard, VCardEmulType type, + const char *flags, + unsigned char *const *certs, + int *cert_len, + VCardKey *key[], + int cert_count); + + The vcard is the value returned from vcard_new. The type is the + card type emulator that this card should presented to the guest as. + The flags are card type emulator specific options. The certs, + cert_len, and keys are all arrays of length cert_count. These are the + the same of the parameters xxxx_card_init() accepts. + + Finally the card is associated with it's reader by the call: + + VReaderStatus vreader_insert_card(VReader *vreader, VCard *vcard); + + This function, like vreader_add_reader, will take care of any event + notification for the card insert. + + + VCardEmulError vcard_emul_force_card_remove(VReader *vreader); + + Force a card that is present to appear to be removed to the guest, even if + that card is a physical card and is present. + + + VCardEmulError vcard_emul_force_card_insert(VReader *reader); + + Force a card that has been removed by vcard_emul_force_card_remove to be + reinserted from the point of view of the guest. This will only work if the + card is physically present (which is always true fro a soft card). + + void vcard_emul_get_atr(Vcard *card, unsigned char *atr, int *atr_len); + + Return the virtual ATR for the card. By convention this should be the value + VCARD_ATR_PREFIX(size) followed by several ascii bytes related to this + particular emulator. For instance the NSS emulator returns + {VCARD_ATR_PREFIX(3), 'N', 'S', 'S' }. Do ot return more data then *atr_len; + + void vcard_emul_reset(VCard *card, VCardPower power) + + Set the state of 'card' to the current power level and reset its internal + state (logout, etc). + +------------------------------------------------------- +List of files and their function: +README - This file +card_7816.c - emulate basic 7816 functionality. Parse APDUs. +card_7816.h - apdu and response services definitions. +card_7816t.h - 7816 specific structures, types and definitions. +event.c - event handling code. +event.h - event handling services definitions. +eventt.h - event handling structures and types +vcard.c - handle common virtual card services like creation, destruction, and + applet management. +vcard.h - common virtual card services function definitions. +vcardt.h - comon virtual card types +vreader.c - common virtual reader services. +vreader.h - common virtual reader services definitions. +vreadert.h - comon virtual reader types. +vcard_emul_type.c - manage the card type emulators. +vcard_emul_type.h - definitions for card type emulators. +cac.c - card type emulator for CAC cards +vcard_emul.h - virtual card emulator service definitions. +vcard_emul_nss.c - virtual card emulator implementation for nss. +vscclient.c - socket connection to guest qemu usb driver. +vscard_common.h - common header with the guest qemu usb driver. +mutex.h - header file for machine independent mutexes. +link_test.c - static test to make sure all the symbols are properly defined. From 585738a6e62eb586f24782dee34306e7c375f9ba Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Sun, 24 Oct 2010 12:09:18 +0200 Subject: [PATCH 053/386] ccid: add ccid-card-emulated device This devices uses libcacard (internal) to emulate a smartcard conforming to the CAC standard. It attaches to the usb-ccid bus. Usage instructions (example command lines) are in the following patch in docs/ccid.txt. It uses libcacard which uses nss, so it can work with both hw cards and certificates (files). Signed-off-by: Alon Levy <alevy@redhat.com> --- changes from v20->v21: (Jes Sorenson review) * cosmetics * use qemu-thread and qemu_malloc/qemu_free changes from v19->v20: * checkpatch.pl changes from v18->v19: * add qdev.desc * backend: drop the enumeration property, back to using a string one. changes from v16->v17: * use PROP_TYPE_ENUM for backend changes from v15->v16: * fix error reporting in initfn * bump copyright year * update copyright license changes from v1: * remove stale comments, use only c-style comments * bugfix, forgot to set recv_len * change reader name to 'Virtual Reader' --- Makefile.objs | 1 + hw/ccid-card-emulated.c | 595 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 596 insertions(+) create mode 100644 hw/ccid-card-emulated.c diff --git a/Makefile.objs b/Makefile.objs index 8c425241fc..c05f5e59be 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -201,6 +201,7 @@ hw-obj-$(CONFIG_DMA) += dma.o hw-obj-$(CONFIG_HPET) += hpet.o hw-obj-$(CONFIG_APPLESMC) += applesmc.o hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o +hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c new file mode 100644 index 0000000000..0b0718426d --- /dev/null +++ b/hw/ccid-card-emulated.c @@ -0,0 +1,595 @@ +/* + * CCID Card Device. Emulated card. + * + * Copyright (c) 2011 Red Hat. + * Written by Alon Levy. + * + * This code is licenced under the GNU LGPL, version 2 or later. + */ + +/* + * It can be used to provide access to the local hardware in a non exclusive + * way, or it can use certificates. It requires the usb-ccid bus. + * + * Usage 1: standard, mirror hardware reader+card: + * qemu .. -usb -device usb-ccid -device ccid-card-emulated + * + * Usage 2: use certificates, no hardware required + * one time: create the certificates: + * for i in 1 2 3; do + * certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i + * done + * qemu .. -usb -device usb-ccid \ + * -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3 + * + * If you use a non default db for the certificates you can specify it using + * the db parameter. + */ + +#include <eventt.h> +#include <vevent.h> +#include <vreader.h> +#include <vcard_emul.h> + +#include "qemu-thread.h" +#include "qemu-char.h" +#include "monitor.h" +#include "hw/ccid.h" + +#define DPRINTF(card, lvl, fmt, ...) \ +do {\ + if (lvl <= card->debug) {\ + printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\ + } \ +} while (0) + +#define EMULATED_DEV_NAME "ccid-card-emulated" + +#define BACKEND_NSS_EMULATED_NAME "nss-emulated" +#define BACKEND_CERTIFICATES_NAME "certificates" + +enum { + BACKEND_NSS_EMULATED = 1, + BACKEND_CERTIFICATES +}; + +#define DEFAULT_BACKEND BACKEND_NSS_EMULATED + +typedef struct EmulatedState EmulatedState; + +enum { + EMUL_READER_INSERT = 0, + EMUL_READER_REMOVE, + EMUL_CARD_INSERT, + EMUL_CARD_REMOVE, + EMUL_GUEST_APDU, + EMUL_RESPONSE_APDU, + EMUL_ERROR, +}; + +static const char *emul_event_to_string(uint32_t emul_event) +{ + switch (emul_event) { + case EMUL_READER_INSERT: + return "EMUL_READER_INSERT"; + case EMUL_READER_REMOVE: + return "EMUL_READER_REMOVE"; + case EMUL_CARD_INSERT: + return "EMUL_CARD_INSERT"; + case EMUL_CARD_REMOVE: + return "EMUL_CARD_REMOVE"; + case EMUL_GUEST_APDU: + return "EMUL_GUEST_APDU"; + case EMUL_RESPONSE_APDU: + return "EMUL_RESPONSE_APDU"; + case EMUL_ERROR: + return "EMUL_ERROR"; + } + return "UNKNOWN"; +} + +typedef struct EmulEvent { + QSIMPLEQ_ENTRY(EmulEvent) entry; + union { + struct { + uint32_t type; + } gen; + struct { + uint32_t type; + uint64_t code; + } error; + struct { + uint32_t type; + uint32_t len; + uint8_t data[]; + } data; + } p; +} EmulEvent; + +#define MAX_ATR_SIZE 40 +struct EmulatedState { + CCIDCardState base; + uint8_t debug; + char *backend_str; + uint32_t backend; + char *cert1; + char *cert2; + char *cert3; + char *db; + uint8_t atr[MAX_ATR_SIZE]; + uint8_t atr_length; + QSIMPLEQ_HEAD(event_list, EmulEvent) event_list; + QemuMutex event_list_mutex; + VReader *reader; + QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list; + QemuMutex vreader_mutex; /* and guest_apdu_list mutex */ + QemuMutex handle_apdu_mutex; + QemuCond handle_apdu_cond; + int pipe[2]; + int quit_apdu_thread; + QemuMutex apdu_thread_quit_mutex; + QemuCond apdu_thread_quit_cond; +}; + +static void emulated_apdu_from_guest(CCIDCardState *base, + const uint8_t *apdu, uint32_t len) +{ + EmulatedState *card = DO_UPCAST(EmulatedState, base, base); + EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len); + + assert(event); + event->p.data.type = EMUL_GUEST_APDU; + event->p.data.len = len; + memcpy(event->p.data.data, apdu, len); + qemu_mutex_lock(&card->vreader_mutex); + QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry); + qemu_mutex_unlock(&card->vreader_mutex); + qemu_mutex_lock(&card->handle_apdu_mutex); + qemu_cond_signal(&card->handle_apdu_cond); + qemu_mutex_unlock(&card->handle_apdu_mutex); +} + +static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len) +{ + EmulatedState *card = DO_UPCAST(EmulatedState, base, base); + + *len = card->atr_length; + return card->atr; +} + +static void emulated_push_event(EmulatedState *card, EmulEvent *event) +{ + qemu_mutex_lock(&card->event_list_mutex); + QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry); + qemu_mutex_unlock(&card->event_list_mutex); + if (write(card->pipe[1], card, 1) != 1) { + DPRINTF(card, 1, "write to pipe failed\n"); + } +} + +static void emulated_push_type(EmulatedState *card, uint32_t type) +{ + EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent)); + + assert(event); + event->p.gen.type = type; + emulated_push_event(card, event); +} + +static void emulated_push_error(EmulatedState *card, uint64_t code) +{ + EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent)); + + assert(event); + event->p.error.type = EMUL_ERROR; + event->p.error.code = code; + emulated_push_event(card, event); +} + +static void emulated_push_data_type(EmulatedState *card, uint32_t type, + const uint8_t *data, uint32_t len) +{ + EmulEvent *event = (EmulEvent *)qemu_malloc(sizeof(EmulEvent) + len); + + assert(event); + event->p.data.type = type; + event->p.data.len = len; + memcpy(event->p.data.data, data, len); + emulated_push_event(card, event); +} + +static void emulated_push_reader_insert(EmulatedState *card) +{ + emulated_push_type(card, EMUL_READER_INSERT); +} + +static void emulated_push_reader_remove(EmulatedState *card) +{ + emulated_push_type(card, EMUL_READER_REMOVE); +} + +static void emulated_push_card_insert(EmulatedState *card, + const uint8_t *atr, uint32_t len) +{ + emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len); +} + +static void emulated_push_card_remove(EmulatedState *card) +{ + emulated_push_type(card, EMUL_CARD_REMOVE); +} + +static void emulated_push_response_apdu(EmulatedState *card, + const uint8_t *apdu, uint32_t len) +{ + emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len); +} + +#define APDU_BUF_SIZE 270 +static void *handle_apdu_thread(void* arg) +{ + EmulatedState *card = arg; + uint8_t recv_data[APDU_BUF_SIZE]; + int recv_len; + VReaderStatus reader_status; + EmulEvent *event; + + while (1) { + qemu_mutex_lock(&card->handle_apdu_mutex); + qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex); + qemu_mutex_unlock(&card->handle_apdu_mutex); + if (card->quit_apdu_thread) { + card->quit_apdu_thread = 0; /* debugging */ + break; + } + qemu_mutex_lock(&card->vreader_mutex); + while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) { + event = QSIMPLEQ_FIRST(&card->guest_apdu_list); + assert((unsigned long)event > 1000); + QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry); + if (event->p.data.type != EMUL_GUEST_APDU) { + DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n"); + qemu_free(event); + continue; + } + if (card->reader == NULL) { + DPRINTF(card, 1, "reader is NULL\n"); + qemu_free(event); + continue; + } + recv_len = sizeof(recv_data); + reader_status = vreader_xfr_bytes(card->reader, + event->p.data.data, event->p.data.len, + recv_data, &recv_len); + DPRINTF(card, 2, "got back apdu of length %d\n", recv_len); + if (reader_status == VREADER_OK) { + emulated_push_response_apdu(card, recv_data, recv_len); + } else { + emulated_push_error(card, reader_status); + } + qemu_free(event); + } + qemu_mutex_unlock(&card->vreader_mutex); + } + qemu_mutex_lock(&card->apdu_thread_quit_mutex); + qemu_cond_signal(&card->apdu_thread_quit_cond); + qemu_mutex_unlock(&card->apdu_thread_quit_mutex); + return NULL; +} + +static void *event_thread(void *arg) +{ + int atr_len = MAX_ATR_SIZE; + uint8_t atr[MAX_ATR_SIZE]; + VEvent *event = NULL; + EmulatedState *card = arg; + + while (1) { + const char *reader_name; + + event = vevent_wait_next_vevent(); + if (event == NULL || event->type == VEVENT_LAST) { + break; + } + if (event->type != VEVENT_READER_INSERT) { + if (card->reader == NULL && event->reader != NULL) { + /* Happens after device_add followed by card remove or insert. + * XXX: create synthetic add_reader events if vcard_emul_init + * already called, which happens if device_del and device_add + * are called */ + card->reader = vreader_reference(event->reader); + } else { + if (event->reader != card->reader) { + fprintf(stderr, + "ERROR: wrong reader: quiting event_thread\n"); + break; + } + } + } + switch (event->type) { + case VEVENT_READER_INSERT: + /* TODO: take a specific reader. i.e. track which reader + * we are seeing here, check it is the one we want (the first, + * or by a particular name), and ignore if we don't want it. + */ + reader_name = vreader_get_name(event->reader); + if (card->reader != NULL) { + DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n", + vreader_get_name(card->reader), reader_name); + qemu_mutex_lock(&card->vreader_mutex); + vreader_free(card->reader); + qemu_mutex_unlock(&card->vreader_mutex); + emulated_push_reader_remove(card); + } + qemu_mutex_lock(&card->vreader_mutex); + DPRINTF(card, 2, "READER INSERT %s\n", reader_name); + card->reader = vreader_reference(event->reader); + qemu_mutex_unlock(&card->vreader_mutex); + emulated_push_reader_insert(card); + break; + case VEVENT_READER_REMOVE: + DPRINTF(card, 2, " READER REMOVE: %s\n", + vreader_get_name(event->reader)); + qemu_mutex_lock(&card->vreader_mutex); + vreader_free(card->reader); + card->reader = NULL; + qemu_mutex_unlock(&card->vreader_mutex); + emulated_push_reader_remove(card); + break; + case VEVENT_CARD_INSERT: + /* get the ATR (intended as a response to a power on from the + * reader */ + atr_len = MAX_ATR_SIZE; + vreader_power_on(event->reader, atr, &atr_len); + card->atr_length = (uint8_t)atr_len; + DPRINTF(card, 2, " CARD INSERT\n"); + emulated_push_card_insert(card, atr, atr_len); + break; + case VEVENT_CARD_REMOVE: + DPRINTF(card, 2, " CARD REMOVE\n"); + emulated_push_card_remove(card); + break; + case VEVENT_LAST: /* quit */ + vevent_delete(event); + return NULL; + break; + default: + break; + } + vevent_delete(event); + } + return NULL; +} + +static void pipe_read(void *opaque) +{ + EmulatedState *card = opaque; + EmulEvent *event, *next; + char dummy; + int len; + + do { + len = read(card->pipe[0], &dummy, sizeof(dummy)); + } while (len == sizeof(dummy)); + qemu_mutex_lock(&card->event_list_mutex); + QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) { + DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type)); + switch (event->p.gen.type) { + case EMUL_RESPONSE_APDU: + ccid_card_send_apdu_to_guest(&card->base, event->p.data.data, + event->p.data.len); + break; + case EMUL_READER_INSERT: + ccid_card_ccid_attach(&card->base); + break; + case EMUL_READER_REMOVE: + ccid_card_ccid_detach(&card->base); + break; + case EMUL_CARD_INSERT: + assert(event->p.data.len <= MAX_ATR_SIZE); + card->atr_length = event->p.data.len; + memcpy(card->atr, event->p.data.data, card->atr_length); + ccid_card_card_inserted(&card->base); + break; + case EMUL_CARD_REMOVE: + ccid_card_card_removed(&card->base); + break; + case EMUL_ERROR: + ccid_card_card_error(&card->base, event->p.error.code); + break; + default: + DPRINTF(card, 2, "unexpected event\n"); + break; + } + qemu_free(event); + } + QSIMPLEQ_INIT(&card->event_list); + qemu_mutex_unlock(&card->event_list_mutex); +} + +static int init_pipe_signaling(EmulatedState *card) +{ + if (pipe(card->pipe) < 0) { + DPRINTF(card, 2, "pipe creation failed\n"); + return -1; + } + fcntl(card->pipe[0], F_SETFL, O_NONBLOCK); + fcntl(card->pipe[1], F_SETFL, O_NONBLOCK); + fcntl(card->pipe[0], F_SETOWN, getpid()); + qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card); + return 0; +} + +#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb" +#define CERTIFICATES_ARGS_TEMPLATE\ + "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)" + +static int wrap_vcard_emul_init(VCardEmulOptions *options) +{ + static int called; + static int options_was_null; + + if (called) { + if ((options == NULL) != options_was_null) { + printf("%s: warning: running emulated with certificates" + " and emulated side by side is not supported\n", + __func__); + return VCARD_EMUL_FAIL; + } + vcard_emul_replay_insertion_events(); + return VCARD_EMUL_OK; + } + options_was_null = (options == NULL); + called = 1; + return vcard_emul_init(options); +} + +static int emulated_initialize_vcard_from_certificates(EmulatedState *card) +{ + char emul_args[200]; + VCardEmulOptions *options = NULL; + + snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE, + card->db ? card->db : CERTIFICATES_DEFAULT_DB, + card->cert1, card->cert2, card->cert3); + options = vcard_emul_options(emul_args); + if (options == NULL) { + printf("%s: warning: not using certificates due to" + " initialization error\n", __func__); + } + return wrap_vcard_emul_init(options); +} + +typedef struct EnumTable { + const char *name; + uint32_t value; +} EnumTable; + +EnumTable backend_enum_table[] = { + {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED}, + {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES}, + {NULL, 0}, +}; + +static uint32_t parse_enumeration(char *str, + EnumTable *table, uint32_t not_found_value) +{ + uint32_t ret = not_found_value; + + while (table->name != NULL) { + if (strcmp(table->name, str) == 0) { + ret = table->value; + break; + } + table++; + } + return ret; +} + +static int emulated_initfn(CCIDCardState *base) +{ + EmulatedState *card = DO_UPCAST(EmulatedState, base, base); + QemuThread thread_id; + VCardEmulError ret; + EnumTable *ptable; + + QSIMPLEQ_INIT(&card->event_list); + QSIMPLEQ_INIT(&card->guest_apdu_list); + qemu_mutex_init(&card->event_list_mutex); + qemu_mutex_init(&card->vreader_mutex); + qemu_mutex_init(&card->handle_apdu_mutex); + qemu_cond_init(&card->handle_apdu_cond); + card->reader = NULL; + card->quit_apdu_thread = 0; + if (init_pipe_signaling(card) < 0) { + return -1; + } + card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0); + if (card->backend == 0) { + printf("unknown backend, must be one of:\n"); + for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) { + printf("%s\n", ptable->name); + } + return -1; + } + + /* TODO: a passthru backened that works on local machine. third card type?*/ + if (card->backend == BACKEND_CERTIFICATES) { + if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) { + ret = emulated_initialize_vcard_from_certificates(card); + } else { + printf("%s: you must provide all three certs for" + " certificates backend\n", EMULATED_DEV_NAME); + return -1; + } + } else { + if (card->backend != BACKEND_NSS_EMULATED) { + printf("%s: bad backend specified. The options are:\n%s (default)," + " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME, + BACKEND_CERTIFICATES_NAME); + return -1; + } + if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) { + printf("%s: unexpected cert parameters to nss emulated backend\n", + EMULATED_DEV_NAME); + return -1; + } + /* default to mirroring the local hardware readers */ + ret = wrap_vcard_emul_init(NULL); + } + if (ret != VCARD_EMUL_OK) { + printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME); + return -1; + } + qemu_thread_create(&thread_id, event_thread, card); + qemu_thread_create(&thread_id, handle_apdu_thread, card); + return 0; +} + +static int emulated_exitfn(CCIDCardState *base) +{ + EmulatedState *card = DO_UPCAST(EmulatedState, base, base); + VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL); + + vevent_queue_vevent(vevent); /* stop vevent thread */ + qemu_mutex_lock(&card->apdu_thread_quit_mutex); + card->quit_apdu_thread = 1; /* stop handle_apdu thread */ + qemu_cond_signal(&card->handle_apdu_cond); + qemu_cond_wait(&card->apdu_thread_quit_cond, + &card->apdu_thread_quit_mutex); + /* handle_apdu thread stopped, can destroy all of it's mutexes */ + qemu_cond_destroy(&card->handle_apdu_cond); + qemu_cond_destroy(&card->apdu_thread_quit_cond); + qemu_mutex_destroy(&card->apdu_thread_quit_mutex); + qemu_mutex_destroy(&card->handle_apdu_mutex); + qemu_mutex_destroy(&card->vreader_mutex); + qemu_mutex_destroy(&card->event_list_mutex); + return 0; +} + +static CCIDCardInfo emulated_card_info = { + .qdev.name = EMULATED_DEV_NAME, + .qdev.desc = "emulated smartcard", + .qdev.size = sizeof(EmulatedState), + .initfn = emulated_initfn, + .exitfn = emulated_exitfn, + .get_atr = emulated_get_atr, + .apdu_from_guest = emulated_apdu_from_guest, + .qdev.unplug = qdev_simple_unplug_cb, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("backend", EmulatedState, backend_str), + DEFINE_PROP_STRING("cert1", EmulatedState, cert1), + DEFINE_PROP_STRING("cert2", EmulatedState, cert2), + DEFINE_PROP_STRING("cert3", EmulatedState, cert3), + DEFINE_PROP_STRING("db", EmulatedState, db), + DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void ccid_card_emulated_register_devices(void) +{ + ccid_card_qdev_register(&emulated_card_info); +} + +device_init(ccid_card_emulated_register_devices) From 1056c02b7b1a3daa3765a6b599800a453ee96c5f Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Sun, 12 Dec 2010 18:13:34 +0200 Subject: [PATCH 054/386] ccid: add docs Add documentation for the usb-ccid device and accompanying two card devices, ccid-card-emulated and ccid-card-passthru. Signed-off-by: Alon Levy <alevy@redhat.com> --- docs/ccid.txt | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 docs/ccid.txt diff --git a/docs/ccid.txt b/docs/ccid.txt new file mode 100644 index 0000000000..b8e504a3cc --- /dev/null +++ b/docs/ccid.txt @@ -0,0 +1,135 @@ +Qemu CCID Device Documentation. + +Contents +1. USB CCID device +2. Building +3. Using ccid-card-emulated with hardware +4. Using ccid-card-emulated with certificates +5. Using ccid-card-passthru with client side hardware +6. Using ccid-card-passthru with client side certificates +7. Passthrough protocol scenario +8. libcacard + +1. USB CCID device + +The USB CCID device is a USB device implementing the CCID specification, which +lets one connect smart card readers that implement the same spec. For more +information see the specification: + + Universal Serial Bus + Device Class: Smart Card + CCID + Specification for + Integrated Circuit(s) Cards Interface Devices + Revision 1.1 + April 22rd, 2005 + +Smartcard are used for authentication, single sign on, decryption in +public/private schemes and digital signatures. A smartcard reader on the client +cannot be used on a guest with simple usb passthrough since it will then not be +available on the client, possibly locking the computer when it is "removed". On +the other hand this device can let you use the smartcard on both the client and +the guest machine. It is also possible to have a completely virtual smart card +reader and smart card (i.e. not backed by a physical device) using this device. + +2. Building + +The cryptographic functions and access to the physical card is done via NSS. + +Installing NSS: + +In redhat/fedora: + yum install nss-devel +In ubuntu/debian: + apt-get install libnss3-dev + (not tested on ubuntu) + +Configuring and building: + ./configure --enable-smartcard && make + +3. Using ccid-card-emulated with hardware + +Assuming you have a working smartcard on the host with the current +user, using NSS, qemu acts as another NSS client using ccid-card-emulated: + + qemu -usb -device usb-ccid -device ccid-card-emualated + +4. Using ccid-card-emulated with certificates + +You must create the certificates. This is a one time process. We use NSS +certificates: + + certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1 + +Note: you must have exactly three certificates. + +Assuming the current user can access the certificates (use certutil -L to +verify), you can use the emulated card type with the certificates backend: + + qemu -usb -device usb-ccid -device ccid-card-emulated,backend=certificates,cert1=cert1,cert2=cert2,cert3=cert3 + +5. Using ccid-card-passthru with client side hardware + +on the host specify the ccid-card-passthru device with a suitable chardev: + + qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid -device ccid-card-passthru,chardev=ccid + +on the client run vscclient, built when you built the libcacard library: + libcacard/vscclient <qemu-host> 2001 + +6. Using ccid-card-passthru with client side certificates + +Run qemu as per #5, and run vscclient as follows: +(Note: vscclient command line interface is in a state of change) + + libcacard/vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" <qemu-host> 2001 + +7. Passthrough protocol scenario + +This is a typical interchange of messages when using the passthru card device. +usb-ccid is a usb device. It defaults to an unattached usb device on startup. +usb-ccid expects a chardev and expects the protocol defined in +cac_card/vscard_common.h to be passed over that. +The usb-ccid device can be in one of three modes: + * detached + * attached with no card + * attached with card + +A typical interchange is: (the arrow shows who started each exchange, it can be client +originated or guest originated) + +client event | vscclient | passthru | usb-ccid | guest event +---------------------------------------------------------------------------------------------- + | VSC_Init | | | + | VSC_ReaderAdd | | attach | + | | | | sees new usb device. +card inserted -> | | | | + | VSC_ATR | insert | insert | see new card + | | | | + | VSC_APDU | VSC_APDU | | <- guest sends APDU +client<->physical | | | | +card APDU exchange| | | | +client response ->| VSC_APDU | VSC_APDU | | receive APDU response + ... + [APDU<->APDU repeats several times] + ... +card removed -> | | | | + | VSC_CardRemove | remove | remove | card removed + ... + [(card insert, apdu's, card remove) repeat] + ... +kill/quit | | | | + vscclient | | | | + | VSC_ReaderRemove | | detach | + | | | | usb device removed. + + +8. libcacard + +ccid-card-passthru and vscclient use libcacard as the card emulator. +libcacard implements a completely virtual CAC (DoD standard for smart cards) +compliant card and uses NSS to actually retrive certificates and do any +encryption using the backend (real reader + card or file backed certificates). + +For documentation of cac_card see README in libcacard subdirectory. + From 51d852672cb8536c541ed5b1dc4ee8f989a96cd7 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:21 +0000 Subject: [PATCH 055/386] target-arm/neon_helper.c: Use make_float32/float32_val macros Use the softfloat make_float32 and float32_val macros to convert between softfloat's float32 type and raw uint32_t types, rather than private conversion functions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 56 ++++++++++++---------------------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 002a9c11a6..2108664adc 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -21,29 +21,6 @@ static float_status neon_float_status; #define NFS &neon_float_status -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 vfp_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t vfp_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - #define NEON_TYPE1(name, type) \ typedef struct \ { \ @@ -1796,50 +1773,51 @@ uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) /* NEON Float helpers. */ uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b) { - float32 f0 = vfp_itos(a); - float32 f1 = vfp_itos(b); + float32 f0 = make_float32(a); + float32 f1 = make_float32(b); return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b; } uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b) { - float32 f0 = vfp_itos(a); - float32 f1 = vfp_itos(b); + float32 f0 = make_float32(a); + float32 f1 = make_float32(b); return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b; } uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) { - float32 f0 = vfp_itos(a); - float32 f1 = vfp_itos(b); - return vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) + float32 f0 = make_float32(a); + float32 f1 = make_float32(b); + return float32_val((float32_compare_quiet(f0, f1, NFS) == 1) ? float32_sub(f0, f1, NFS) : float32_sub(f1, f0, NFS)); } uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b) { - return vfp_stoi(float32_add(vfp_itos(a), vfp_itos(b), NFS)); + return float32_val(float32_add(make_float32(a), make_float32(b), NFS)); } uint32_t HELPER(neon_sub_f32)(uint32_t a, uint32_t b) { - return vfp_stoi(float32_sub(vfp_itos(a), vfp_itos(b), NFS)); + return float32_val(float32_sub(make_float32(a), make_float32(b), NFS)); } uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b) { - return vfp_stoi(float32_mul(vfp_itos(a), vfp_itos(b), NFS)); + return float32_val(float32_mul(make_float32(a), make_float32(b), NFS)); } /* Floating point comparisons produce an integer result. */ #define NEON_VOP_FCMP(name, cmp) \ uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \ { \ - if (float32_compare_quiet(vfp_itos(a), vfp_itos(b), NFS) cmp 0) \ + if (float32_compare_quiet(make_float32(a), make_float32(b), NFS) cmp 0) { \ return ~0; \ - else \ + } else { \ return 0; \ + } \ } NEON_VOP_FCMP(ceq_f32, ==) @@ -1848,15 +1826,15 @@ NEON_VOP_FCMP(cgt_f32, >) uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b) { - float32 f0 = float32_abs(vfp_itos(a)); - float32 f1 = float32_abs(vfp_itos(b)); + float32 f0 = float32_abs(make_float32(a)); + float32 f1 = float32_abs(make_float32(b)); return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0; } uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) { - float32 f0 = float32_abs(vfp_itos(a)); - float32 f1 = float32_abs(vfp_itos(b)); + float32 f0 = float32_abs(make_float32(a)); + float32 f1 = float32_abs(make_float32(b)); return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0; } From c7498daea76948128c1298d78fe9e7e618b5ff7c Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:22 +0000 Subject: [PATCH 056/386] target-arm: Return right result for Neon comparison with NaNs Fix the helper functions implementing the Neon floating point comparison ops (VCGE, VCGT, VCEQ, VACGT, VACGE) to return the right answer when one of the values being compared is a NaN. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 2108664adc..9d54a75ef3 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1810,32 +1810,40 @@ uint32_t HELPER(neon_mul_f32)(uint32_t a, uint32_t b) } /* Floating point comparisons produce an integer result. */ -#define NEON_VOP_FCMP(name, cmp) \ +#define NEON_VOP_FCMP(name, ok) \ uint32_t HELPER(neon_##name)(uint32_t a, uint32_t b) \ { \ - if (float32_compare_quiet(make_float32(a), make_float32(b), NFS) cmp 0) { \ - return ~0; \ - } else { \ - return 0; \ + switch (float32_compare_quiet(make_float32(a), make_float32(b), NFS)) { \ + ok return ~0; \ + default: return 0; \ } \ } -NEON_VOP_FCMP(ceq_f32, ==) -NEON_VOP_FCMP(cge_f32, >=) -NEON_VOP_FCMP(cgt_f32, >) +NEON_VOP_FCMP(ceq_f32, case float_relation_equal:) +NEON_VOP_FCMP(cge_f32, case float_relation_equal: case float_relation_greater:) +NEON_VOP_FCMP(cgt_f32, case float_relation_greater:) uint32_t HELPER(neon_acge_f32)(uint32_t a, uint32_t b) { float32 f0 = float32_abs(make_float32(a)); float32 f1 = float32_abs(make_float32(b)); - return (float32_compare_quiet(f0, f1,NFS) >= 0) ? ~0 : 0; + switch (float32_compare_quiet(f0, f1, NFS)) { + case float_relation_equal: + case float_relation_greater: + return ~0; + default: + return 0; + } } uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) { float32 f0 = float32_abs(make_float32(a)); float32 f1 = float32_abs(make_float32(b)); - return (float32_compare_quiet(f0, f1, NFS) > 0) ? ~0 : 0; + if (float32_compare_quiet(f0, f1, NFS) == float_relation_greater) { + return ~0; + } + return 0; } #define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1)) From 0e3261098ff41c40ce3381b8ad7cff330458da3d Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:23 +0000 Subject: [PATCH 057/386] target-arm: Fix VCLE.F32 #0, VCLT.F32 #0 NaN handling Implementing the floating-point versions of VCLE #0 and VCLT #0 by doing a GT comparison and inverting the result gives the wrong result if the input is a NaN. Implement as a GT comparison with the operands swapped instead. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 39512bc62f..33417e6825 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5677,25 +5677,31 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_neon_rsb(size, tmp, tmp2); tcg_temp_free(tmp2); break; - case 24: case 27: /* Float VCGT #0, Float VCLE #0 */ + case 24: /* Float VCGT #0 */ tmp2 = tcg_const_i32(0); gen_helper_neon_cgt_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); - if (op == 27) - tcg_gen_not_i32(tmp, tmp); break; - case 25: case 28: /* Float VCGE #0, Float VCLT #0 */ + case 25: /* Float VCGE #0 */ tmp2 = tcg_const_i32(0); gen_helper_neon_cge_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); - if (op == 28) - tcg_gen_not_i32(tmp, tmp); break; case 26: /* Float VCEQ #0 */ tmp2 = tcg_const_i32(0); gen_helper_neon_ceq_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; + case 27: /* Float VCLE #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cge_f32(tmp, tmp2, tmp); + tcg_temp_free(tmp2); + break; + case 28: /* Float VCLT #0 */ + tmp2 = tcg_const_i32(0); + gen_helper_neon_cgt_f32(tmp, tmp2, tmp); + tcg_temp_free(tmp2); + break; case 30: /* Float VABS */ gen_vfp_abs(0); break; From 79c18be7dfe660ab48f9f535e6cabd38c9f1d73b Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:24 +0000 Subject: [PATCH 058/386] target-arm: Correct ABD's handling of negative zeroes Implement ABD by taking the absolute value of the difference of the operands (as the ARM ARM specifies) rather than by flipping the order of the operands to the subtract based on the results of a comparison. The latter approch gives the wrong answers for some edge cases like negative zero. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 9d54a75ef3..bf324c62b6 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1789,9 +1789,7 @@ uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) { float32 f0 = make_float32(a); float32 f1 = make_float32(b); - return float32_val((float32_compare_quiet(f0, f1, NFS) == 1) - ? float32_sub(f0, f1, NFS) - : float32_sub(f1, f0, NFS)); + return float32_val(float32_abs(float32_sub(f0, f1, NFS))); } uint32_t HELPER(neon_add_f32)(uint32_t a, uint32_t b) From 274f1b041e0d550750cc6992092ad0197b2c5320 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:25 +0000 Subject: [PATCH 059/386] softfloat: Add float*_min() and float*_max() functions Add min and max operations to softfloat. This allows us to implement propagation of NaNs and handling of negative zero correctly (unlike the approach of having target helper routines return one of the operands based on the result of a comparison op). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 4 ++++ 2 files changed, 53 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 08e4ae03d9..03fb9487bd 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -6057,6 +6057,55 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) return float128_compare_internal(a, b, 1 STATUS_VAR); } +/* min() and max() functions. These can't be implemented as + * 'compare and pick one input' because that would mishandle + * NaNs and +0 vs -0. + */ +#define MINMAX(s, nan_exp) \ +INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b, \ + int ismin STATUS_PARAM ) \ +{ \ + flag aSign, bSign; \ + uint ## s ## _t av, bv; \ + a = float ## s ## _squash_input_denormal(a STATUS_VAR); \ + b = float ## s ## _squash_input_denormal(b STATUS_VAR); \ + if (float ## s ## _is_any_nan(a) || \ + float ## s ## _is_any_nan(b)) { \ + return propagateFloat ## s ## NaN(a, b STATUS_VAR); \ + } \ + aSign = extractFloat ## s ## Sign(a); \ + bSign = extractFloat ## s ## Sign(b); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ + if (aSign != bSign) { \ + if (ismin) { \ + return aSign ? a : b; \ + } else { \ + return aSign ? b : a; \ + } \ + } else { \ + if (ismin) { \ + return (aSign ^ (av < bv)) ? a : b; \ + } else { \ + return (aSign ^ (av < bv)) ? b : a; \ + } \ + } \ +} \ + \ +float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 1 STATUS_VAR); \ +} \ + \ +float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 0 STATUS_VAR); \ +} + +MINMAX(32, 0xff) +MINMAX(64, 0x7ff) + + /* Multiply A by 2 raised to the power N. */ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 5d05fa5cf8..90f4250173 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -324,6 +324,8 @@ 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 ); +float32 float32_min(float32, float32 STATUS_PARAM); +float32 float32_max(float32, float32 STATUS_PARAM); int float32_is_quiet_nan( float32 ); int float32_is_signaling_nan( float32 ); float32 float32_maybe_silence_nan( float32 ); @@ -436,6 +438,8 @@ 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 ); +float64 float64_min(float64, float64 STATUS_PARAM); +float64 float64_max(float64, float64 STATUS_PARAM); int float64_is_quiet_nan( float64 a ); int float64_is_signaling_nan( float64 ); float64 float64_maybe_silence_nan( float64 ); From 4a9f9cb24de52e93aae7539a004dd20314ca1c0c Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Fri, 11 Mar 2011 08:12:26 +0000 Subject: [PATCH 060/386] target-arm: Use new softfloat min/max functions for VMAX, VMIN Use the new softfloat min/max functions to implement the Neon VMAX and VMIN instructions. This allows us to get the right behaviour for NaN and negative zero. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index bf324c62b6..71f1a7ead0 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1773,16 +1773,12 @@ uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) /* NEON Float helpers. */ uint32_t HELPER(neon_min_f32)(uint32_t a, uint32_t b) { - float32 f0 = make_float32(a); - float32 f1 = make_float32(b); - return (float32_compare_quiet(f0, f1, NFS) == -1) ? a : b; + return float32_val(float32_min(make_float32(a), make_float32(b), NFS)); } uint32_t HELPER(neon_max_f32)(uint32_t a, uint32_t b) { - float32 f0 = make_float32(a); - float32 f1 = make_float32(b); - return (float32_compare_quiet(f0, f1, NFS) == 1) ? a : b; + return float32_val(float32_max(make_float32(a), make_float32(b), NFS)); } uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b) From 622465e1fa4c07d96fcb6e8cbe746b1e3f3ff65e Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 14 Mar 2011 07:23:11 +0000 Subject: [PATCH 061/386] target-arm/helper.c: For float-int conversion helpers pass ints as ints Correct the argument and return types for the float<->int conversion helper functions so that integer arguments and return values are declared as uint32_t/uint64_t, not float32/float64. This allows us to remove the hand-rolled functions which were doing bitwise copies between the types via unions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helper.c | 151 +++++++++++++++---------------------------- target-arm/helpers.h | 56 ++++++++-------- 2 files changed, 81 insertions(+), 126 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 78f3d39203..6788a4c383 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2486,135 +2486,90 @@ DO_VFP_cmp(s, float32) DO_VFP_cmp(d, float64) #undef DO_VFP_cmp -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 vfp_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t vfp_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - -static inline float64 vfp_itod(uint64_t i) -{ - union { - uint64_t i; - float64 d; - } v; - - v.i = i; - return v.d; -} - -static inline uint64_t vfp_dtoi(float64 d) -{ - union { - uint64_t i; - float64 d; - } v; - - v.d = d; - return v.i; -} - /* Integer to float conversion. */ -float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) +float32 VFP_HELPER(uito, s)(uint32_t x, CPUState *env) { - return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); + return uint32_to_float32(x, &env->vfp.fp_status); } -float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) +float64 VFP_HELPER(uito, d)(uint32_t x, CPUState *env) { - return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); + return uint32_to_float64(x, &env->vfp.fp_status); } -float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) +float32 VFP_HELPER(sito, s)(uint32_t x, CPUState *env) { - return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); + return int32_to_float32(x, &env->vfp.fp_status); } -float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) +float64 VFP_HELPER(sito, d)(uint32_t x, CPUState *env) { - return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); + return int32_to_float64(x, &env->vfp.fp_status); } /* Float to integer conversion. */ -float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) +uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); + return float32_to_uint32(x, &env->vfp.fp_status); } -float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) +uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); + return float64_to_uint32(x, &env->vfp.fp_status); } -float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) +uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); + return float32_to_int32(x, &env->vfp.fp_status); } -float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) +uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); + return float64_to_int32(x, &env->vfp.fp_status); } -float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) +uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); + return float32_to_uint32_round_to_zero(x, &env->vfp.fp_status); } -float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) +uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); + return float64_to_uint32_round_to_zero(x, &env->vfp.fp_status); } -float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) +uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); + return float32_to_int32_round_to_zero(x, &env->vfp.fp_status); } -float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) +uint32_t VFP_HELPER(tosiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { - return float32_zero; + return 0; } - return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); + return float64_to_int32_round_to_zero(x, &env->vfp.fp_status); } /* floating point conversion */ @@ -2637,33 +2592,33 @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) } /* VFP3 fixed point conversion. */ -#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ -ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ +#define VFP_CONV_FIX(name, p, fsz, itype, sign) \ +float##fsz VFP_HELPER(name##to, p)(uint##fsz##_t x, uint32_t shift, \ + CPUState *env) \ { \ - ftype tmp; \ - tmp = sign##int32_to_##ftype ((itype##_t)vfp_##p##toi(x), \ - &env->vfp.fp_status); \ - return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \ + float##fsz tmp; \ + tmp = sign##int32_to_##float##fsz ((itype##_t)x, &env->vfp.fp_status); \ + return float##fsz##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \ } \ -ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ +uint##fsz##_t VFP_HELPER(to##name, p)(float##fsz x, uint32_t shift, \ + CPUState *env) \ { \ - ftype tmp; \ - if (ftype##_is_any_nan(x)) { \ - return ftype##_zero; \ + float##fsz tmp; \ + if (float##fsz##_is_any_nan(x)) { \ + return 0; \ } \ - tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ - return vfp_ito##p(ftype##_to_##itype##_round_to_zero(tmp, \ - &env->vfp.fp_status)); \ + tmp = float##fsz##_scalbn(x, shift, &env->vfp.fp_status); \ + return float##fsz##_to_##itype##_round_to_zero(tmp, &env->vfp.fp_status); \ } -VFP_CONV_FIX(sh, d, float64, int16, ) -VFP_CONV_FIX(sl, d, float64, int32, ) -VFP_CONV_FIX(uh, d, float64, uint16, u) -VFP_CONV_FIX(ul, d, float64, uint32, u) -VFP_CONV_FIX(sh, s, float32, int16, ) -VFP_CONV_FIX(sl, s, float32, int32, ) -VFP_CONV_FIX(uh, s, float32, uint16, u) -VFP_CONV_FIX(ul, s, float32, uint32, u) +VFP_CONV_FIX(sh, d, 64, int16, ) +VFP_CONV_FIX(sl, d, 64, int32, ) +VFP_CONV_FIX(uh, d, 64, uint16, u) +VFP_CONV_FIX(ul, d, 64, uint32, u) +VFP_CONV_FIX(sh, s, 32, int16, ) +VFP_CONV_FIX(sl, s, 32, int32, ) +VFP_CONV_FIX(uh, s, 32, uint16, u) +VFP_CONV_FIX(ul, s, 32, uint32, u) #undef VFP_CONV_FIX /* Half precision conversions. */ diff --git a/target-arm/helpers.h b/target-arm/helpers.h index bd6977c2fe..9de10e352f 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -96,36 +96,36 @@ DEF_HELPER_3(vfp_cmped, void, f64, f64, env) DEF_HELPER_2(vfp_fcvtds, f64, f32, env) DEF_HELPER_2(vfp_fcvtsd, f32, f64, env) -DEF_HELPER_2(vfp_uitos, f32, f32, env) -DEF_HELPER_2(vfp_uitod, f64, f32, env) -DEF_HELPER_2(vfp_sitos, f32, f32, env) -DEF_HELPER_2(vfp_sitod, f64, f32, env) +DEF_HELPER_2(vfp_uitos, f32, i32, env) +DEF_HELPER_2(vfp_uitod, f64, i32, env) +DEF_HELPER_2(vfp_sitos, f32, i32, env) +DEF_HELPER_2(vfp_sitod, f64, i32, env) -DEF_HELPER_2(vfp_touis, f32, f32, env) -DEF_HELPER_2(vfp_touid, f32, f64, env) -DEF_HELPER_2(vfp_touizs, f32, f32, env) -DEF_HELPER_2(vfp_touizd, f32, f64, env) -DEF_HELPER_2(vfp_tosis, f32, f32, env) -DEF_HELPER_2(vfp_tosid, f32, f64, env) -DEF_HELPER_2(vfp_tosizs, f32, f32, env) -DEF_HELPER_2(vfp_tosizd, f32, f64, env) +DEF_HELPER_2(vfp_touis, i32, f32, env) +DEF_HELPER_2(vfp_touid, i32, f64, env) +DEF_HELPER_2(vfp_touizs, i32, f32, env) +DEF_HELPER_2(vfp_touizd, i32, f64, env) +DEF_HELPER_2(vfp_tosis, i32, f32, env) +DEF_HELPER_2(vfp_tosid, i32, f64, env) +DEF_HELPER_2(vfp_tosizs, i32, f32, env) +DEF_HELPER_2(vfp_tosizd, i32, f64, env) -DEF_HELPER_3(vfp_toshs, f32, f32, i32, env) -DEF_HELPER_3(vfp_tosls, f32, f32, i32, env) -DEF_HELPER_3(vfp_touhs, f32, f32, i32, env) -DEF_HELPER_3(vfp_touls, f32, f32, i32, env) -DEF_HELPER_3(vfp_toshd, f64, f64, i32, env) -DEF_HELPER_3(vfp_tosld, f64, f64, i32, env) -DEF_HELPER_3(vfp_touhd, f64, f64, i32, env) -DEF_HELPER_3(vfp_tould, f64, f64, i32, env) -DEF_HELPER_3(vfp_shtos, f32, f32, i32, env) -DEF_HELPER_3(vfp_sltos, f32, f32, i32, env) -DEF_HELPER_3(vfp_uhtos, f32, f32, i32, env) -DEF_HELPER_3(vfp_ultos, f32, f32, i32, env) -DEF_HELPER_3(vfp_shtod, f64, f64, i32, env) -DEF_HELPER_3(vfp_sltod, f64, f64, i32, env) -DEF_HELPER_3(vfp_uhtod, f64, f64, i32, env) -DEF_HELPER_3(vfp_ultod, f64, f64, i32, env) +DEF_HELPER_3(vfp_toshs, i32, f32, i32, env) +DEF_HELPER_3(vfp_tosls, i32, f32, i32, env) +DEF_HELPER_3(vfp_touhs, i32, f32, i32, env) +DEF_HELPER_3(vfp_touls, i32, f32, i32, env) +DEF_HELPER_3(vfp_toshd, i64, f64, i32, env) +DEF_HELPER_3(vfp_tosld, i64, f64, i32, env) +DEF_HELPER_3(vfp_touhd, i64, f64, i32, env) +DEF_HELPER_3(vfp_tould, i64, f64, i32, env) +DEF_HELPER_3(vfp_shtos, f32, i32, i32, env) +DEF_HELPER_3(vfp_sltos, f32, i32, i32, env) +DEF_HELPER_3(vfp_uhtos, f32, i32, i32, env) +DEF_HELPER_3(vfp_ultos, f32, i32, i32, env) +DEF_HELPER_3(vfp_shtod, f64, i64, i32, env) +DEF_HELPER_3(vfp_sltod, f64, i64, i32, env) +DEF_HELPER_3(vfp_uhtod, f64, i64, i32, env) +DEF_HELPER_3(vfp_ultod, f64, i64, i32, env) DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env) DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env) From 2055283bcc8292fd63c772ed90a2502f427b2174 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 7 Mar 2011 11:10:32 +0000 Subject: [PATCH 062/386] hw/vexpress.c: Add model of ARM Versatile Express board Add a model of the ARM Versatile Express board (with A9MPx4 daughterboard). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- Makefile.target | 1 + hw/vexpress.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 hw/vexpress.c diff --git a/Makefile.target b/Makefile.target index ace5608016..ddb0931f68 100644 --- a/Makefile.target +++ b/Makefile.target @@ -333,6 +333,7 @@ obj-arm-y += framebuffer.o obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o obj-arm-y += syborg_virtio.o +obj-arm-y += vexpress.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/hw/vexpress.c b/hw/vexpress.c new file mode 100644 index 0000000000..9ffd332dee --- /dev/null +++ b/hw/vexpress.c @@ -0,0 +1,224 @@ +/* + * ARM Versatile Express emulation. + * + * Copyright (c) 2010 - 2011 B Labs Ltd. + * Copyright (c) 2011 Linaro Limited + * Written by Bahadir Balban, Amit Mahajan, Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "sysbus.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" + +#define SMP_BOOT_ADDR 0xe0000000 + +#define VEXPRESS_BOARD_ID 0x8e0 + +static struct arm_boot_info vexpress_binfo = { + .smp_loader_start = SMP_BOOT_ADDR, +}; + +static void vexpress_a9_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env = NULL; + ram_addr_t ram_offset, vram_offset, sram_offset; + DeviceState *dev, *sysctl; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[64]; + int n; + qemu_irq cpu_irq[4]; + uint32_t proc_id; + uint32_t sys_id; + ram_addr_t low_ram_size, vram_size, sram_size; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + for (n = 0; n < smp_cpus; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(env); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + } + + if (ram_size > 0x40000000) { + /* 1GB is the maximum the address space permits */ + fprintf(stderr, "vexpress: cannot model more than 1GB RAM\n"); + exit(1); + } + + ram_offset = qemu_ram_alloc(NULL, "vexpress.highmem", ram_size); + low_ram_size = ram_size; + if (low_ram_size > 0x4000000) { + low_ram_size = 0x4000000; + } + /* RAM is from 0x60000000 upwards. The bottom 64MB of the + * address space should in theory be remappable to various + * things including ROM or RAM; we always map the RAM there. + */ + cpu_register_physical_memory(0x0, low_ram_size, ram_offset | IO_MEM_RAM); + cpu_register_physical_memory(0x60000000, ram_size, + ram_offset | IO_MEM_RAM); + + /* 0x1e000000 A9MPCore (SCU) private memory region */ + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + vexpress_binfo.smp_priv_base = 0x1e000000; + sysbus_mmio_map(busdev, 0, vexpress_binfo.smp_priv_base); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + /* Interrupts [42:0] are from the motherboard; + * [47:43] are reserved; [63:48] are daughterboard + * peripherals. Note that some documentation numbers + * external interrupts starting from 32 (because the + * A9MP has internal interrupts 0..31). + */ + for (n = 0; n < 64; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + /* Motherboard peripherals CS7 : 0x10000000 .. 0x10020000 */ + sys_id = 0x1190f500; + proc_id = 0x0c000191; + + /* 0x10000000 System registers */ + sysctl = qdev_create(NULL, "realview_sysctl"); + qdev_prop_set_uint32(sysctl, "sys_id", sys_id); + qdev_init_nofail(sysctl); + qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); + + /* 0x10001000 SP810 system control */ + /* 0x10002000 serial bus PCI */ + /* 0x10004000 PL041 audio */ + + dev = sysbus_create_varargs("pl181", 0x10005000, pic[9], pic[10], NULL); + /* Wire up MMC card detect and read-only signals */ + qdev_connect_gpio_out(dev, 0, + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT)); + qdev_connect_gpio_out(dev, 1, + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN)); + + sysbus_create_simple("pl050_keyboard", 0x10006000, pic[12]); + sysbus_create_simple("pl050_mouse", 0x10007000, pic[13]); + + sysbus_create_simple("pl011", 0x10009000, pic[5]); + sysbus_create_simple("pl011", 0x1000a000, pic[6]); + sysbus_create_simple("pl011", 0x1000b000, pic[7]); + sysbus_create_simple("pl011", 0x1000c000, pic[8]); + + /* 0x1000f000 SP805 WDT */ + + sysbus_create_simple("sp804", 0x10011000, pic[2]); + sysbus_create_simple("sp804", 0x10012000, pic[3]); + + /* 0x10016000 Serial Bus DVI */ + + sysbus_create_simple("pl031", 0x10017000, pic[4]); /* RTC */ + + /* 0x1001a000 Compact Flash */ + + /* 0x1001f000 PL111 CLCD (motherboard) */ + + /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ + + /* 0x10020000 PL111 CLCD (daughterboard) */ + sysbus_create_simple("pl110", 0x10020000, pic[44]); + + /* 0x10060000 AXI RAM */ + /* 0x100e0000 PL341 Dynamic Memory Controller */ + /* 0x100e1000 PL354 Static Memory Controller */ + /* 0x100e2000 System Configuration Controller */ + + sysbus_create_simple("sp804", 0x100e4000, pic[48]); + /* 0x100e5000 SP805 Watchdog module */ + /* 0x100e6000 BP147 TrustZone Protection Controller */ + /* 0x100e9000 PL301 'Fast' AXI matrix */ + /* 0x100ea000 PL301 'Slow' AXI matrix */ + /* 0x100ec000 TrustZone Address Space Controller */ + /* 0x10200000 CoreSight debug APB */ + /* 0x1e00a000 PL310 L2 Cache Controller */ + + /* CS0: NOR0 flash : 0x40000000 .. 0x44000000 */ + /* CS4: NOR1 flash : 0x44000000 .. 0x48000000 */ + /* CS2: SRAM : 0x48000000 .. 0x4a000000 */ + sram_size = 0x2000000; + sram_offset = qemu_ram_alloc(NULL, "vexpress.sram", sram_size); + cpu_register_physical_memory(0x48000000, sram_size, + sram_offset | IO_MEM_RAM); + + /* CS3: USB, ethernet, VRAM : 0x4c000000 .. 0x50000000 */ + + /* 0x4c000000 Video RAM */ + vram_size = 0x800000; + vram_offset = qemu_ram_alloc(NULL, "vexpress.vram", vram_size); + cpu_register_physical_memory(0x4c000000, vram_size, + vram_offset | IO_MEM_RAM); + + /* 0x4e000000 LAN9118 Ethernet */ + if (nd_table[0].vlan) { + lan9118_init(&nd_table[0], 0x4e000000, pic[15]); + } + + /* 0x4f000000 ISP1761 USB */ + + /* ??? Hack to map an additional page of ram for the secondary CPU + startup code. I guess this works on real hardware because the + BootROM happens to be in ROM/flash or in memory that isn't clobbered + until after Linux boots the secondary CPUs. */ + ram_offset = qemu_ram_alloc(NULL, "vexpress.hack", 0x1000); + cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000, + ram_offset | IO_MEM_RAM); + + vexpress_binfo.ram_size = ram_size; + vexpress_binfo.kernel_filename = kernel_filename; + vexpress_binfo.kernel_cmdline = kernel_cmdline; + vexpress_binfo.initrd_filename = initrd_filename; + vexpress_binfo.nb_cpus = smp_cpus; + vexpress_binfo.board_id = VEXPRESS_BOARD_ID; + vexpress_binfo.loader_start = 0x60000000; + arm_load_kernel(first_cpu, &vexpress_binfo); +} + + +static QEMUMachine vexpress_a9_machine = { + .name = "vexpress-a9", + .desc = "ARM Versatile Express for Cortex-A9", + .init = vexpress_a9_init, + .use_scsi = 1, + .max_cpus = 4, +}; + +static void vexpress_machine_init(void) +{ + qemu_register_machine(&vexpress_a9_machine); +} + +machine_init(vexpress_machine_init); From 4ff9786c67f7c7180f33ec146e9acc9ce90adfa9 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 13 Mar 2011 15:44:02 +0100 Subject: [PATCH 063/386] Fix trivial "endianness bugs" Replace endianess -> endianness. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- audio/sdlaudio.c | 20 ++++++++++---------- block/vdi.c | 4 ++-- target-microblaze/translate.c | 2 +- target-mips/cpu.h | 2 +- usb-bsd.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index b74dcfa734..a847aa90f7 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -139,36 +139,36 @@ static int aud_to_sdlfmt (audfmt_e fmt) } } -static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess) +static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness) { switch (sdlfmt) { case AUDIO_S8: - *endianess = 0; + *endianness = 0; *fmt = AUD_FMT_S8; break; case AUDIO_U8: - *endianess = 0; + *endianness = 0; *fmt = AUD_FMT_U8; break; case AUDIO_S16LSB: - *endianess = 0; + *endianness = 0; *fmt = AUD_FMT_S16; break; case AUDIO_U16LSB: - *endianess = 0; + *endianness = 0; *fmt = AUD_FMT_U16; break; case AUDIO_S16MSB: - *endianess = 1; + *endianness = 1; *fmt = AUD_FMT_S16; break; case AUDIO_U16MSB: - *endianess = 1; + *endianness = 1; *fmt = AUD_FMT_U16; break; @@ -338,7 +338,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as) SDLVoiceOut *sdl = (SDLVoiceOut *) hw; SDLAudioState *s = &glob_sdl; SDL_AudioSpec req, obt; - int endianess; + int endianness; int err; audfmt_e effective_fmt; struct audsettings obt_as; @@ -354,7 +354,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as) return -1; } - err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess); + err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness); if (err) { sdl_close (s); return -1; @@ -363,7 +363,7 @@ static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.channels; obt_as.fmt = effective_fmt; - obt_as.endianness = endianess; + obt_as.endianness = endianness; audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; diff --git a/block/vdi.c b/block/vdi.c index 90540792d3..701745bf8c 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -113,7 +113,7 @@ void uuid_unparse(const uuid_t uu, char *out); */ #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n" -/* Unallocated blocks use this index (no need to convert endianess). */ +/* Unallocated blocks use this index (no need to convert endianness). */ #define VDI_UNALLOCATED UINT32_MAX #if !defined(CONFIG_UUID) @@ -194,7 +194,7 @@ typedef struct { uint32_t block_sectors; /* First sector of block map. */ uint32_t bmap_sector; - /* VDI header (converted to host endianess). */ + /* VDI header (converted to host endianness). */ VdiHeader header; } BDRVVdiState; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index fdb2b40df9..b54b169b18 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -923,7 +923,7 @@ static void dec_load(DisasContext *dc) /* * When doing reverse accesses we need to do two things. * - * 1. Reverse the address wrt endianess. + * 1. Reverse the address wrt endianness. * 2. Byteswap the data lanes on the way back into the CPU core. */ if (rev && size != 4) { diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 2419aa93d2..0b98d10266 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -63,7 +63,7 @@ union fpr_t { uint32_t w[2]; /* binary single fixed-point */ }; /* define FP_ENDIAN_IDX to access the same location - * in the fpr_t union regardless of the host endianess + * in the fpr_t union regardless of the host endianness */ #if defined(HOST_WORDS_BIGENDIAN) # define FP_ENDIAN_IDX 1 diff --git a/usb-bsd.c b/usb-bsd.c index abcb60c6f1..50ccd489fe 100644 --- a/usb-bsd.c +++ b/usb-bsd.c @@ -464,7 +464,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) printf("usb_host_scan: couldn't get device information for %s - %s\n", devbuf, strerror(errno)); - // XXX: might need to fixup endianess of word values before copying over + /* XXX: might need to fixup endianness of word values before copying over */ vendor_id = dev_info.udi_vendorNo; product_id = dev_info.udi_productNo; From 9bcfc7daabb138b0fe3d64d74892942d482e5bbd Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Wed, 16 Mar 2011 18:05:01 +0900 Subject: [PATCH 064/386] ioapic: when switches to level trigger mode, interrupts raised repeatedly. - the trigger mode is edge at first - During initializatoin, the interrupt is raised as edge which is masked. The corresponding bit of irr is set. - Then the mode is switched to level and it's unmasked. - the bit of irr is set, so the interrupt is raised repeatedly by ioapic_service(). - OS considers that the irq line is broken and falls back to polling mode. This patch fixes the issues. After raising edige, clear the bit of irr. > Bringing up interface eth0: > Determining IP information for eth0...irq 18: nobody cared (try booting with the "irqpoll" option) > Pid: 4126, comm: ip Not tainted 2.6.38-rc7 #1 > Call Trace: > <IRQ> [<ffffffff8105b009>] ? __report_bad_irq+0x38/0x87 > [<ffffffff8105b177>] ? note_interrupt+0x11f/0x188 > [<ffffffff8105bacf>] ? handle_fasteoi_irq+0xa7/0xd1 > [<ffffffff810046ff>] ? handle_irq+0x83/0x8c > [<ffffffff81003eb9>] ? do_IRQ+0x48/0xaf > [<ffffffff81300513>] ? ret_from_intr+0x0/0xe > [<ffffffff81031ab8>] ? __do_softirq+0x4f/0x114 > [<ffffffff81002d6c>] ? call_softirq+0x1c/0x28 > [<ffffffff81004647>] ? do_softirq+0x33/0x68 > [<ffffffff810316fb>] ? irq_exit+0x36/0x38 > [<ffffffff81015f2c>] ? smp_apic_timer_interrupt+0x88/0x96 > [<ffffffff81002853>] ? apic_timer_interrupt+0x13/0x20 > <EOI> [<ffffffff810177ed>] ? __ioapic_set_affinity+0x68/0x7c > [<ffffffff813000f0>] ? _raw_spin_unlock_irqrestore+0x8/0xa > [<ffffffff8105a84f>] ? __setup_irq+0x224/0x2cb > [<ffffffff8120e3c5>] ? e1000_intr+0x0/0x103 > [<ffffffff8105a9c7>] ? request_threaded_irq+0xd1/0x114 > [<ffffffff8120e396>] ? e1000_request_irq+0x34/0x63 > [<ffffffff8121237d>] ? e1000_open+0x81/0x11f > [<ffffffff8129097c>] ? call_netdevice_notifiers+0x45/0x4a > [<ffffffff81290d8d>] ? __dev_open+0x97/0xc4 > [<ffffffff8128e9c5>] ? __dev_change_flags+0xb9/0x13d > [<ffffffff81290cc1>] ? dev_change_flags+0x1c/0x51 > [<ffffffff812d0542>] ? devinet_ioctl+0x26e/0x594 > [<ffffffff812d174c>] ? inet_ioctl+0x92/0xaa > [<ffffffff81281d75>] ? T.1003+0x13/0x32 > [<ffffffff81282152>] ? sock_ioctl+0x1f2/0x1ff > [<ffffffff810ae2d3>] ? do_vfs_ioctl+0x498/0x4e7 > [<ffffffff81281203>] ? sock_alloc_file+0xb3/0x115 > [<ffffffff8109f79f>] ? fd_install+0x31/0x5d > [<ffffffff810ae364>] ? sys_ioctl+0x42/0x65 > [<ffffffff81001f3b>] ? system_call_fastpath+0x16/0x1b > handlers: > [<ffffffff8120e3c5>] (e1000_intr+0x0/0x103) > Disabling IRQ #18 Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/ioapic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ioapic.c b/hw/ioapic.c index 569327d1e9..8557e5cac6 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -164,6 +164,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level) if (level) { s->irr |= mask; ioapic_service(s); + s->irr &= ~mask; } } } From 2917dce477f91e933052f5555b4c6be961ff624e Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 3 Apr 2011 21:36:36 +0200 Subject: [PATCH 065/386] tests/cris: Fix some errors and potential crashes These errors were reported by cppcheck: tests/cris/check_openpf1.c:30: error: Mismatching allocation and deallocation: f tests/cris/check_openpf2.c:13: error: Mismatching allocation and deallocation: f tests/cris/check_stat3.c:16: error: Buffer overrun possible for long cmd-line args tests/cris/check_stat4.c:18: error: Buffer overrun possible for long cmd-line args The first two are obvious coding errors (fopen needs fclose, not close). The last two may seem less important (nobody will start test code with an argument of more than 1022 characters which raises a buffer overrun). Fixing them nevertheless helps with static code checks like those done by cppcheck. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- tests/cris/check_openpf1.c | 2 +- tests/cris/check_openpf2.c | 2 +- tests/cris/check_stat3.c | 2 +- tests/cris/check_stat4.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/cris/check_openpf1.c b/tests/cris/check_openpf1.c index 1d71e0bddb..fdcf4c5c3f 100644 --- a/tests/cris/check_openpf1.c +++ b/tests/cris/check_openpf1.c @@ -27,7 +27,7 @@ int main (int argc, char *argv[]) f = fopen (fnam, "rb"); if (f == NULL) abort (); - close (f); + fclose(f); /* Cover another execution path. */ if (fopen ("/nonexistent", "rb") != NULL diff --git a/tests/cris/check_openpf2.c b/tests/cris/check_openpf2.c index f44a8f34bb..5d56189f8e 100644 --- a/tests/cris/check_openpf2.c +++ b/tests/cris/check_openpf2.c @@ -10,7 +10,7 @@ int main (int argc, char *argv[]) FILE *f = fopen ("check_openpf2.c", "rb"); if (f == NULL) abort (); - close (f); + fclose(f); printf ("pass\n"); return 0; } diff --git a/tests/cris/check_stat3.c b/tests/cris/check_stat3.c index 3b5b217a1c..36a9d5d274 100644 --- a/tests/cris/check_stat3.c +++ b/tests/cris/check_stat3.c @@ -13,7 +13,7 @@ int main (int argc, char *argv[]) char path[1024] = "/"; struct stat buf; - strcat (path, argv[0]); + strncat(path, argv[0], sizeof(path) - 2); if (stat (".", &buf) != 0 || !S_ISDIR (buf.st_mode)) abort (); diff --git a/tests/cris/check_stat4.c b/tests/cris/check_stat4.c index e1955cab34..04f21fe7c4 100644 --- a/tests/cris/check_stat4.c +++ b/tests/cris/check_stat4.c @@ -15,7 +15,7 @@ int main (int argc, char *argv[]) char path[1024] = "/"; struct stat buf; - strcat (path, argv[0]); + strncat(path, argv[0], sizeof(path) - 2); if (lstat (".", &buf) != 0 || !S_ISDIR (buf.st_mode)) abort (); From 425189a8ffc1247cc803bf6e1ffea42c47831684 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Tue, 22 Mar 2011 11:02:09 +0100 Subject: [PATCH 066/386] gdbstub: Catch and report more vmstop reasons When the VM goes into stop state while there is a gdb frontend attached, it makes sense to inform gdb about this fact and at least a bit about the stop reason. Basically, all stops are interesting except for the temporary VMSTOP_SAVE/LOADVM. The patch maps the relevant VMSTOP reasons on unique and more or less associatable signals that gdb understands. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- gdbstub.c | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 1e9f9312de..0838948c5c 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -45,7 +45,12 @@ enum { GDB_SIGNAL_0 = 0, GDB_SIGNAL_INT = 2, + GDB_SIGNAL_QUIT = 3, GDB_SIGNAL_TRAP = 5, + GDB_SIGNAL_ABRT = 6, + GDB_SIGNAL_ALRM = 14, + GDB_SIGNAL_IO = 23, + GDB_SIGNAL_XCPU = 24, GDB_SIGNAL_UNKNOWN = 143 }; @@ -2270,14 +2275,11 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) const char *type; int ret; - if (running || (reason != VMSTOP_DEBUG && reason != VMSTOP_USER) || - s->state == RS_INACTIVE || s->state == RS_SYSCALL) { + if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) { return; } - /* disable single step if it was enable */ - cpu_single_step(env, 0); - - if (reason == VMSTOP_DEBUG) { + switch (reason) { + case VMSTOP_DEBUG: if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: @@ -2294,17 +2296,44 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", GDB_SIGNAL_TRAP, gdb_id(env), type, env->watchpoint_hit->vaddr); - put_packet(s, buf); env->watchpoint_hit = NULL; - return; + goto send_packet; } - tb_flush(env); + tb_flush(env); ret = GDB_SIGNAL_TRAP; - } else { + break; + case VMSTOP_USER: ret = GDB_SIGNAL_INT; + break; + case VMSTOP_SHUTDOWN: + ret = GDB_SIGNAL_QUIT; + break; + case VMSTOP_DISKFULL: + ret = GDB_SIGNAL_IO; + break; + case VMSTOP_WATCHDOG: + ret = GDB_SIGNAL_ALRM; + break; + case VMSTOP_PANIC: + ret = GDB_SIGNAL_ABRT; + break; + case VMSTOP_SAVEVM: + case VMSTOP_LOADVM: + return; + case VMSTOP_MIGRATE: + ret = GDB_SIGNAL_XCPU; + break; + default: + ret = GDB_SIGNAL_UNKNOWN; + break; } snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env)); + +send_packet: put_packet(s, buf); + + /* disable single step if it was enabled */ + cpu_single_step(env, 0); } #endif From d17161f6cc48a30b5e0c65a7d78ac47b069af06b Mon Sep 17 00:00:00 2001 From: Kevin Wolf <mail@kevin-wolf.de> Date: Sat, 26 Mar 2011 19:37:56 +0100 Subject: [PATCH 067/386] e1000: Mask out lower bits of RDBAL/TDBAL Rx and Tx descriptors are 16 byte aligned, so the lower bits are ignored by real hardware. In fact, they always read back as zero on real hardware, but probably nobody relies on that. Signed-off-by: Kevin Wolf <mail@kevin-wolf.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/e1000.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 55daae0eba..fe3e812610 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -517,6 +517,14 @@ txdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp) return E1000_ICR_TXDW; } +static uint64_t tx_desc_base(E1000State *s) +{ + uint64_t bah = s->mac_reg[TDBAH]; + uint64_t bal = s->mac_reg[TDBAL] & ~0xf; + + return (bah << 32) + bal; +} + static void start_xmit(E1000State *s) { @@ -530,7 +538,7 @@ start_xmit(E1000State *s) } while (s->mac_reg[TDH] != s->mac_reg[TDT]) { - base = ((uint64_t)s->mac_reg[TDBAH] << 32) + s->mac_reg[TDBAL] + + base = tx_desc_base(s) + sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); @@ -651,6 +659,14 @@ e1000_can_receive(VLANClientState *nc) return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1); } +static uint64_t rx_desc_base(E1000State *s) +{ + uint64_t bah = s->mac_reg[RDBAH]; + uint64_t bal = s->mac_reg[RDBAL] & ~0xf; + + return (bah << 32) + bal; +} + static ssize_t e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { @@ -700,8 +716,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) if (desc_size > s->rxbuf_size) { desc_size = s->rxbuf_size; } - base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + - sizeof(desc) * s->mac_reg[RDH]; + base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); desc.special = vlan_special; desc.status |= (vlan_status | E1000_RXD_STAT_DD); From 22156ab498acf5f8104801148732ae8e83f336a0 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Mon, 28 Mar 2011 22:00:30 +0100 Subject: [PATCH 068/386] net: Remove unused net-checksum.c file The common checksum functions were moved to net/checksum.c in commit 7200ac3c7c8eefe574193b49eeff09f120e11ec7 but the original net-checksum.c was never deleted from the source tree. Remove it now since all users of the checksum functions link against net/checksum.o and net-checksum.c is not even compiled anymore. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- net-checksum.c | 86 -------------------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 net-checksum.c diff --git a/net-checksum.c b/net-checksum.c deleted file mode 100644 index 4956c5cefa..0000000000 --- a/net-checksum.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * IP checksumming functions. - * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> - * - * 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; under version 2 of the License. - * - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include "hw/hw.h" -#include "net.h" - -#define PROTO_TCP 6 -#define PROTO_UDP 17 - -uint32_t net_checksum_add(int len, uint8_t *buf) -{ - uint32_t sum = 0; - int i; - - for (i = 0; i < len; i++) { - if (i & 1) - sum += (uint32_t)buf[i]; - else - sum += (uint32_t)buf[i] << 8; - } - return sum; -} - -uint16_t net_checksum_finish(uint32_t sum) -{ - while (sum>>16) - sum = (sum & 0xFFFF)+(sum >> 16); - return ~sum; -} - -uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, - uint8_t *addrs, uint8_t *buf) -{ - uint32_t sum = 0; - - sum += net_checksum_add(length, buf); // payload - sum += net_checksum_add(8, addrs); // src + dst address - sum += proto + length; // protocol & length - return net_checksum_finish(sum); -} - -void net_checksum_calculate(uint8_t *data, int length) -{ - int hlen, plen, proto, csum_offset; - uint16_t csum; - - if ((data[14] & 0xf0) != 0x40) - return; /* not IPv4 */ - hlen = (data[14] & 0x0f) * 4; - plen = (data[16] << 8 | data[17]) - hlen; - proto = data[23]; - - switch (proto) { - case PROTO_TCP: - csum_offset = 16; - break; - case PROTO_UDP: - csum_offset = 6; - break; - default: - return; - } - - if (plen < csum_offset+2) - return; - - data[14+hlen+csum_offset] = 0; - data[14+hlen+csum_offset+1] = 0; - csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen); - data[14+hlen+csum_offset] = csum >> 8; - data[14+hlen+csum_offset+1] = csum & 0xff; -} From f1d3fb04d55f46d39073e7089a5be43a16e80aa9 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Wed, 30 Mar 2011 22:03:38 +0100 Subject: [PATCH 069/386] vl.c: Tidy up message printed when we exit on a signal Tidy up the message printed when qemu exits due to a signal, so that it's clearer where the message is coming from and that it's not just stray debug output. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Acked-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- vl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index d3d81e08fb..5c80600c71 100644 --- a/vl.c +++ b/vl.c @@ -1169,8 +1169,15 @@ int qemu_shutdown_requested(void) void qemu_kill_report(void) { if (shutdown_signal != -1) { - fprintf(stderr, "Got signal %d from pid %d\n", - shutdown_signal, shutdown_pid); + fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal); + if (shutdown_pid == 0) { + /* This happens for eg ^C at the terminal, so it's worth + * avoiding printing an odd message in that case. + */ + fputc('\n', stderr); + } else { + fprintf(stderr, " from pid %d\n", shutdown_pid); + } shutdown_signal = -1; } } From 0ce235a7ee5a1852c0a18d4764ac0a6700805c83 Mon Sep 17 00:00:00 2001 From: Gleb Natapov <gleb@redhat.com> Date: Thu, 31 Mar 2011 11:27:23 +0200 Subject: [PATCH 070/386] register signal handler after initializing SDL. SDL library initialization mangles signal handlers, so QEMU should register them after initializing SDL. This was the case before and code even have a comment about that. Fix it to be so again. Signed-off-by: Gleb Natapov <gleb@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- vl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 5c80600c71..4d9e503d7c 100644 --- a/vl.c +++ b/vl.c @@ -3059,9 +3059,6 @@ int main(int argc, char **argv, char **envp) cpu_synchronize_all_post_init(); - /* must be after terminal init, SDL library changes signal handlers */ - os_setup_signal_handling(); - set_numa_modes(); current_machine = machine; @@ -3117,6 +3114,9 @@ int main(int argc, char **argv, char **envp) break; } + /* must be after terminal init, SDL library changes signal handlers */ + os_setup_signal_handling(); + #ifdef CONFIG_VNC /* init remote displays */ if (vnc_display) { From 6d65516f774c62a1abde3e52b689ac743b9ccc71 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 3 Apr 2011 08:55:35 +0200 Subject: [PATCH 071/386] w32: Fix compilation (wrong include file) arpa/inet.h is not available for w32, so commit edbb21363fbfe40e050f583df921484cbc31c79d breaks w32 compilations. This is fixed by using qemu_socket.h. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Reviewed-by: Alon Levy <alevy@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/ccid-card-passthru.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index 8506fed4fc..28eb9d18f8 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -8,9 +8,8 @@ * See the COPYING file in the top-level directory. */ -#include <arpa/inet.h> - #include "qemu-char.h" +#include "qemu_socket.h" #include "monitor.h" #include "hw/ccid.h" #include "libcacard/vscard_common.h" From 1b01b4e717ada625575c207105b0b270c0b8467d Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Tue, 29 Mar 2011 15:29:28 +0200 Subject: [PATCH 072/386] Only build ivshmem when CONFIG_PCI && CONFIG_KVM The ivshmem depends on PCI and KVM, not only KVM. Reflect this in the Makefile, so we don't get build errors on s390x. Signed-off-by: Alexander Graf <agraf@suse.de> CC: Cam Macdonell <cam@cs.ualberta.ca> CC: Juan Quintela <quintela@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- Makefile.target | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index ddb0931f68..04e20dde95 100644 --- a/Makefile.target +++ b/Makefile.target @@ -209,7 +209,13 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS) obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o # Inter-VM PCI shared memory -obj-$(CONFIG_KVM) += ivshmem.o +CONFIG_IVSHMEM = +ifeq ($(CONFIG_KVM), y) + ifeq ($(CONFIG_PCI), y) + CONFIG_IVSHMEM = y + endif +endif +obj-$(CONFIG_IVSHMEM) += ivshmem.o # Hardware support obj-i386-y += vga.o From 29f82b37e5341b96e514373854411c4fcb935fc0 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Tue, 29 Mar 2011 15:29:29 +0200 Subject: [PATCH 073/386] virtio: use generic name when possible We have two different virtio buses: pci and s390. The abstraction path taken in qemu is to have generic aliases for each device type in the architecture specific qdev devices. So let's make use of these aliases whenever we can and define them whenever we can. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- blockdev.c | 2 +- hw/s390-virtio-bus.c | 2 ++ hw/virtio-pci.c | 3 +++ vl.c | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/blockdev.c b/blockdev.c index ecf2252d83..bbe92fe196 100644 --- a/blockdev.c +++ b/blockdev.c @@ -503,7 +503,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) case IF_VIRTIO: /* add virtio block device */ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); - qemu_opt_set(opts, "driver", "virtio-blk-pci"); + qemu_opt_set(opts, "driver", "virtio-blk"); qemu_opt_set(opts, "drive", dinfo->id); if (devaddr) qemu_opt_set(opts, "addr", devaddr); diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 784dc01b97..d44eff25aa 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -325,6 +325,7 @@ static const VirtIOBindings virtio_s390_bindings = { static VirtIOS390DeviceInfo s390_virtio_net = { .init = s390_virtio_net_init, .qdev.name = "virtio-net-s390", + .qdev.alias = "virtio-net", .qdev.size = sizeof(VirtIOS390Device), .qdev.props = (Property[]) { DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic), @@ -340,6 +341,7 @@ static VirtIOS390DeviceInfo s390_virtio_net = { static VirtIOS390DeviceInfo s390_virtio_blk = { .init = s390_virtio_blk_init, .qdev.name = "virtio-blk-s390", + .qdev.alias = "virtio-blk", .qdev.size = sizeof(VirtIOS390Device), .qdev.props = (Property[]) { DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index df10703b29..555f23f1da 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -873,6 +873,7 @@ static PCIDeviceInfo virtio_info[] = { .qdev.reset = virtio_pci_reset, },{ .qdev.name = "virtio-net-pci", + .qdev.alias = "virtio-net", .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_net_init_pci, .exit = virtio_net_exit_pci, @@ -911,6 +912,7 @@ static PCIDeviceInfo virtio_info[] = { .qdev.reset = virtio_pci_reset, },{ .qdev.name = "virtio-balloon-pci", + .qdev.alias = "virtio-balloon", .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_balloon_init_pci, .exit = virtio_exit_pci, @@ -922,6 +924,7 @@ static PCIDeviceInfo virtio_info[] = { },{ #ifdef CONFIG_VIRTFS .qdev.name = "virtio-9p-pci", + .qdev.alias = "virtio-9p", .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_9p_init_pci, .qdev.props = (Property[]) { diff --git a/vl.c b/vl.c index 4d9e503d7c..de232b75e6 100644 --- a/vl.c +++ b/vl.c @@ -1598,7 +1598,7 @@ static int balloon_parse(const char *arg) /* create empty opts */ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); } - qemu_opt_set(opts, "driver", "virtio-balloon-pci"); + qemu_opt_set(opts, "driver", "virtio-balloon"); return 0; } @@ -2484,12 +2484,12 @@ int main(int argc, char **argv, char **envp) qemu_opt_get(opts, "path"), qemu_opt_get(opts, "security_model")); - len = strlen("virtio-9p-pci,fsdev=,mount_tag="); + len = strlen("virtio-9p,fsdev=,mount_tag="); len += 2*strlen(qemu_opt_get(opts, "mount_tag")); arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p)); snprintf(arg_9p, (len + 1) * sizeof(*arg_9p), - "virtio-9p-pci,fsdev=%s,mount_tag=%s", + "virtio-9p,fsdev=%s,mount_tag=%s", qemu_opt_get(opts, "mount_tag"), qemu_opt_get(opts, "mount_tag")); From 359507eed1b6d8ae2392e0c8fe32d5f0de9d1d75 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Tue, 29 Mar 2011 15:29:30 +0200 Subject: [PATCH 074/386] s390x: fix KVM target During Jan's rework of the generic KVM layer, he added some more error checks and actually aborted if something went wrong. Unfortunately, one of the s390 internal error codes slipped through, aborting the VM without needing to. This patch fixes booting of S390x virtual machines in KVM. Signed-off-by: Alexander Graf <agraf@suse.de> CC: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-s390x/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 91232038ea..ae7dc561b3 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -441,7 +441,7 @@ static int handle_instruction(CPUState *env, struct kvm_run *run) if (r < 0) { enter_pgmcheck(env, 0x0001); } - return r; + return 0; } static int handle_intercept(CPUState *env) From 6be9b4147adb27f78ec944af5abfc97e7cd0d066 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Tue, 29 Mar 2011 15:29:31 +0200 Subject: [PATCH 075/386] s390x: fix s390-virtio-serial Commit 6b331efb733a0f913ddc0b7762a1307dec304061 broke the s390 proxy version of virtio-serial by only taking its PCI brother into account. So let's adjust s390-virtio-serial the same way as its PCI counterpart, making it compile and work again. Signed-off-by: Alexander Graf <agraf@suse.de> CC: Amit Shah <amit.shah@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/s390-virtio-bus.c | 6 +++--- hw/s390-virtio-bus.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index d44eff25aa..58af164880 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -139,7 +139,7 @@ static int s390_virtio_serial_init(VirtIOS390Device *dev) bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus); - vdev = virtio_serial_init((DeviceState *)dev, dev->max_virtserial_ports); + vdev = virtio_serial_init((DeviceState *)dev, &dev->serial); if (!vdev) { return -1; } @@ -355,8 +355,8 @@ static VirtIOS390DeviceInfo s390_virtio_serial = { .qdev.alias = "virtio-serial", .qdev.size = sizeof(VirtIOS390Device), .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, max_virtserial_ports, - 31), + DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, + serial.max_virtserial_ports, 31), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 33379a3ba4..edf6d04570 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -18,6 +18,7 @@ */ #include "virtio-net.h" +#include "virtio-serial.h" #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ @@ -43,8 +44,7 @@ typedef struct VirtIOS390Device { BlockConf block; NICConf nic; uint32_t host_features; - /* Max. number of ports we can have for a the virtio-serial device */ - uint32_t max_virtserial_ports; + virtio_serial_conf serial; virtio_net_conf net; } VirtIOS390Device; From db500609847caa9d43a1186bb7ab2df56fa8e1b0 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht <uli@suse.de> Date: Tue, 29 Mar 2011 15:29:32 +0200 Subject: [PATCH 076/386] s390x: Enable disassembler for s390x This patch enables the instruction disassembler when using an S390x target. Signed-off-by: Ulrich Hecht <uli@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- disas.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/disas.c b/disas.c index c76f36f590..17b4ce47b2 100644 --- a/disas.c +++ b/disas.c @@ -215,6 +215,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) disasm_info.mach = bfd_mach_cris_v32; print_insn = print_insn_crisv32; } +#elif defined(TARGET_S390X) + disasm_info.mach = bfd_mach_s390_64; + print_insn = print_insn_s390; #elif defined(TARGET_MICROBLAZE) disasm_info.mach = bfd_arch_microblaze; print_insn = print_insn_microblaze; @@ -414,6 +417,9 @@ void monitor_disas(Monitor *mon, CPUState *env, #elif defined(TARGET_SH4) disasm_info.mach = bfd_mach_sh4; print_insn = print_insn_sh; +#elif defined(TARGET_S390X) + disasm_info.mach = bfd_mach_s390_64; + print_insn = print_insn_s390; #else monitor_printf(mon, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", pc); From bc434676dc99f492492b8d0b23a0e49262202029 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht <uli@suse.de> Date: Tue, 29 Mar 2011 15:29:33 +0200 Subject: [PATCH 077/386] s390x: Enable nptl for s390x S390x user emulation can do nptl. Reflect this in the configure script. Signed-off-by: Ulrich Hecht <uli@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 2ef5c75054..e91525fd1c 100755 --- a/configure +++ b/configure @@ -3150,6 +3150,7 @@ case "$target_arch2" in target_phys_bits=64 ;; s390x) + target_nptl="yes" target_phys_bits=64 ;; *) From 490f4edcdf64524fb29a758e381985b6b0cf002f Mon Sep 17 00:00:00 2001 From: Ulrich Hecht <uli@suse.de> Date: Tue, 29 Mar 2011 15:29:34 +0200 Subject: [PATCH 078/386] s390x: enable CPU_QuadU S390x uses the QuadU type, so let's enable it. Signed-off-by: Ulrich Hecht <uli@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- cpu-all.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 4f4631d79c..4cc445ffc3 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -138,7 +138,7 @@ typedef union { uint64_t ll; } CPU_DoubleU; -#ifdef TARGET_SPARC +#if defined(TARGET_SPARC) || defined(TARGET_S390X) typedef union { float128 q; #if defined(HOST_WORDS_BIGENDIAN) \ From 449aa4a4915f4d2f43126eec6031cfc96ef06687 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Mon, 4 Apr 2011 07:14:03 +0200 Subject: [PATCH 079/386] Revert "ioapic: when switches to level trigger mode, interrupts raised repeatedly." This reverts commit 9bcfc7daabb138b0fe3d64d74892942d482e5bbd. --- hw/ioapic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ioapic.c b/hw/ioapic.c index 8557e5cac6..569327d1e9 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -164,7 +164,6 @@ static void ioapic_set_irq(void *opaque, int vector, int level) if (level) { s->irr |= mask; ioapic_service(s); - s->irr &= ~mask; } } } From 25a8bb96f4a9dcb27dc55027b81d9646273a937b Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:32 +0100 Subject: [PATCH 080/386] lm32: add Milkymist AC97 support This patch adds support for the Milkymist AC97 compatible sound output and input core. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + configure | 3 + hw/milkymist-ac97.c | 335 ++++++++++++++++++++++++++++++++++++++++++++ trace-events | 12 ++ 4 files changed, 351 insertions(+) create mode 100644 hw/milkymist-ac97.c diff --git a/Makefile.target b/Makefile.target index 04e20dde95..0610bb8c81 100644 --- a/Makefile.target +++ b/Makefile.target @@ -267,6 +267,7 @@ obj-lm32-y += lm32_juart.o obj-lm32-y += lm32_timer.o obj-lm32-y += lm32_uart.o obj-lm32-y += lm32_sys.o +obj-lm32-y += milkymist-ac97.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/configure b/configure index e91525fd1c..2e7b4f8718 100755 --- a/configure +++ b/configure @@ -3350,6 +3350,9 @@ if test "$target_softmmu" = "yes" ; then arm) cflags="-DHAS_AUDIO $cflags" ;; + lm32) + cflags="-DHAS_AUDIO $cflags" + ;; i386|mips|ppc) cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags" ;; diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c new file mode 100644 index 0000000000..6c9e318aa2 --- /dev/null +++ b/hw/milkymist-ac97.c @@ -0,0 +1,335 @@ +/* + * QEMU model of the Milkymist System Controller. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/ac97.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "audio/audio.h" +#include "qemu-error.h" + +enum { + R_AC97_CTRL = 0, + R_AC97_ADDR, + R_AC97_DATAOUT, + R_AC97_DATAIN, + R_D_CTRL, + R_D_ADDR, + R_D_REMAINING, + R_RESERVED, + R_U_CTRL, + R_U_ADDR, + R_U_REMAINING, + R_MAX +}; + +enum { + AC97_CTRL_RQEN = (1<<0), + AC97_CTRL_WRITE = (1<<1), +}; + +enum { + CTRL_EN = (1<<0), +}; + +struct MilkymistAC97State { + SysBusDevice busdev; + + QEMUSoundCard card; + SWVoiceIn *voice_in; + SWVoiceOut *voice_out; + + uint32_t regs[R_MAX]; + + qemu_irq crrequest_irq; + qemu_irq crreply_irq; + qemu_irq dmar_irq; + qemu_irq dmaw_irq; +}; +typedef struct MilkymistAC97State MilkymistAC97State; + +static void update_voices(MilkymistAC97State *s) +{ + if (s->regs[R_D_CTRL] & CTRL_EN) { + AUD_set_active_out(s->voice_out, 1); + } else { + AUD_set_active_out(s->voice_out, 0); + } + + if (s->regs[R_U_CTRL] & CTRL_EN) { + AUD_set_active_in(s->voice_in, 1); + } else { + AUD_set_active_in(s->voice_in, 0); + } +} + +static uint32_t ac97_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistAC97State *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_AC97_CTRL: + case R_AC97_ADDR: + case R_AC97_DATAOUT: + case R_AC97_DATAIN: + case R_D_CTRL: + case R_D_ADDR: + case R_D_REMAINING: + case R_U_CTRL: + case R_U_ADDR: + case R_U_REMAINING: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_ac97: read access to unkown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_ac97_memory_read(addr << 2, r); + + return r; +} + +static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistAC97State *s = opaque; + + trace_milkymist_ac97_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_AC97_CTRL: + /* always raise an IRQ according to the direction */ + if (value & AC97_CTRL_RQEN) { + if (value & AC97_CTRL_WRITE) { + trace_milkymist_ac97_pulse_irq_crrequest(); + qemu_irq_pulse(s->crrequest_irq); + } else { + trace_milkymist_ac97_pulse_irq_crreply(); + qemu_irq_pulse(s->crreply_irq); + } + } + + /* RQEN is self clearing */ + s->regs[addr] = value & ~AC97_CTRL_RQEN; + break; + case R_D_CTRL: + case R_U_CTRL: + s->regs[addr] = value; + update_voices(s); + break; + case R_AC97_ADDR: + case R_AC97_DATAOUT: + case R_AC97_DATAIN: + case R_D_ADDR: + case R_D_REMAINING: + case R_U_ADDR: + case R_U_REMAINING: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_ac97: write access to unkown register 0x" + TARGET_FMT_plx, addr); + break; + } + +} + +static CPUReadMemoryFunc * const ac97_read_fn[] = { + NULL, + NULL, + &ac97_read, +}; + +static CPUWriteMemoryFunc * const ac97_write_fn[] = { + NULL, + NULL, + &ac97_write, +}; + +static void ac97_in_cb(void *opaque, int avail_b) +{ + MilkymistAC97State *s = opaque; + uint8_t buf[4096]; + uint32_t remaining = s->regs[R_U_REMAINING]; + int temp = audio_MIN(remaining, avail_b); + uint32_t addr = s->regs[R_U_ADDR]; + int transferred = 0; + + trace_milkymist_ac97_in_cb(avail_b, remaining); + + /* prevent from raising an IRQ */ + if (temp == 0) { + return; + } + + while (temp) { + int acquired, to_copy; + + to_copy = audio_MIN(temp, sizeof(buf)); + acquired = AUD_read(s->voice_in, buf, to_copy); + if (!acquired) { + break; + } + + cpu_physical_memory_write(addr, buf, acquired); + + temp -= acquired; + addr += acquired; + transferred += acquired; + } + + trace_milkymist_ac97_in_cb_transferred(transferred); + + s->regs[R_U_ADDR] = addr; + s->regs[R_U_REMAINING] -= transferred; + + if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) { + trace_milkymist_ac97_pulse_irq_dmaw(); + qemu_irq_pulse(s->dmaw_irq); + } +} + +static void ac97_out_cb(void *opaque, int free_b) +{ + MilkymistAC97State *s = opaque; + uint8_t buf[4096]; + uint32_t remaining = s->regs[R_D_REMAINING]; + int temp = audio_MIN(remaining, free_b); + uint32_t addr = s->regs[R_D_ADDR]; + int transferred = 0; + + trace_milkymist_ac97_out_cb(free_b, remaining); + + /* prevent from raising an IRQ */ + if (temp == 0) { + return; + } + + while (temp) { + int copied, to_copy; + + to_copy = audio_MIN(temp, sizeof(buf)); + cpu_physical_memory_read(addr, buf, to_copy); + copied = AUD_write(s->voice_out, buf, to_copy); + if (!copied) { + break; + } + temp -= copied; + addr += copied; + transferred += copied; + } + + trace_milkymist_ac97_out_cb_transferred(transferred); + + s->regs[R_D_ADDR] = addr; + s->regs[R_D_REMAINING] -= transferred; + + if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) { + trace_milkymist_ac97_pulse_irq_dmar(); + qemu_irq_pulse(s->dmar_irq); + } +} + +static void milkymist_ac97_reset(DeviceState *d) +{ + MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + AUD_set_active_in(s->voice_in, 0); + AUD_set_active_out(s->voice_out, 0); +} + +static int ac97_post_load(void *opaque, int version_id) +{ + MilkymistAC97State *s = opaque; + + update_voices(s); + + return 0; +} + +static int milkymist_ac97_init(SysBusDevice *dev) +{ + MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev); + int ac97_regs; + + struct audsettings as; + sysbus_init_irq(dev, &s->crrequest_irq); + sysbus_init_irq(dev, &s->crreply_irq); + sysbus_init_irq(dev, &s->dmar_irq); + sysbus_init_irq(dev, &s->dmaw_irq); + + AUD_register_card("Milkymist AC'97", &s->card); + + as.freq = 48000; + as.nchannels = 2; + as.fmt = AUD_FMT_S16; + as.endianness = 1; + + s->voice_in = AUD_open_in(&s->card, s->voice_in, + "mm_ac97.in", s, ac97_in_cb, &as); + s->voice_out = AUD_open_out(&s->card, s->voice_out, + "mm_ac97.out", s, ac97_out_cb, &as); + + ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, ac97_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_ac97 = { + .name = "milkymist-ac97", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ac97_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_ac97_info = { + .init = milkymist_ac97_init, + .qdev.name = "milkymist-ac97", + .qdev.size = sizeof(MilkymistAC97State), + .qdev.vmsd = &vmstate_milkymist_ac97, + .qdev.reset = milkymist_ac97_reset, +}; + +static void milkymist_ac97_register(void) +{ + sysbus_register_withprop(&milkymist_ac97_info); +} + +device_init(milkymist_ac97_register) diff --git a/trace-events b/trace-events index 90c9e0b5e7..fc8caa8e54 100644 --- a/trace-events +++ b/trace-events @@ -286,3 +286,15 @@ disable lm32_uart_irq_state(int level) "irq state %d" # hw/lm32_sys.c disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" + +# hw/milkymist-ac97.c +disable milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request" +disable milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply" +disable milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write" +disable milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read" +disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u" +disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" +disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" +disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" From e4dc6d2cdca3e64fe09d3c76a56294b7b7aa7d7f Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:33 +0100 Subject: [PATCH 081/386] lm32: add Milkymist HPDMC support This patch adds support for the Milkymist's High Performance Dynamic Memory Controller. This is just a dumb model without any functionality. While the real hardware acts for example as a bridge between software and hardware for sending SDRAM commans, this model will only eat up these commands and always returns the expected hardware states, eg. PLL locked etc. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-hpdmc.c | 161 +++++++++++++++++++++++++++++++++++++++++++ trace-events | 4 ++ 3 files changed, 166 insertions(+) create mode 100644 hw/milkymist-hpdmc.c diff --git a/Makefile.target b/Makefile.target index 0610bb8c81..0e4f69379b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -268,6 +268,7 @@ obj-lm32-y += lm32_timer.o obj-lm32-y += lm32_uart.o obj-lm32-y += lm32_sys.o obj-lm32-y += milkymist-ac97.o +obj-lm32-y += milkymist-hpdmc.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c new file mode 100644 index 0000000000..c0962fb528 --- /dev/null +++ b/hw/milkymist-hpdmc.c @@ -0,0 +1,161 @@ +/* + * QEMU model of the Milkymist High Performance Dynamic Memory Controller. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/hpdmc.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "qemu-error.h" + +enum { + R_SYSTEM = 0, + R_BYPASS, + R_TIMING, + R_IODELAY, + R_MAX +}; + +enum { + IODELAY_DQSDELAY_RDY = (1<<5), + IODELAY_PLL1_LOCKED = (1<<6), + IODELAY_PLL2_LOCKED = (1<<7), +}; + +struct MilkymistHpdmcState { + SysBusDevice busdev; + + uint32_t regs[R_MAX]; +}; +typedef struct MilkymistHpdmcState MilkymistHpdmcState; + +static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistHpdmcState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SYSTEM: + case R_BYPASS: + case R_TIMING: + case R_IODELAY: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_hpdmc: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_hpdmc_memory_read(addr << 2, r); + + return r; +} + +static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistHpdmcState *s = opaque; + + trace_milkymist_hpdmc_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_SYSTEM: + case R_BYPASS: + case R_TIMING: + s->regs[addr] = value; + break; + case R_IODELAY: + /* ignore writes */ + break; + + default: + error_report("milkymist_hpdmc: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const hpdmc_read_fn[] = { + NULL, + NULL, + &hpdmc_read, +}; + +static CPUWriteMemoryFunc * const hpdmc_write_fn[] = { + NULL, + NULL, + &hpdmc_write, +}; + +static void milkymist_hpdmc_reset(DeviceState *d) +{ + MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + /* defaults */ + s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED + | IODELAY_PLL2_LOCKED; +} + +static int milkymist_hpdmc_init(SysBusDevice *dev) +{ + MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev); + int hpdmc_regs; + + hpdmc_regs = cpu_register_io_memory(hpdmc_read_fn, hpdmc_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, hpdmc_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_hpdmc = { + .name = "milkymist-hpdmc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_hpdmc_info = { + .init = milkymist_hpdmc_init, + .qdev.name = "milkymist-hpdmc", + .qdev.size = sizeof(MilkymistHpdmcState), + .qdev.vmsd = &vmstate_milkymist_hpdmc, + .qdev.reset = milkymist_hpdmc_reset, +}; + +static void milkymist_hpdmc_register(void) +{ + sysbus_register_withprop(&milkymist_hpdmc_info); +} + +device_init(milkymist_hpdmc_register) diff --git a/trace-events b/trace-events index fc8caa8e54..9ccf82c9da 100644 --- a/trace-events +++ b/trace-events @@ -298,3 +298,7 @@ disable milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining disable milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" + +# hw/milkymist-hpdmc.c +disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" From b4e37d98560c41afb944c616ce5c1df8577c35da Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:34 +0100 Subject: [PATCH 082/386] lm32: add Milkymist memory card support This patch adds support for Milkymist's memory card core. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + default-configs/lm32-softmmu.mak | 1 + hw/milkymist-memcard.c | 294 +++++++++++++++++++++++++++++++ trace-events | 8 +- 4 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 hw/milkymist-memcard.c diff --git a/Makefile.target b/Makefile.target index 0e4f69379b..d58358b900 100644 --- a/Makefile.target +++ b/Makefile.target @@ -269,6 +269,7 @@ obj-lm32-y += lm32_uart.o obj-lm32-y += lm32_sys.o obj-lm32-y += milkymist-ac97.o obj-lm32-y += milkymist-hpdmc.o +obj-lm32-y += milkymist-memcard.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak index ab774a2509..3e7f57e700 100644 --- a/default-configs/lm32-softmmu.mak +++ b/default-configs/lm32-softmmu.mak @@ -2,3 +2,4 @@ CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y +CONFIG_SD=y diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c new file mode 100644 index 0000000000..06077af82a --- /dev/null +++ b/hw/milkymist-memcard.c @@ -0,0 +1,294 @@ +/* + * QEMU model of the Milkymist SD Card Controller. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/memcard.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "sysemu.h" +#include "trace.h" +#include "qemu-error.h" +#include "blockdev.h" +#include "sd.h" + +enum { + ENABLE_CMD_TX = (1<<0), + ENABLE_CMD_RX = (1<<1), + ENABLE_DAT_TX = (1<<2), + ENABLE_DAT_RX = (1<<3), +}; + +enum { + PENDING_CMD_TX = (1<<0), + PENDING_CMD_RX = (1<<1), + PENDING_DAT_TX = (1<<2), + PENDING_DAT_RX = (1<<3), +}; + +enum { + START_CMD_TX = (1<<0), + START_DAT_RX = (1<<1), +}; + +enum { + R_CLK2XDIV = 0, + R_ENABLE, + R_PENDING, + R_START, + R_CMD, + R_DAT, + R_MAX +}; + +struct MilkymistMemcardState { + SysBusDevice busdev; + SDState *card; + + int command_write_ptr; + int response_read_ptr; + int response_len; + int ignore_next_cmd; + int enabled; + uint8_t command[6]; + uint8_t response[17]; + uint32_t regs[R_MAX]; +}; +typedef struct MilkymistMemcardState MilkymistMemcardState; + +static void update_pending_bits(MilkymistMemcardState *s) +{ + /* transmits are instantaneous, thus tx pending bits are never set */ + s->regs[R_PENDING] = 0; + /* if rx is enabled the corresponding pending bits are always set */ + if (s->regs[R_ENABLE] & ENABLE_CMD_RX) { + s->regs[R_PENDING] |= PENDING_CMD_RX; + } + if (s->regs[R_ENABLE] & ENABLE_DAT_RX) { + s->regs[R_PENDING] |= PENDING_DAT_RX; + } +} + +static void memcard_sd_command(MilkymistMemcardState *s) +{ + SDRequest req; + + req.cmd = s->command[0] & 0x3f; + req.arg = (s->command[1] << 24) | (s->command[2] << 16) + | (s->command[3] << 8) | s->command[4]; + req.crc = s->command[5]; + + s->response[0] = req.cmd; + s->response_len = sd_do_command(s->card, &req, s->response+1); + s->response_read_ptr = 0; + + if (s->response_len == 16) { + /* R2 response */ + s->response[0] = 0x3f; + s->response_len += 1; + } else if (s->response_len == 4) { + /* no crc calculation, insert dummy byte */ + s->response[5] = 0; + s->response_len += 2; + } + + if (req.cmd == 0) { + /* next write is a dummy byte to clock the initialization of the sd + * card */ + s->ignore_next_cmd = 1; + } +} + +static uint32_t memcard_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistMemcardState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CMD: + if (!s->enabled) { + r = 0xff; + } else { + r = s->response[s->response_read_ptr++]; + if (s->response_read_ptr > s->response_len) { + error_report("milkymist_memcard: " + "read more cmd bytes than available. Clipping."); + s->response_read_ptr = 0; + } + } + break; + case R_DAT: + if (!s->enabled) { + r = 0xffffffff; + } else { + r = 0; + r |= sd_read_data(s->card) << 24; + r |= sd_read_data(s->card) << 16; + r |= sd_read_data(s->card) << 8; + r |= sd_read_data(s->card); + } + break; + case R_CLK2XDIV: + case R_ENABLE: + case R_PENDING: + case R_START: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_memcard: read access to unkown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_memcard_memory_read(addr << 2, r); + + return r; +} + +static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistMemcardState *s = opaque; + + trace_milkymist_memcard_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_PENDING: + /* clear rx pending bits */ + s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX)); + update_pending_bits(s); + break; + case R_CMD: + if (!s->enabled) { + break; + } + if (s->ignore_next_cmd) { + s->ignore_next_cmd = 0; + break; + } + s->command[s->command_write_ptr] = value & 0xff; + s->command_write_ptr = (s->command_write_ptr + 1) % 6; + if (s->command_write_ptr == 0) { + memcard_sd_command(s); + } + break; + case R_DAT: + if (!s->enabled) { + break; + } + sd_write_data(s->card, (value >> 24) & 0xff); + sd_write_data(s->card, (value >> 16) & 0xff); + sd_write_data(s->card, (value >> 8) & 0xff); + sd_write_data(s->card, value & 0xff); + break; + case R_ENABLE: + s->regs[addr] = value; + update_pending_bits(s); + break; + case R_CLK2XDIV: + case R_START: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_memcard: write access to unkown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const memcard_read_fn[] = { + NULL, + NULL, + &memcard_read, +}; + +static CPUWriteMemoryFunc * const memcard_write_fn[] = { + NULL, + NULL, + &memcard_write, +}; + +static void milkymist_memcard_reset(DeviceState *d) +{ + MilkymistMemcardState *s = + container_of(d, MilkymistMemcardState, busdev.qdev); + int i; + + s->command_write_ptr = 0; + s->response_read_ptr = 0; + s->response_len = 0; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } +} + +static int milkymist_memcard_init(SysBusDevice *dev) +{ + MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev); + DriveInfo *dinfo; + int memcard_regs; + + dinfo = drive_get_next(IF_SD); + s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0); + s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0; + + memcard_regs = cpu_register_io_memory(memcard_read_fn, memcard_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, memcard_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_memcard = { + .name = "milkymist-memcard", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), + VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), + VMSTATE_INT32(response_len, MilkymistMemcardState), + VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState), + VMSTATE_INT32(enabled, MilkymistMemcardState), + VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6), + VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17), + VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_memcard_info = { + .init = milkymist_memcard_init, + .qdev.name = "milkymist-memcard", + .qdev.size = sizeof(MilkymistMemcardState), + .qdev.vmsd = &vmstate_milkymist_memcard, + .qdev.reset = milkymist_memcard_reset, +}; + +static void milkymist_memcard_register(void) +{ + sysbus_register_withprop(&milkymist_memcard_info); +} + +device_init(milkymist_memcard_register) diff --git a/trace-events b/trace-events index 9ccf82c9da..7627595713 100644 --- a/trace-events +++ b/trace-events @@ -300,5 +300,9 @@ disable milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining % disable milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" # hw/milkymist-hpdmc.c -disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x" +disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x" + +# hw/milkymist-memcard.c +disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" From 0742454485d8fe5c88de390af0b20ce6c6e164b2 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:35 +0100 Subject: [PATCH 083/386] lm32: add Milkymist Minimac support This patch adds support for Milkymist's minimal Ethernet MAC. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-minimac.c | 568 +++++++++++++++++++++++++++++++++++++++++ trace-events | 12 + 3 files changed, 581 insertions(+) create mode 100644 hw/milkymist-minimac.c diff --git a/Makefile.target b/Makefile.target index d58358b900..6fd8a17116 100644 --- a/Makefile.target +++ b/Makefile.target @@ -270,6 +270,7 @@ obj-lm32-y += lm32_sys.o obj-lm32-y += milkymist-ac97.o obj-lm32-y += milkymist-hpdmc.o obj-lm32-y += milkymist-memcard.o +obj-lm32-y += milkymist-minimac.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-minimac.c b/hw/milkymist-minimac.c new file mode 100644 index 0000000000..b07f18d8a7 --- /dev/null +++ b/hw/milkymist-minimac.c @@ -0,0 +1,568 @@ +/* + * QEMU model of the Milkymist minimac block. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/minimac.pdf + * + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "net.h" +#include "qemu-error.h" + +#include <zlib.h> + +enum { + R_SETUP = 0, + R_MDIO, + R_STATE0, + R_ADDR0, + R_COUNT0, + R_STATE1, + R_ADDR1, + R_COUNT1, + R_STATE2, + R_ADDR2, + R_COUNT2, + R_STATE3, + R_ADDR3, + R_COUNT3, + R_TXADDR, + R_TXCOUNT, + R_MAX +}; + +enum { + SETUP_RX_RST = (1<<0), + SETUP_TX_RST = (1<<2), +}; + +enum { + MDIO_DO = (1<<0), + MDIO_DI = (1<<1), + MDIO_OE = (1<<2), + MDIO_CLK = (1<<3), +}; + +enum { + STATE_EMPTY = 0, + STATE_LOADED = 1, + STATE_PENDING = 2, +}; + +enum { + MDIO_OP_WRITE = 1, + MDIO_OP_READ = 2, +}; + +enum mdio_state { + MDIO_STATE_IDLE, + MDIO_STATE_READING, + MDIO_STATE_WRITING, +}; + +enum { + R_PHY_ID1 = 2, + R_PHY_ID2 = 3, + R_PHY_MAX = 32 +}; + +#define MINIMAC_MTU 1530 + +struct MilkymistMinimacMdioState { + int last_clk; + int count; + uint32_t data; + uint16_t data_out; + int state; + + uint8_t phy_addr; + uint8_t reg_addr; +}; +typedef struct MilkymistMinimacMdioState MilkymistMinimacMdioState; + +struct MilkymistMinimacState { + SysBusDevice busdev; + NICState *nic; + NICConf conf; + char *phy_model; + + qemu_irq rx_irq; + qemu_irq tx_irq; + + uint32_t regs[R_MAX]; + + MilkymistMinimacMdioState mdio; + + uint16_t phy_regs[R_PHY_MAX]; +}; +typedef struct MilkymistMinimacState MilkymistMinimacState; + +static const uint8_t preamble_sfd[] = { + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5 +}; + +static void minimac_mdio_write_reg(MilkymistMinimacState *s, + uint8_t phy_addr, uint8_t reg_addr, uint16_t value) +{ + trace_milkymist_minimac_mdio_write(phy_addr, reg_addr, value); + + /* nop */ +} + +static uint16_t minimac_mdio_read_reg(MilkymistMinimacState *s, + uint8_t phy_addr, uint8_t reg_addr) +{ + uint16_t r = s->phy_regs[reg_addr]; + + trace_milkymist_minimac_mdio_read(phy_addr, reg_addr, r); + + return r; +} + +static void minimac_update_mdio(MilkymistMinimacState *s) +{ + MilkymistMinimacMdioState *m = &s->mdio; + + /* detect rising clk edge */ + if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) { + /* shift data in */ + int bit = ((s->regs[R_MDIO] & MDIO_DO) + && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0; + m->data = (m->data << 1) | bit; + + /* check for sync */ + if (m->data == 0xffffffff) { + m->count = 32; + } + + if (m->count == 16) { + uint8_t start = (m->data >> 14) & 0x3; + uint8_t op = (m->data >> 12) & 0x3; + uint8_t ta = (m->data) & 0x3; + + if (start == 1 && op == MDIO_OP_WRITE && ta == 2) { + m->state = MDIO_STATE_WRITING; + } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) { + m->state = MDIO_STATE_READING; + } else { + m->state = MDIO_STATE_IDLE; + } + + if (m->state != MDIO_STATE_IDLE) { + m->phy_addr = (m->data >> 7) & 0x1f; + m->reg_addr = (m->data >> 2) & 0x1f; + } + + if (m->state == MDIO_STATE_READING) { + m->data_out = minimac_mdio_read_reg(s, m->phy_addr, + m->reg_addr); + } + } + + if (m->count < 16 && m->state == MDIO_STATE_READING) { + int bit = (m->data_out & 0x8000) ? 1 : 0; + m->data_out <<= 1; + + if (bit) { + s->regs[R_MDIO] |= MDIO_DI; + } else { + s->regs[R_MDIO] &= ~MDIO_DI; + } + } + + if (m->count == 0 && m->state) { + if (m->state == MDIO_STATE_WRITING) { + uint16_t data = m->data & 0xffff; + minimac_mdio_write_reg(s, m->phy_addr, m->reg_addr, data); + } + m->state = MDIO_STATE_IDLE; + } + m->count--; + } + + m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0; +} + +static size_t assemble_frame(uint8_t *buf, size_t size, + const uint8_t *payload, size_t payload_size) +{ + uint32_t crc; + + if (size < payload_size + 12) { + error_report("milkymist_minimac: received too big ethernet frame"); + return 0; + } + + /* prepend preamble and sfd */ + memcpy(buf, preamble_sfd, 8); + + /* now copy the payload */ + memcpy(buf + 8, payload, payload_size); + + /* pad frame if needed */ + if (payload_size < 60) { + memset(buf + payload_size + 8, 0, 60 - payload_size); + payload_size = 60; + } + + /* append fcs */ + crc = cpu_to_le32(crc32(0, buf + 8, payload_size)); + memcpy(buf + payload_size + 8, &crc, 4); + + return payload_size + 12; +} + +static void minimac_tx(MilkymistMinimacState *s) +{ + uint8_t buf[MINIMAC_MTU]; + uint32_t txcount = s->regs[R_TXCOUNT]; + + /* do nothing if transmission logic is in reset */ + if (s->regs[R_SETUP] & SETUP_TX_RST) { + return; + } + + if (txcount < 64) { + error_report("milkymist_minimac: ethernet frame too small (%u < %u)\n", + txcount, 64); + return; + } + + if (txcount > MINIMAC_MTU) { + error_report("milkymist_minimac: MTU exceeded (%u > %u)\n", + txcount, MINIMAC_MTU); + return; + } + + /* dma */ + cpu_physical_memory_read(s->regs[R_TXADDR], buf, txcount); + + if (memcmp(buf, preamble_sfd, 8) != 0) { + error_report("milkymist_minimac: frame doesn't contain the preamble " + "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + return; + } + + trace_milkymist_minimac_tx_frame(txcount - 12); + + /* send packet, skipping preamble and sfd */ + qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12); + + s->regs[R_TXCOUNT] = 0; + + trace_milkymist_minimac_pulse_irq_tx(); + qemu_irq_pulse(s->tx_irq); +} + +static ssize_t minimac_rx(VLANClientState *nc, const uint8_t *buf, size_t size) +{ + MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + + uint32_t r_addr; + uint32_t r_count; + uint32_t r_state; + + uint8_t frame_buf[MINIMAC_MTU]; + size_t frame_size; + + trace_milkymist_minimac_rx_frame(buf, size); + + /* discard frames if nic is in reset */ + if (s->regs[R_SETUP] & SETUP_RX_RST) { + return size; + } + + /* choose appropriate slot */ + if (s->regs[R_STATE0] == STATE_LOADED) { + r_addr = R_ADDR0; + r_count = R_COUNT0; + r_state = R_STATE0; + } else if (s->regs[R_STATE1] == STATE_LOADED) { + r_addr = R_ADDR1; + r_count = R_COUNT1; + r_state = R_STATE1; + } else if (s->regs[R_STATE2] == STATE_LOADED) { + r_addr = R_ADDR2; + r_count = R_COUNT2; + r_state = R_STATE2; + } else if (s->regs[R_STATE3] == STATE_LOADED) { + r_addr = R_ADDR3; + r_count = R_COUNT3; + r_state = R_STATE3; + } else { + trace_milkymist_minimac_drop_rx_frame(buf); + return size; + } + + /* assemble frame */ + frame_size = assemble_frame(frame_buf, sizeof(frame_buf), buf, size); + + if (frame_size == 0) { + return size; + } + + trace_milkymist_minimac_rx_transfer(buf, frame_size); + + /* do dma */ + cpu_physical_memory_write(s->regs[r_addr], frame_buf, frame_size); + + /* update slot */ + s->regs[r_count] = frame_size; + s->regs[r_state] = STATE_PENDING; + + trace_milkymist_minimac_pulse_irq_rx(); + qemu_irq_pulse(s->rx_irq); + + return size; +} + +static uint32_t +minimac_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistMinimacState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SETUP: + case R_MDIO: + case R_STATE0: + case R_ADDR0: + case R_COUNT0: + case R_STATE1: + case R_ADDR1: + case R_COUNT1: + case R_STATE2: + case R_ADDR2: + case R_COUNT2: + case R_STATE3: + case R_ADDR3: + case R_COUNT3: + case R_TXADDR: + case R_TXCOUNT: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_minimac: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_minimac_memory_read(addr << 2, r); + + return r; +} + +static void +minimac_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistMinimacState *s = opaque; + + trace_milkymist_minimac_memory_read(addr, value); + + addr >>= 2; + switch (addr) { + case R_MDIO: + { + /* MDIO_DI is read only */ + int mdio_di = (s->regs[R_MDIO] & MDIO_DI); + s->regs[R_MDIO] = value; + if (mdio_di) { + s->regs[R_MDIO] |= mdio_di; + } else { + s->regs[R_MDIO] &= ~mdio_di; + } + + minimac_update_mdio(s); + } break; + case R_TXCOUNT: + s->regs[addr] = value; + if (value > 0) { + minimac_tx(s); + } + break; + case R_SETUP: + case R_STATE0: + case R_ADDR0: + case R_COUNT0: + case R_STATE1: + case R_ADDR1: + case R_COUNT1: + case R_STATE2: + case R_ADDR2: + case R_COUNT2: + case R_STATE3: + case R_ADDR3: + case R_COUNT3: + case R_TXADDR: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_minimac: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const minimac_read_fn[] = { + NULL, + NULL, + &minimac_read, +}; + +static CPUWriteMemoryFunc * const minimac_write_fn[] = { + NULL, + NULL, + &minimac_write, +}; + +static int minimac_can_rx(VLANClientState *nc) +{ + MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + + /* discard frames if nic is in reset */ + if (s->regs[R_SETUP] & SETUP_RX_RST) { + return 1; + } + + if (s->regs[R_STATE0] == STATE_LOADED) { + return 1; + } + if (s->regs[R_STATE1] == STATE_LOADED) { + return 1; + } + if (s->regs[R_STATE2] == STATE_LOADED) { + return 1; + } + if (s->regs[R_STATE3] == STATE_LOADED) { + return 1; + } + + return 0; +} + +static void minimac_cleanup(VLANClientState *nc) +{ + MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + + s->nic = NULL; +} + +static void milkymist_minimac_reset(DeviceState *d) +{ + MilkymistMinimacState *s = + container_of(d, MilkymistMinimacState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + for (i = 0; i < R_PHY_MAX; i++) { + s->phy_regs[i] = 0; + } + + /* defaults */ + s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */ + s->phy_regs[R_PHY_ID2] = 0x161a; +} + +static NetClientInfo net_milkymist_minimac_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = minimac_can_rx, + .receive = minimac_rx, + .cleanup = minimac_cleanup, +}; + +static int milkymist_minimac_init(SysBusDevice *dev) +{ + MilkymistMinimacState *s = FROM_SYSBUS(typeof(*s), dev); + int regs; + + sysbus_init_irq(dev, &s->rx_irq); + sysbus_init_irq(dev, &s->tx_irq); + + regs = cpu_register_io_memory(minimac_read_fn, minimac_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, regs); + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_milkymist_minimac_info, &s->conf, + dev->qdev.info->name, dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_minimac_mdio = { + .name = "milkymist_minimac_mdio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(last_clk, MilkymistMinimacMdioState), + VMSTATE_INT32(count, MilkymistMinimacMdioState), + VMSTATE_UINT32(data, MilkymistMinimacMdioState), + VMSTATE_UINT16(data_out, MilkymistMinimacMdioState), + VMSTATE_INT32(state, MilkymistMinimacMdioState), + VMSTATE_UINT8(phy_addr, MilkymistMinimacMdioState), + VMSTATE_UINT8(reg_addr, MilkymistMinimacMdioState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_milkymist_minimac = { + .name = "milkymist-minimac", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistMinimacState, R_MAX), + VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimacState, R_PHY_MAX), + VMSTATE_STRUCT(mdio, MilkymistMinimacState, 0, + vmstate_milkymist_minimac_mdio, MilkymistMinimacMdioState), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_minimac_info = { + .init = milkymist_minimac_init, + .qdev.name = "milkymist-minimac", + .qdev.size = sizeof(MilkymistMinimacState), + .qdev.vmsd = &vmstate_milkymist_minimac, + .qdev.reset = milkymist_minimac_reset, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(MilkymistMinimacState, conf), + DEFINE_PROP_STRING("phy_model", MilkymistMinimacState, phy_model), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void milkymist_minimac_register(void) +{ + sysbus_register_withprop(&milkymist_minimac_info); +} + +device_init(milkymist_minimac_register) diff --git a/trace-events b/trace-events index 7627595713..2becf85afd 100644 --- a/trace-events +++ b/trace-events @@ -306,3 +306,15 @@ disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x v # hw/milkymist-memcard.c disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" + +# hw/milkymist-minimac.c +disable milkymist_minimac_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_minimac_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_minimac_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" +disable milkymist_minimac_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" +disable milkymist_minimac_tx_frame(uint32_t length) "length %u" +disable milkymist_minimac_rx_frame(const void *buf, uint32_t length) "buf %p length %u" +disable milkymist_minimac_drop_rx_frame(const void *buf) "buf %p" +disable milkymist_minimac_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" +disable milkymist_minimac_pulse_irq_rx(void) "Pulse IRQ RX" +disable milkymist_minimac_pulse_irq_tx(void) "Pulse IRQ TX" From 5ee18b9c6843fa69da3c3ed92c57e01102614e34 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:36 +0100 Subject: [PATCH 084/386] lm32: add Milkymist PFPU support This patch adds support for Milkymist's Programmable FPU. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-pfpu.c | 536 ++++++++++++++++++++++++++++++++++++++++++++ trace-events | 6 + 3 files changed, 543 insertions(+) create mode 100644 hw/milkymist-pfpu.c diff --git a/Makefile.target b/Makefile.target index 6fd8a17116..0a87446f15 100644 --- a/Makefile.target +++ b/Makefile.target @@ -271,6 +271,7 @@ obj-lm32-y += milkymist-ac97.o obj-lm32-y += milkymist-hpdmc.o obj-lm32-y += milkymist-memcard.o obj-lm32-y += milkymist-minimac.o +obj-lm32-y += milkymist-pfpu.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c new file mode 100644 index 0000000000..4831e00b81 --- /dev/null +++ b/hw/milkymist-pfpu.c @@ -0,0 +1,536 @@ +/* + * QEMU model of the Milkymist programmable FPU. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/pfpu.pdf + * + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "qemu-log.h" +#include "qemu-error.h" +#include <math.h> + +/* #define TRACE_EXEC */ + +#ifdef TRACE_EXEC +# define D_EXEC(x) x +#else +# define D_EXEC(x) +#endif + +enum { + R_CTL = 0, + R_MESHBASE, + R_HMESHLAST, + R_VMESHLAST, + R_CODEPAGE, + R_VERTICES, + R_COLLISIONS, + R_STRAYWRITES, + R_LASTDMA, + R_PC, + R_DREGBASE, + R_CODEBASE, + R_MAX +}; + +enum { + CTL_START_BUSY = (1<<0), +}; + +enum { + OP_NOP = 0, + OP_FADD, + OP_FSUB, + OP_FMUL, + OP_FABS, + OP_F2I, + OP_I2F, + OP_VECTOUT, + OP_SIN, + OP_COS, + OP_ABOVE, + OP_EQUAL, + OP_COPY, + OP_IF, + OP_TSIGN, + OP_QUAKE, +}; + +enum { + GPR_X = 0, + GPR_Y = 1, + GPR_FLAGS = 2, +}; + +enum { + LATENCY_FADD = 5, + LATENCY_FSUB = 5, + LATENCY_FMUL = 7, + LATENCY_FABS = 2, + LATENCY_F2I = 2, + LATENCY_I2F = 3, + LATENCY_VECTOUT = 0, + LATENCY_SIN = 4, + LATENCY_COS = 4, + LATENCY_ABOVE = 2, + LATENCY_EQUAL = 2, + LATENCY_COPY = 2, + LATENCY_IF = 2, + LATENCY_TSIGN = 2, + LATENCY_QUAKE = 2, + MAX_LATENCY = 7 +}; + +#define GPR_BEGIN 0x100 +#define GPR_END 0x17f +#define MICROCODE_BEGIN 0x200 +#define MICROCODE_END 0x3ff +#define MICROCODE_WORDS 2048 + +#define REINTERPRET_CAST(type, val) (*((type *)&(val))) + +#ifdef TRACE_EXEC +static const char *opcode_to_str[] = { + "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT", + "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE", +}; +#endif + +struct MilkymistPFPUState { + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq irq; + + uint32_t regs[R_MAX]; + uint32_t gp_regs[128]; + uint32_t microcode[MICROCODE_WORDS]; + + int output_queue_pos; + uint32_t output_queue[MAX_LATENCY]; +}; +typedef struct MilkymistPFPUState MilkymistPFPUState; + +static inline target_phys_addr_t +get_dma_address(uint32_t base, uint32_t x, uint32_t y) +{ + return base + 8 * (128 * y + x); +} + +static inline void +output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos) +{ + s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val; +} + +static inline uint32_t +output_queue_remove(MilkymistPFPUState *s) +{ + return s->output_queue[s->output_queue_pos]; +} + +static inline void +output_queue_advance(MilkymistPFPUState *s) +{ + s->output_queue[s->output_queue_pos] = 0; + s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY; +} + +static int pfpu_decode_insn(MilkymistPFPUState *s) +{ + uint32_t pc = s->regs[R_PC]; + uint32_t insn = s->microcode[pc]; + uint32_t reg_a = (insn >> 18) & 0x7f; + uint32_t reg_b = (insn >> 11) & 0x7f; + uint32_t op = (insn >> 7) & 0xf; + uint32_t reg_d = insn & 0x7f; + uint32_t r; + int latency = 0; + + switch (op) { + case OP_NOP: + break; + case OP_FADD: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a + b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FADD; + D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FSUB: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a - b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FSUB; + D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FMUL: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = a * b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FMUL; + D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_FABS: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float t = fabsf(a); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_FABS; + D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r)); + } break; + case OP_F2I: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + int32_t t = a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_F2I; + D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r)); + } break; + case OP_I2F: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_I2F; + D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r)); + } break; + case OP_VECTOUT: + { + uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); + uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); + target_phys_addr_t dma_ptr = + get_dma_address(s->regs[R_MESHBASE], + s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); + cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4); + cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4); + s->regs[R_LASTDMA] = dma_ptr + 4; + D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr)); + trace_milkymist_pfpu_vectout(a, b, dma_ptr); + } break; + case OP_SIN: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = sinf(a * (1.0f / (M_PI * 4096.0f))); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_SIN; + D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r)); + } break; + case OP_COS: + { + int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); + float t = cosf(a * (1.0f / (M_PI * 4096.0f))); + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_COS; + D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r)); + } break; + case OP_ABOVE: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (a > b) ? 1.0f : 0.0f; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_ABOVE; + D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_EQUAL: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (a == b) ? 1.0f : 0.0f; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_EQUAL; + D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_COPY: + { + r = s->gp_regs[reg_a]; + latency = LATENCY_COPY; + D_EXEC(qemu_log("COPY")); + } break; + case OP_IF: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + uint32_t f = s->gp_regs[GPR_FLAGS]; + float t = (f != 0) ? a : b; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_IF; + D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r)); + } break; + case OP_TSIGN: + { + float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); + float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); + float t = (b < 0) ? -a : a; + r = REINTERPRET_CAST(uint32_t, t); + latency = LATENCY_TSIGN; + D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); + } break; + case OP_QUAKE: + { + uint32_t a = s->gp_regs[reg_a]; + r = 0x5f3759df - (a >> 1); + latency = LATENCY_QUAKE; + D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r)); + } break; + + default: + error_report("milkymist_pfpu: unknown opcode %d\n", op); + break; + } + + if (!reg_d) { + D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n", + s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, + s->regs[R_PC] + latency)); + } else { + D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n", + s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, + s->regs[R_PC] + latency, reg_d)); + } + + if (op == OP_VECTOUT) { + return 0; + } + + /* store output for this cycle */ + if (reg_d) { + uint32_t val = output_queue_remove(s); + D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val)); + s->gp_regs[reg_d] = val; + } + + output_queue_advance(s); + + /* store op output */ + if (op != OP_NOP) { + output_queue_insert(s, r, latency-1); + } + + /* advance PC */ + s->regs[R_PC]++; + + return 1; +}; + +static void pfpu_start(MilkymistPFPUState *s) +{ + int x, y; + int i; + + for (y = 0; y <= s->regs[R_VMESHLAST]; y++) { + for (x = 0; x <= s->regs[R_HMESHLAST]; x++) { + D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y)); + + /* set current position */ + s->gp_regs[GPR_X] = x; + s->gp_regs[GPR_Y] = y; + + /* run microcode on this position */ + i = 0; + while (pfpu_decode_insn(s)) { + /* decode at most MICROCODE_WORDS instructions */ + if (i++ >= MICROCODE_WORDS) { + error_report("milkymist_pfpu: too many instructions " + "executed in microcode. No VECTOUT?\n"); + break; + } + } + + /* reset pc for next run */ + s->regs[R_PC] = 0; + } + } + + s->regs[R_VERTICES] = x * y; + + trace_milkymist_pfpu_pulse_irq(); + qemu_irq_pulse(s->irq); +} + +static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) +{ + return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; +} + +static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistPFPUState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CTL: + case R_MESHBASE: + case R_HMESHLAST: + case R_VMESHLAST: + case R_CODEPAGE: + case R_VERTICES: + case R_COLLISIONS: + case R_STRAYWRITES: + case R_LASTDMA: + case R_PC: + case R_DREGBASE: + case R_CODEBASE: + r = s->regs[addr]; + break; + case GPR_BEGIN ... GPR_END: + r = s->gp_regs[addr - GPR_BEGIN]; + break; + case MICROCODE_BEGIN ... MICROCODE_END: + r = s->microcode[get_microcode_address(s, addr)]; + break; + + default: + error_report("milkymist_pfpu: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_pfpu_memory_read(addr << 2, r); + + return r; +} + +static void +pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistPFPUState *s = opaque; + + trace_milkymist_pfpu_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTL: + if (value & CTL_START_BUSY) { + pfpu_start(s); + } + break; + case R_MESHBASE: + case R_HMESHLAST: + case R_VMESHLAST: + case R_CODEPAGE: + case R_VERTICES: + case R_COLLISIONS: + case R_STRAYWRITES: + case R_LASTDMA: + case R_PC: + case R_DREGBASE: + case R_CODEBASE: + s->regs[addr] = value; + break; + case GPR_BEGIN ... GPR_END: + s->gp_regs[addr - GPR_BEGIN] = value; + break; + case MICROCODE_BEGIN ... MICROCODE_END: + s->microcode[get_microcode_address(s, addr)] = value; + break; + + default: + error_report("milkymist_pfpu: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const pfpu_read_fn[] = { + NULL, + NULL, + &pfpu_read, +}; + +static CPUWriteMemoryFunc * const pfpu_write_fn[] = { + NULL, + NULL, + &pfpu_write, +}; + +static void milkymist_pfpu_reset(DeviceState *d) +{ + MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + for (i = 0; i < 128; i++) { + s->gp_regs[i] = 0; + } + for (i = 0; i < MICROCODE_WORDS; i++) { + s->microcode[i] = 0; + } + s->output_queue_pos = 0; + for (i = 0; i < MAX_LATENCY; i++) { + s->output_queue[i] = 0; + } +} + +static int milkymist_pfpu_init(SysBusDevice *dev) +{ + MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev); + int pfpu_regs; + + sysbus_init_irq(dev, &s->irq); + + pfpu_regs = cpu_register_io_memory(pfpu_read_fn, pfpu_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, MICROCODE_END * 4, pfpu_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_pfpu = { + .name = "milkymist-pfpu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), + VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), + VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), + VMSTATE_INT32(output_queue_pos, MilkymistPFPUState), + VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_pfpu_info = { + .init = milkymist_pfpu_init, + .qdev.name = "milkymist-pfpu", + .qdev.size = sizeof(MilkymistPFPUState), + .qdev.vmsd = &vmstate_milkymist_pfpu, + .qdev.reset = milkymist_pfpu_reset, +}; + +static void milkymist_pfpu_register(void) +{ + sysbus_register_withprop(&milkymist_pfpu_info); +} + +device_init(milkymist_pfpu_register) diff --git a/trace-events b/trace-events index 2becf85afd..b3fa971d2d 100644 --- a/trace-events +++ b/trace-events @@ -318,3 +318,9 @@ disable milkymist_minimac_drop_rx_frame(const void *buf) "buf %p" disable milkymist_minimac_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" disable milkymist_minimac_pulse_irq_rx(void) "Pulse IRQ RX" disable milkymist_minimac_pulse_irq_tx(void) "Pulse IRQ TX" + +# hw/milkymist-pfpu.c +disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x" +disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ" From 87a381ec341bd0195db0531db10f29d603eff49a Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:37 +0100 Subject: [PATCH 085/386] lm32: add Milkymist SoftUSB support This patch adds support for Milkymist's SoftUSB core. This model differ from the real hardware in its functionality. The real hardware consits of a tiny freely programmable microcontroller which controls the USB ports. For simplicity reasons, this model emulates only keyboard and mouse input devices, eg. input events translates directly to the corresponding expected messages. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-softusb.c | 357 +++++++++++++++++++++++++++++++++++++++++ trace-events | 8 + 3 files changed, 366 insertions(+) create mode 100644 hw/milkymist-softusb.c diff --git a/Makefile.target b/Makefile.target index 0a87446f15..8924626c30 100644 --- a/Makefile.target +++ b/Makefile.target @@ -272,6 +272,7 @@ obj-lm32-y += milkymist-hpdmc.o obj-lm32-y += milkymist-memcard.o obj-lm32-y += milkymist-minimac.o obj-lm32-y += milkymist-pfpu.o +obj-lm32-y += milkymist-softusb.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c new file mode 100644 index 0000000000..1565260279 --- /dev/null +++ b/hw/milkymist-softusb.c @@ -0,0 +1,357 @@ +/* + * QEMU model of the Milkymist SoftUSB block. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * not available yet + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "console.h" +#include "usb.h" +#include "qemu-error.h" + +enum { + R_CTRL = 0, + R_MAX +}; + +enum { + CTRL_RESET = (1<<0), +}; + +#define COMLOC_DEBUG_PRODUCE 0x1000 +#define COMLOC_DEBUG_BASE 0x1001 +#define COMLOC_MEVT_PRODUCE 0x1101 +#define COMLOC_MEVT_BASE 0x1102 +#define COMLOC_KEVT_PRODUCE 0x1142 +#define COMLOC_KEVT_BASE 0x1143 + +struct MilkymistSoftUsbState { + SysBusDevice busdev; + USBBus usbbus; + USBPort usbport[2]; + USBDevice *usbdev; + + qemu_irq irq; + + /* device properties */ + uint32_t pmem_base; + uint32_t pmem_size; + uint32_t dmem_base; + uint32_t dmem_size; + + /* device registers */ + uint32_t regs[R_MAX]; + + /* mouse state */ + int mouse_dx; + int mouse_dy; + int mouse_dz; + uint8_t mouse_buttons_state; + + /* keyboard state */ + uint8_t kbd_usb_buffer[8]; +}; +typedef struct MilkymistSoftUsbState MilkymistSoftUsbState; + +static uint32_t softusb_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistSoftUsbState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CTRL: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_softusb: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_softusb_memory_read(addr << 2, r); + + return r; +} + +static void +softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistSoftUsbState *s = opaque; + + trace_milkymist_softusb_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTRL: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_softusb: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const softusb_read_fn[] = { + NULL, + NULL, + &softusb_read, +}; + +static CPUWriteMemoryFunc * const softusb_write_fn[] = { + NULL, + NULL, + &softusb_write, +}; + +static inline void softusb_read_dmem(MilkymistSoftUsbState *s, + uint32_t offset, uint8_t *buf, uint32_t len) +{ + if (offset + len >= s->dmem_size) { + error_report("milkymist_softusb: read dmem out of bounds " + "at offset 0x%x, len %d\n", offset, len); + return; + } + + cpu_physical_memory_read(s->dmem_base + offset, buf, len); +} + +static inline void softusb_write_dmem(MilkymistSoftUsbState *s, + uint32_t offset, uint8_t *buf, uint32_t len) +{ + if (offset + len >= s->dmem_size) { + error_report("milkymist_softusb: write dmem out of bounds " + "at offset 0x%x, len %d\n", offset, len); + return; + } + + cpu_physical_memory_write(s->dmem_base + offset, buf, len); +} + +static inline void softusb_read_pmem(MilkymistSoftUsbState *s, + uint32_t offset, uint8_t *buf, uint32_t len) +{ + if (offset + len >= s->pmem_size) { + error_report("milkymist_softusb: read pmem out of bounds " + "at offset 0x%x, len %d\n", offset, len); + return; + } + + cpu_physical_memory_read(s->pmem_base + offset, buf, len); +} + +static inline void softusb_write_pmem(MilkymistSoftUsbState *s, + uint32_t offset, uint8_t *buf, uint32_t len) +{ + if (offset + len >= s->pmem_size) { + error_report("milkymist_softusb: write pmem out of bounds " + "at offset 0x%x, len %d\n", offset, len); + return; + } + + cpu_physical_memory_write(s->pmem_base + offset, buf, len); +} + +static void softusb_mouse_changed(MilkymistSoftUsbState *s) +{ + uint8_t m; + uint8_t buf[4]; + + buf[0] = s->mouse_buttons_state; + buf[1] = s->mouse_dx; + buf[2] = s->mouse_dy; + buf[3] = s->mouse_dz; + + softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); + trace_milkymist_softusb_mevt(m); + softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4); + m = (m + 1) & 0xf; + softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); + + trace_milkymist_softusb_pulse_irq(); + qemu_irq_pulse(s->irq); +} + +static void softusb_kbd_changed(MilkymistSoftUsbState *s) +{ + uint8_t m; + + softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); + trace_milkymist_softusb_kevt(m); + softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8); + m = (m + 1) & 0x7; + softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); + + trace_milkymist_softusb_pulse_irq(); + qemu_irq_pulse(s->irq); +} + +static void softusb_mouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + MilkymistSoftUsbState *s = opaque; + + /* if device is in reset, do nothing */ + if (s->regs[R_CTRL] & CTRL_RESET) { + return; + } + + trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state); + + s->mouse_dx = dx; + s->mouse_dy = dy; + s->mouse_dz = dz; + s->mouse_buttons_state = buttons_state; + + softusb_mouse_changed(s); +} + +static void softusb_usbdev_datain(void *opaque) +{ + MilkymistSoftUsbState *s = opaque; + + USBPacket p; + + p.pid = USB_TOKEN_IN; + p.devep = 1; + p.data = s->kbd_usb_buffer; + p.len = sizeof(s->kbd_usb_buffer); + s->usbdev->info->handle_data(s->usbdev, &p); + + softusb_kbd_changed(s); +} + +static void softusb_attach(USBPort *port) +{ +} + +static USBPortOps softusb_ops = { + .attach = softusb_attach, +}; + +static void milkymist_softusb_reset(DeviceState *d) +{ + MilkymistSoftUsbState *s = + container_of(d, MilkymistSoftUsbState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + s->mouse_dx = 0; + s->mouse_dy = 0; + s->mouse_dz = 0; + s->mouse_buttons_state = 0; + memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer)); + + /* defaults */ + s->regs[R_CTRL] = CTRL_RESET; +} + +static int milkymist_softusb_init(SysBusDevice *dev) +{ + MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev); + int softusb_regs; + ram_addr_t pmem_ram; + ram_addr_t dmem_ram; + + sysbus_init_irq(dev, &s->irq); + + softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, softusb_regs); + + /* register pmem and dmem */ + pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size); + cpu_register_physical_memory(s->pmem_base, s->pmem_size, + pmem_ram | IO_MEM_RAM); + dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size); + cpu_register_physical_memory(s->dmem_base, s->dmem_size, + dmem_ram | IO_MEM_RAM); + + qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse"); + + /* create our usb bus */ + usb_bus_new(&s->usbbus, NULL); + + /* our two ports */ + usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops, + USB_SPEED_MASK_LOW); + usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops, + USB_SPEED_MASK_LOW); + + /* and finally create an usb keyboard */ + s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd"); + usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain); + s->usbdev->info->handle_reset(s->usbdev); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_softusb = { + .name = "milkymist-softusb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), + VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState), + VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState), + VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState), + VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState), + VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_softusb_info = { + .init = milkymist_softusb_init, + .qdev.name = "milkymist-softusb", + .qdev.size = sizeof(MilkymistSoftUsbState), + .qdev.vmsd = &vmstate_milkymist_softusb, + .qdev.reset = milkymist_softusb_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32( + "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000 + ), + DEFINE_PROP_UINT32( + "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000 + ), + DEFINE_PROP_UINT32( + "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000 + ), + DEFINE_PROP_UINT32( + "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000 + ), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void milkymist_softusb_register(void) +{ + sysbus_register_withprop(&milkymist_softusb_info); +} + +device_init(milkymist_softusb_register) diff --git a/trace-events b/trace-events index b3fa971d2d..74cce75eec 100644 --- a/trace-events +++ b/trace-events @@ -324,3 +324,11 @@ disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x val disable milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" disable milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x" disable milkymist_pfpu_pulse_irq(void) "Pulse IRQ" + +# hw/milkymist-softusb.c +disable milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_softusb_mevt(uint8_t m) "m %d" +disable milkymist_softusb_kevt(uint8_t m) "m %d" +disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x" +disable milkymist_softusb_pulse_irq(void) "Pulse IRQ" From 9683242448541b6fb5511421af3d8f0c6cd19477 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:38 +0100 Subject: [PATCH 086/386] lm32: add Milkymist System Controller support This patch adds support for Milkymist's System Controller core. The model has the following features: - support for shutting down and restarting the board - provide two timers and GPIO - provide registers for system identification and reading the boards capabilities Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-sysctl.c | 330 ++++++++++++++++++++++++++++++++++++++++++ trace-events | 11 ++ 3 files changed, 342 insertions(+) create mode 100644 hw/milkymist-sysctl.c diff --git a/Makefile.target b/Makefile.target index 8924626c30..c1175652f9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -273,6 +273,7 @@ obj-lm32-y += milkymist-memcard.o obj-lm32-y += milkymist-minimac.o obj-lm32-y += milkymist-pfpu.o obj-lm32-y += milkymist-softusb.o +obj-lm32-y += milkymist-sysctl.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c new file mode 100644 index 0000000000..eaea543bf3 --- /dev/null +++ b/hw/milkymist-sysctl.c @@ -0,0 +1,330 @@ +/* + * QEMU model of the Milkymist System Controller. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/sysctl.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "sysemu.h" +#include "trace.h" +#include "qemu-timer.h" +#include "qemu-error.h" + +enum { + CTRL_ENABLE = (1<<0), + CTRL_AUTORESTART = (1<<1), +}; + +enum { + ICAP_READY = (1<<0), +}; + +enum { + R_GPIO_IN = 0, + R_GPIO_OUT, + R_GPIO_INTEN, + R_RESERVED0, + R_TIMER0_CONTROL, + R_TIMER0_COMPARE, + R_TIMER0_COUNTER, + R_RESERVED1, + R_TIMER1_CONTROL, + R_TIMER1_COMPARE, + R_TIMER1_COUNTER, + R_RESERVED2, + R_RESERVED3, + R_ICAP, + R_CAPABILITIES, + R_SYSTEM_ID, + R_MAX +}; + +struct MilkymistSysctlState { + SysBusDevice busdev; + + QEMUBH *bh0; + QEMUBH *bh1; + ptimer_state *ptimer0; + ptimer_state *ptimer1; + + uint32_t freq_hz; + uint32_t capabilities; + uint32_t systemid; + uint32_t strappings; + + uint32_t regs[R_MAX]; + + qemu_irq gpio_irq; + qemu_irq timer0_irq; + qemu_irq timer1_irq; +}; +typedef struct MilkymistSysctlState MilkymistSysctlState; + +static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value) +{ + trace_milkymist_sysctl_icap_write(value); + switch (value & 0xffff) { + case 0x000e: + qemu_system_shutdown_request(); + break; + } +} + +static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistSysctlState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_TIMER0_COUNTER: + r = (uint32_t)ptimer_get_count(s->ptimer0); + /* milkymist timer counts up */ + r = s->regs[R_TIMER0_COMPARE] - r; + break; + case R_TIMER1_COUNTER: + r = (uint32_t)ptimer_get_count(s->ptimer1); + /* milkymist timer counts up */ + r = s->regs[R_TIMER1_COMPARE] - r; + break; + case R_GPIO_IN: + case R_GPIO_OUT: + case R_GPIO_INTEN: + case R_TIMER0_CONTROL: + case R_TIMER0_COMPARE: + case R_TIMER1_CONTROL: + case R_TIMER1_COMPARE: + case R_ICAP: + case R_CAPABILITIES: + case R_SYSTEM_ID: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_sysctl: read access to unkown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_sysctl_memory_read(addr << 2, r); + + return r; +} + +static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistSysctlState *s = opaque; + + trace_milkymist_sysctl_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_GPIO_OUT: + case R_GPIO_INTEN: + case R_TIMER0_COUNTER: + if (value > s->regs[R_TIMER0_COUNTER]) { + value = s->regs[R_TIMER0_COUNTER]; + error_report("milkymist_sysctl: timer0: trying to write a " + "value greater than the limit. Clipping."); + } + /* milkymist timer counts up */ + value = s->regs[R_TIMER0_COUNTER] - value; + ptimer_set_count(s->ptimer0, value); + break; + case R_TIMER1_COUNTER: + if (value > s->regs[R_TIMER1_COUNTER]) { + value = s->regs[R_TIMER1_COUNTER]; + error_report("milkymist_sysctl: timer1: trying to write a " + "value greater than the limit. Clipping."); + } + /* milkymist timer counts up */ + value = s->regs[R_TIMER1_COUNTER] - value; + ptimer_set_count(s->ptimer1, value); + break; + case R_TIMER0_COMPARE: + ptimer_set_limit(s->ptimer0, value, 0); + s->regs[addr] = value; + break; + case R_TIMER1_COMPARE: + ptimer_set_limit(s->ptimer1, value, 0); + s->regs[addr] = value; + break; + case R_TIMER0_CONTROL: + s->regs[addr] = value; + if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) { + trace_milkymist_sysctl_start_timer1(); + ptimer_run(s->ptimer0, 0); + } else { + trace_milkymist_sysctl_stop_timer1(); + ptimer_stop(s->ptimer0); + } + break; + case R_TIMER1_CONTROL: + s->regs[addr] = value; + if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) { + trace_milkymist_sysctl_start_timer1(); + ptimer_run(s->ptimer1, 0); + } else { + trace_milkymist_sysctl_stop_timer1(); + ptimer_stop(s->ptimer1); + } + break; + case R_ICAP: + sysctl_icap_write(s, value); + break; + case R_SYSTEM_ID: + qemu_system_reset_request(); + break; + + case R_GPIO_IN: + case R_CAPABILITIES: + error_report("milkymist_sysctl: write to read-only register 0x" + TARGET_FMT_plx, addr << 2); + break; + + default: + error_report("milkymist_sysctl: write access to unkown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const sysctl_read_fn[] = { + NULL, + NULL, + &sysctl_read, +}; + +static CPUWriteMemoryFunc * const sysctl_write_fn[] = { + NULL, + NULL, + &sysctl_write, +}; + +static void timer0_hit(void *opaque) +{ + MilkymistSysctlState *s = opaque; + + if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) { + s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE; + trace_milkymist_sysctl_stop_timer0(); + ptimer_stop(s->ptimer0); + } + + trace_milkymist_sysctl_pulse_irq_timer0(); + qemu_irq_pulse(s->timer0_irq); +} + +static void timer1_hit(void *opaque) +{ + MilkymistSysctlState *s = opaque; + + if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) { + s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE; + trace_milkymist_sysctl_stop_timer1(); + ptimer_stop(s->ptimer1); + } + + trace_milkymist_sysctl_pulse_irq_timer1(); + qemu_irq_pulse(s->timer1_irq); +} + +static void milkymist_sysctl_reset(DeviceState *d) +{ + MilkymistSysctlState *s = + container_of(d, MilkymistSysctlState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + ptimer_stop(s->ptimer0); + ptimer_stop(s->ptimer1); + + /* defaults */ + s->regs[R_ICAP] = ICAP_READY; + s->regs[R_SYSTEM_ID] = s->systemid; + s->regs[R_CAPABILITIES] = s->capabilities; + s->regs[R_GPIO_IN] = s->strappings; +} + +static int milkymist_sysctl_init(SysBusDevice *dev) +{ + MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev); + int sysctl_regs; + + sysbus_init_irq(dev, &s->gpio_irq); + sysbus_init_irq(dev, &s->timer0_irq); + sysbus_init_irq(dev, &s->timer1_irq); + + s->bh0 = qemu_bh_new(timer0_hit, s); + s->bh1 = qemu_bh_new(timer1_hit, s); + s->ptimer0 = ptimer_init(s->bh0); + s->ptimer1 = ptimer_init(s->bh1); + ptimer_set_freq(s->ptimer0, s->freq_hz); + ptimer_set_freq(s->ptimer1, s->freq_hz); + + sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_sysctl = { + .name = "milkymist-sysctl", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), + VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), + VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_sysctl_info = { + .init = milkymist_sysctl_init, + .qdev.name = "milkymist-sysctl", + .qdev.size = sizeof(MilkymistSysctlState), + .qdev.vmsd = &vmstate_milkymist_sysctl, + .qdev.reset = milkymist_sysctl_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, + freq_hz, 80000000), + DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, + capabilities, 0x00000000), + DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, + systemid, 0x10014d31), + DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, + strappings, 0x00000001), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void milkymist_sysctl_register(void) +{ + sysbus_register_withprop(&milkymist_sysctl_info); +} + +device_init(milkymist_sysctl_register) diff --git a/trace-events b/trace-events index 74cce75eec..f6fc40397b 100644 --- a/trace-events +++ b/trace-events @@ -332,3 +332,14 @@ disable milkymist_softusb_mevt(uint8_t m) "m %d" disable milkymist_softusb_kevt(uint8_t m) "m %d" disable milkymist_softusb_mouse_event(int dx, int dy, int dz, int bs) "dx %d dy %d dz %d bs %02x" disable milkymist_softusb_pulse_irq(void) "Pulse IRQ" + +# hw/milkymist-sysctl.c +disable milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_sysctl_icap_write(uint32_t value) "value %08x" +disable milkymist_sysctl_start_timer0(void) "Start timer0" +disable milkymist_sysctl_stop_timer0(void) "Stop timer0" +disable milkymist_sysctl_start_timer1(void) "Start timer1" +disable milkymist_sysctl_stop_timer1(void) "Stop timer1" +disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0" +disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1" From 20ff075bb3340c5278a0da38ad1f4d602565aa06 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:39 +0100 Subject: [PATCH 087/386] configure: add opengl detection This patch introduce a new config option CONFIG_OPENGL. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- configure | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/configure b/configure index 2e7b4f8718..faaed60540 100755 --- a/configure +++ b/configure @@ -720,6 +720,10 @@ for opt do ;; --enable-vhost-net) vhost_net="yes" ;; + --disable-opengl) opengl="no" + ;; + --enable-opengl) opengl="yes" + ;; --*dir) ;; --disable-rbd) rbd="no" @@ -1944,6 +1948,27 @@ EOF fi fi +########################################## +# opengl probe, used by milkymist-tmu2 +if test "$opengl" != "no" ; then + opengl_libs="-lGL" + cat > $TMPC << EOF +#include <X11/Xlib.h> +#include <GL/gl.h> +#include <GL/glx.h> +int main(void) { GL_VERSION; return 0; } +EOF + if compile_prog "" "-lGL" ; then + opengl=yes + libs_softmmu="$opengl_libs $libs_softmmu" + else + if test "$opengl" = "yes" ; then + feature_not_found "opengl" + fi + opengl=no + fi +fi + # # Check for xxxat() functions when we are building linux-user # emulator. This is done because older glibc versions don't @@ -2582,6 +2607,7 @@ echo "spice support $spice" echo "rbd support $rbd" echo "xfsctl support $xfs" echo "nss used $smartcard_nss" +echo "OpenGL support $opengl" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -2872,6 +2898,10 @@ if test "$smartcard_nss" = "yes" ; then echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak fi +if test "$opengl" = "yes" ; then + echo "CONFIG_OPENGL=y" >> $config_host_mak +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak From 0670dadd64be8c06d176e797bfc1943ecbce6eb2 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:40 +0100 Subject: [PATCH 088/386] lm32: add Milkymist TMU2 support This patch adds support for Milkymist's texture mapping unit. For fast computation this model needs hardware accelerated 3D graphics support (OpenGL). There is no graphical output, all computations belong to internal framebuffers only. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-tmu2.c | 481 ++++++++++++++++++++++++++++++++++++++++++++ trace-events | 6 + 3 files changed, 488 insertions(+) create mode 100644 hw/milkymist-tmu2.c diff --git a/Makefile.target b/Makefile.target index c1175652f9..6581519064 100644 --- a/Makefile.target +++ b/Makefile.target @@ -274,6 +274,7 @@ obj-lm32-y += milkymist-minimac.o obj-lm32-y += milkymist-pfpu.o obj-lm32-y += milkymist-softusb.o obj-lm32-y += milkymist-sysctl.o +obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c new file mode 100644 index 0000000000..9cebe3173b --- /dev/null +++ b/hw/milkymist-tmu2.c @@ -0,0 +1,481 @@ +/* + * QEMU model of the Milkymist texture mapping unit. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * Copyright (c) 2010 Sebastien Bourdeauducq + * <sebastien.bourdeauducq@lekernel.net> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/tmu2.pdf + * + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "qemu-error.h" + +#include <X11/Xlib.h> +#include <GL/gl.h> +#include <GL/glx.h> + +enum { + R_CTL = 0, + R_HMESHLAST, + R_VMESHLAST, + R_BRIGHTNESS, + R_CHROMAKEY, + R_VERTICESADDR, + R_TEXFBUF, + R_TEXHRES, + R_TEXVRES, + R_TEXHMASK, + R_TEXVMASK, + R_DSTFBUF, + R_DSTHRES, + R_DSTVRES, + R_DSTHOFFSET, + R_DSTVOFFSET, + R_DSTSQUAREW, + R_DSTSQUAREH, + R_ALPHA, + R_MAX +}; + +enum { + CTL_START_BUSY = (1<<0), + CTL_CHROMAKEY = (1<<1), +}; + +enum { + MAX_BRIGHTNESS = 63, + MAX_ALPHA = 63, +}; + +enum { + MESH_MAXSIZE = 128, +}; + +struct vertex { + int x; + int y; +} __attribute__((packed)); + +struct MilkymistTMU2State { + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq irq; + + uint32_t regs[R_MAX]; + + Display *dpy; + GLXFBConfig glx_fb_config; + GLXContext glx_context; +}; +typedef struct MilkymistTMU2State MilkymistTMU2State; + +static const int glx_fbconfig_attr[] = { + GLX_GREEN_SIZE, 5, + GLX_GREEN_SIZE, 6, + GLX_BLUE_SIZE, 5, + None +}; + +static int tmu2_glx_init(MilkymistTMU2State *s) +{ + GLXFBConfig *configs; + int nelements; + + s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */ + if (s->dpy == NULL) { + return 1; + } + + configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements); + if (configs == NULL) { + return 1; + } + + s->glx_fb_config = *configs; + XFree(configs); + + /* FIXME: call glXDestroyContext() */ + s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config, + GLX_RGBA_TYPE, NULL, 1); + if (s->glx_context == NULL) { + return 1; + } + + return 0; +} + +static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres, + int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh) +{ + int x, y; + int x0, y0, x1, y1; + int u0, v0, u1, v1, u2, v2, u3, v3; + double xscale = 1.0 / ((double)(64 * texhres)); + double yscale = 1.0 / ((double)(64 * texvres)); + + glLoadIdentity(); + glTranslatef(ho, vo, 0); + glEnable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + + for (y = 0; y < vmeshlast; y++) { + y0 = y * sh; + y1 = y0 + sh; + for (x = 0; x < hmeshlast; x++) { + x0 = x * sw; + x1 = x0 + sw; + + u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x); + v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y); + u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x); + v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y); + u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x); + v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y); + u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x); + v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y); + + glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale); + glVertex3i(x0, y0, 0); + glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale); + glVertex3i(x1, y0, 0); + glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale); + glVertex3i(x1, y1, 0); + glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale); + glVertex3i(x0, y1, 0); + } + } + + glEnd(); +} + +static void tmu2_start(MilkymistTMU2State *s) +{ + int pbuffer_attrib[6] = { + GLX_PBUFFER_WIDTH, + 0, + GLX_PBUFFER_HEIGHT, + 0, + GLX_PRESERVED_CONTENTS, + True + }; + + GLXPbuffer pbuffer; + GLuint texture; + void *fb; + target_phys_addr_t fb_len; + void *mesh; + target_phys_addr_t mesh_len; + float m; + + trace_milkymist_tmu2_start(); + + /* Create and set up a suitable OpenGL context */ + pbuffer_attrib[1] = s->regs[R_DSTHRES]; + pbuffer_attrib[3] = s->regs[R_DSTVRES]; + pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib); + glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context); + + /* Fixup endianness. TODO: would it work on BE hosts? */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + glPixelStorei(GL_PACK_SWAP_BYTES, 1); + + /* Row alignment */ + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + glPixelStorei(GL_PACK_ALIGNMENT, 2); + + /* Read the QEMU source framebuffer into an OpenGL texture */ + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES]; + fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0); + if (fb == NULL) { + glDeleteTextures(1, &texture); + glXMakeContextCurrent(s->dpy, None, None, NULL); + glXDestroyPbuffer(s->dpy, pbuffer); + return; + } + glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES], + 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb); + cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); + + /* Set up texturing options */ + /* WARNING: + * Many cases of TMU2 masking are not supported by OpenGL. + * We only implement the most common ones: + * - full bilinear filtering vs. nearest texel + * - texture clamping vs. texture wrapping + */ + if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + } + if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + /* Translucency and decay */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f; + glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f); + + /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */ + fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; + fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0); + if (fb == NULL) { + glDeleteTextures(1, &texture); + glXMakeContextCurrent(s->dpy, None, None, NULL); + glXDestroyPbuffer(s->dpy, pbuffer); + return; + } + + glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, fb); + cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); + glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + + /* Map the texture */ + mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex); + mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0); + if (mesh == NULL) { + glDeleteTextures(1, &texture); + glXMakeContextCurrent(s->dpy, None, None, NULL); + glXDestroyPbuffer(s->dpy, pbuffer); + return; + } + + tmu2_gl_map((struct vertex *)mesh, + s->regs[R_TEXHRES], s->regs[R_TEXVRES], + s->regs[R_HMESHLAST], s->regs[R_VMESHLAST], + s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET], + s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]); + cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len); + + /* Write back the OpenGL framebuffer to the QEMU framebuffer */ + fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; + fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1); + if (fb == NULL) { + glDeleteTextures(1, &texture); + glXMakeContextCurrent(s->dpy, None, None, NULL); + glXDestroyPbuffer(s->dpy, pbuffer); + return; + } + + glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, fb); + cpu_physical_memory_unmap(fb, fb_len, 1, fb_len); + + /* Free OpenGL allocs */ + glDeleteTextures(1, &texture); + glXMakeContextCurrent(s->dpy, None, None, NULL); + glXDestroyPbuffer(s->dpy, pbuffer); + + s->regs[R_CTL] &= ~CTL_START_BUSY; + + trace_milkymist_tmu2_pulse_irq(); + qemu_irq_pulse(s->irq); +} + +static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistTMU2State *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CTL: + case R_HMESHLAST: + case R_VMESHLAST: + case R_BRIGHTNESS: + case R_CHROMAKEY: + case R_VERTICESADDR: + case R_TEXFBUF: + case R_TEXHRES: + case R_TEXVRES: + case R_TEXHMASK: + case R_TEXVMASK: + case R_DSTFBUF: + case R_DSTHRES: + case R_DSTVRES: + case R_DSTHOFFSET: + case R_DSTVOFFSET: + case R_DSTSQUAREW: + case R_DSTSQUAREH: + case R_ALPHA: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_tmu2: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_tmu2_memory_read(addr << 2, r); + + return r; +} + +static void tmu2_check_registers(MilkymistTMU2State *s) +{ + if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) { + error_report("milkymist_tmu2: max brightness is %d\n", MAX_BRIGHTNESS); + } + + if (s->regs[R_ALPHA] > MAX_ALPHA) { + error_report("milkymist_tmu2: max alpha is %d\n", MAX_ALPHA); + } + + if (s->regs[R_VERTICESADDR] & 0x07) { + error_report("milkymist_tmu2: vertex mesh address has to be 64-bit " + "aligned\n"); + } + + if (s->regs[R_TEXFBUF] & 0x01) { + error_report("milkymist_tmu2: texture buffer address has to be " + "16-bit aligned\n"); + } +} + +static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistTMU2State *s = opaque; + + trace_milkymist_tmu2_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTL: + s->regs[addr] = value; + if (value & CTL_START_BUSY) { + tmu2_start(s); + } + break; + case R_BRIGHTNESS: + case R_HMESHLAST: + case R_VMESHLAST: + case R_CHROMAKEY: + case R_VERTICESADDR: + case R_TEXFBUF: + case R_TEXHRES: + case R_TEXVRES: + case R_TEXHMASK: + case R_TEXVMASK: + case R_DSTFBUF: + case R_DSTHRES: + case R_DSTVRES: + case R_DSTHOFFSET: + case R_DSTVOFFSET: + case R_DSTSQUAREW: + case R_DSTSQUAREH: + case R_ALPHA: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_tmu2: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + tmu2_check_registers(s); +} + +static CPUReadMemoryFunc * const tmu2_read_fn[] = { + NULL, + NULL, + &tmu2_read, +}; + +static CPUWriteMemoryFunc * const tmu2_write_fn[] = { + NULL, + NULL, + &tmu2_write, +}; + +static void milkymist_tmu2_reset(DeviceState *d) +{ + MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } +} + +static int milkymist_tmu2_init(SysBusDevice *dev) +{ + MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev); + int tmu2_regs; + + if (tmu2_glx_init(s)) { + return 1; + } + + sysbus_init_irq(dev, &s->irq); + + tmu2_regs = cpu_register_io_memory(tmu2_read_fn, tmu2_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, tmu2_regs); + + return 0; +} + +static const VMStateDescription vmstate_milkymist_tmu2 = { + .name = "milkymist-tmu2", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_tmu2_info = { + .init = milkymist_tmu2_init, + .qdev.name = "milkymist-tmu2", + .qdev.size = sizeof(MilkymistTMU2State), + .qdev.vmsd = &vmstate_milkymist_tmu2, + .qdev.reset = milkymist_tmu2_reset, +}; + +static void milkymist_tmu2_register(void) +{ + sysbus_register_withprop(&milkymist_tmu2_info); +} + +device_init(milkymist_tmu2_register) diff --git a/trace-events b/trace-events index f6fc40397b..3a88adfdad 100644 --- a/trace-events +++ b/trace-events @@ -343,3 +343,9 @@ disable milkymist_sysctl_start_timer1(void) "Start timer1" disable milkymist_sysctl_stop_timer1(void) "Stop timer1" disable milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0" disable milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1" + +# hw/milkymist-tmu2.c +disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_tmu2_start(void) "Start TMU" +disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ" From 883de16b464554e195fe7e20daaa9525cfeaf3a2 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:41 +0100 Subject: [PATCH 089/386] lm32: add Milkymist UART support This patch adds support for Milkymist's simple UART. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + hw/milkymist-uart.c | 180 ++++++++++++++++++++++++++++++++++++++++++++ trace-events | 6 ++ 3 files changed, 187 insertions(+) create mode 100644 hw/milkymist-uart.c diff --git a/Makefile.target b/Makefile.target index 6581519064..c009117e47 100644 --- a/Makefile.target +++ b/Makefile.target @@ -275,6 +275,7 @@ obj-lm32-y += milkymist-pfpu.o obj-lm32-y += milkymist-softusb.o obj-lm32-y += milkymist-sysctl.o obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o +obj-lm32-y += milkymist-uart.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c new file mode 100644 index 0000000000..56c90da0b6 --- /dev/null +++ b/hw/milkymist-uart.c @@ -0,0 +1,180 @@ +/* + * QEMU model of the Milkymist UART block. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/uart.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "qemu-char.h" +#include "qemu-error.h" + +enum { + R_RXTX = 0, + R_DIV, + R_MAX +}; + +struct MilkymistUartState { + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq rx_irq; + qemu_irq tx_irq; + + uint32_t regs[R_MAX]; +}; +typedef struct MilkymistUartState MilkymistUartState; + +static uint32_t uart_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistUartState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_RXTX: + case R_DIV: + r = s->regs[addr]; + break; + + default: + error_report("milkymist_uart: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_uart_memory_read(addr << 2, r); + + return r; +} + +static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistUartState *s = opaque; + unsigned char ch = value; + + trace_milkymist_uart_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_RXTX: + if (s->chr) { + qemu_chr_write(s->chr, &ch, 1); + } + trace_milkymist_uart_pulse_irq_tx(); + qemu_irq_pulse(s->tx_irq); + break; + case R_DIV: + s->regs[addr] = value; + break; + + default: + error_report("milkymist_uart: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const uart_read_fn[] = { + NULL, + NULL, + &uart_read, +}; + +static CPUWriteMemoryFunc * const uart_write_fn[] = { + NULL, + NULL, + &uart_write, +}; + +static void uart_rx(void *opaque, const uint8_t *buf, int size) +{ + MilkymistUartState *s = opaque; + + s->regs[R_RXTX] = *buf; + trace_milkymist_uart_pulse_irq_rx(); + qemu_irq_pulse(s->rx_irq); +} + +static int uart_can_rx(void *opaque) +{ + return 1; +} + +static void uart_event(void *opaque, int event) +{ +} + +static void milkymist_uart_reset(DeviceState *d) +{ + MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } +} + +static int milkymist_uart_init(SysBusDevice *dev) +{ + MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); + int uart_regs; + + sysbus_init_irq(dev, &s->rx_irq); + sysbus_init_irq(dev, &s->tx_irq); + + uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, uart_regs); + + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) { + qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); + } + + return 0; +} + +static const VMStateDescription vmstate_milkymist_uart = { + .name = "milkymist-uart", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_uart_info = { + .init = milkymist_uart_init, + .qdev.name = "milkymist-uart", + .qdev.size = sizeof(MilkymistUartState), + .qdev.vmsd = &vmstate_milkymist_uart, + .qdev.reset = milkymist_uart_reset, +}; + +static void milkymist_uart_register(void) +{ + sysbus_register_withprop(&milkymist_uart_info); +} + +device_init(milkymist_uart_register) diff --git a/trace-events b/trace-events index 3a88adfdad..55f3de532a 100644 --- a/trace-events +++ b/trace-events @@ -349,3 +349,9 @@ disable milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x val disable milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" disable milkymist_tmu2_start(void) "Start TMU" disable milkymist_tmu2_pulse_irq(void) "Pulse IRQ" + +# hw/milkymist-uart.c +disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX" +disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX" From d23948b15a9920fb7f6374b55a6db1ecff81f3ee Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:42 +0100 Subject: [PATCH 090/386] lm32: add Milkymist VGAFB support This patch adds support for Milkymist's VGA framebuffer. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 2 + hw/milkymist-vgafb.c | 318 ++++++++++++++++++++++++++++++++++ hw/milkymist-vgafb_template.h | 74 ++++++++ trace-events | 4 + 4 files changed, 398 insertions(+) create mode 100644 hw/milkymist-vgafb.c create mode 100644 hw/milkymist-vgafb_template.h diff --git a/Makefile.target b/Makefile.target index c009117e47..2a65e15be9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -276,6 +276,8 @@ obj-lm32-y += milkymist-softusb.o obj-lm32-y += milkymist-sysctl.o obj-lm32-$(CONFIG_OPENGL) += milkymist-tmu2.o obj-lm32-y += milkymist-uart.o +obj-lm32-y += milkymist-vgafb.o +obj-lm32-y += framebuffer.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c new file mode 100644 index 0000000000..8922731511 --- /dev/null +++ b/hw/milkymist-vgafb.c @@ -0,0 +1,318 @@ + +/* + * QEMU model of the Milkymist VGA framebuffer. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + * + * Specification available at: + * http://www.milkymist.org/socdoc/vgafb.pdf + */ + +#include "hw.h" +#include "sysbus.h" +#include "trace.h" +#include "console.h" +#include "framebuffer.h" +#include "pixel_ops.h" +#include "qemu-error.h" + +#define BITS 8 +#include "milkymist-vgafb_template.h" +#define BITS 15 +#include "milkymist-vgafb_template.h" +#define BITS 16 +#include "milkymist-vgafb_template.h" +#define BITS 24 +#include "milkymist-vgafb_template.h" +#define BITS 32 +#include "milkymist-vgafb_template.h" + +enum { + R_CTRL = 0, + R_HRES, + R_HSYNC_START, + R_HSYNC_END, + R_HSCAN, + R_VRES, + R_VSYNC_START, + R_VSYNC_END, + R_VSCAN, + R_BASEADDRESS, + R_BASEADDRESS_ACT, + R_BURST_COUNT, + R_SOURCE_CLOCK, + R_MAX +}; + +enum { + CTRL_RESET = (1<<0), +}; + +struct MilkymistVgafbState { + SysBusDevice busdev; + DisplayState *ds; + + int invalidate; + uint32_t fb_offset; + uint32_t fb_mask; + + uint32_t regs[R_MAX]; +}; +typedef struct MilkymistVgafbState MilkymistVgafbState; + +static int vgafb_enabled(MilkymistVgafbState *s) +{ + return !(s->regs[R_CTRL] & CTRL_RESET); +} + +static void vgafb_update_display(void *opaque) +{ + MilkymistVgafbState *s = opaque; + int first = 0; + int last = 0; + drawfn fn; + + if (!vgafb_enabled(s)) { + return; + } + + int dest_width = s->regs[R_HRES]; + + switch (ds_get_bits_per_pixel(s->ds)) { + case 0: + return; + case 8: + fn = draw_line_8; + break; + case 15: + fn = draw_line_15; + dest_width *= 2; + break; + case 16: + fn = draw_line_16; + dest_width *= 2; + break; + case 24: + fn = draw_line_24; + dest_width *= 3; + break; + case 32: + fn = draw_line_32; + dest_width *= 4; + break; + default: + hw_error("milkymist_vgafb: bad color depth\n"); + break; + } + + framebuffer_update_display(s->ds, + s->regs[R_BASEADDRESS] + s->fb_offset, + s->regs[R_HRES], + s->regs[R_VRES], + s->regs[R_HRES] * 2, + dest_width, + 0, + s->invalidate, + fn, + NULL, + &first, &last); + + if (first >= 0) { + dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1); + } + s->invalidate = 0; +} + +static void vgafb_invalidate_display(void *opaque) +{ + MilkymistVgafbState *s = opaque; + s->invalidate = 1; +} + +static void vgafb_resize(MilkymistVgafbState *s) +{ + if (!vgafb_enabled(s)) { + return; + } + + qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]); + s->invalidate = 1; +} + +static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr) +{ + MilkymistVgafbState *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_CTRL: + case R_HRES: + case R_HSYNC_START: + case R_HSYNC_END: + case R_HSCAN: + case R_VRES: + case R_VSYNC_START: + case R_VSYNC_END: + case R_VSCAN: + case R_BASEADDRESS: + case R_BURST_COUNT: + case R_SOURCE_CLOCK: + r = s->regs[addr]; + break; + case R_BASEADDRESS_ACT: + r = s->regs[R_BASEADDRESS]; + break; + + default: + error_report("milkymist_vgafb: read access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } + + trace_milkymist_vgafb_memory_read(addr << 2, r); + + return r; +} + +static void +vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MilkymistVgafbState *s = opaque; + + trace_milkymist_vgafb_memory_write(addr, value); + + addr >>= 2; + switch (addr) { + case R_CTRL: + case R_HSYNC_START: + case R_HSYNC_END: + case R_HSCAN: + case R_VSYNC_START: + case R_VSYNC_END: + case R_VSCAN: + case R_BURST_COUNT: + case R_SOURCE_CLOCK: + s->regs[addr] = value; + break; + case R_BASEADDRESS: + if (value & 0x1f) { + error_report("milkymist_vgafb: framebuffer base address have to " + "be 32 byte aligned"); + break; + } + s->regs[addr] = value & s->fb_mask; + s->invalidate = 1; + break; + case R_HRES: + case R_VRES: + s->regs[addr] = value; + vgafb_resize(s); + break; + case R_BASEADDRESS_ACT: + error_report("milkymist_vgafb: write to read-only register 0x" + TARGET_FMT_plx, addr << 2); + break; + + default: + error_report("milkymist_vgafb: write access to unknown register 0x" + TARGET_FMT_plx, addr << 2); + break; + } +} + +static CPUReadMemoryFunc * const vgafb_read_fn[] = { + NULL, + NULL, + &vgafb_read +}; + +static CPUWriteMemoryFunc * const vgafb_write_fn[] = { + NULL, + NULL, + &vgafb_write +}; + +static void milkymist_vgafb_reset(DeviceState *d) +{ + MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev); + int i; + + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + /* defaults */ + s->regs[R_CTRL] = CTRL_RESET; + s->regs[R_HRES] = 640; + s->regs[R_VRES] = 480; + s->regs[R_BASEADDRESS] = 0; +} + +static int milkymist_vgafb_init(SysBusDevice *dev) +{ + MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev); + int vgafb_regs; + + vgafb_regs = cpu_register_io_memory(vgafb_read_fn, vgafb_write_fn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, R_MAX * 4, vgafb_regs); + + s->ds = graphic_console_init(vgafb_update_display, + vgafb_invalidate_display, + NULL, NULL, s); + + return 0; +} + +static int vgafb_post_load(void *opaque, int version_id) +{ + vgafb_invalidate_display(opaque); + return 0; +} + +static const VMStateDescription vmstate_milkymist_vgafb = { + .name = "milkymist-vgafb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = vgafb_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo milkymist_vgafb_info = { + .init = milkymist_vgafb_init, + .qdev.name = "milkymist-vgafb", + .qdev.size = sizeof(MilkymistVgafbState), + .qdev.vmsd = &vmstate_milkymist_vgafb, + .qdev.reset = milkymist_vgafb_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0), + DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void milkymist_vgafb_register(void) +{ + sysbus_register_withprop(&milkymist_vgafb_info); +} + +device_init(milkymist_vgafb_register) diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h new file mode 100644 index 0000000000..69af9ef3f6 --- /dev/null +++ b/hw/milkymist-vgafb_template.h @@ -0,0 +1,74 @@ +/* + * QEMU model of the Milkymist VGA framebuffer. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ + +#if BITS == 8 +#define COPY_PIXEL(to, r, g, b) \ + do { \ + *to = rgb_to_pixel8(r, g, b); \ + to += 1; \ + } while (0) +#elif BITS == 15 +#define COPY_PIXEL(to, r, g, b) \ + do { \ + *(uint16_t *)to = rgb_to_pixel15(r, g, b); \ + to += 2; \ + } while (0) +#elif BITS == 16 +#define COPY_PIXEL(to, r, g, b) \ + do { \ + *(uint16_t *)to = rgb_to_pixel16(r, g, b); \ + to += 2; \ + } while (0) +#elif BITS == 24 +#define COPY_PIXEL(to, r, g, b) \ + do { \ + uint32 tmp = rgb_to_pixel24(r, g, b); \ + *(to++) = tmp & 0xff; \ + *(to++) = (tmp >> 8) & 0xff; \ + *(to++) = (tmp >> 16) & 0xff; \ + } while (0) +#elif BITS == 32 +#define COPY_PIXEL(to, r, g, b) \ + do { \ + *(uint32_t *)to = rgb_to_pixel32(r, g, b); \ + to += 4; \ + } while (0) +#else +#error unknown bit depth +#endif + +static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s, + int width, int deststep) +{ + uint16_t rgb565; + uint8_t r, g, b; + + while (width--) { + rgb565 = lduw_raw(s); + r = ((rgb565 >> 11) & 0x1f) << 3; + g = ((rgb565 >> 5) & 0x3f) << 2; + b = ((rgb565 >> 0) & 0x1f) << 3; + COPY_PIXEL(d, r, g, b); + s += 2; + } +} + +#undef BITS +#undef COPY_PIXEL diff --git a/trace-events b/trace-events index 55f3de532a..06efdb7753 100644 --- a/trace-events +++ b/trace-events @@ -355,3 +355,7 @@ disable milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x val disable milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" disable milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX" disable milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX" + +# hw/milkymist-vgafb.c +disable milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" From 38d3339398ec0cffa53834ed32306836a4ad2c78 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:43 +0100 Subject: [PATCH 091/386] lm32: add milkymist hw support functions This patch adds wrappers for easy creation of the qdev devices. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/milkymist-hw.h | 204 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 hw/milkymist-hw.h diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h new file mode 100644 index 0000000000..15acdbccd6 --- /dev/null +++ b/hw/milkymist-hw.h @@ -0,0 +1,204 @@ +#ifndef QEMU_HW_MILKYMIST_H +#define QEMU_HW_MILKYMIST_H + +static inline DeviceState *milkymist_uart_create(target_phys_addr_t base, + qemu_irq rx_irq, qemu_irq tx_irq) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-uart"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq); + + return dev; +} + +static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-hpdmc"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + + return dev; +} + +static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-memcard"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + + return dev; +} + +static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base, + uint32_t fb_offset, uint32_t fb_mask) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-vgafb"); + qdev_prop_set_uint32(dev, "fb_offset", fb_offset); + qdev_prop_set_uint32(dev, "fb_mask", fb_mask); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + + return dev; +} + +static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base, + qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq, + uint32_t freq_hz, uint32_t system_id, uint32_t capabilities, + uint32_t gpio_strappings) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-sysctl"); + qdev_prop_set_uint32(dev, "frequency", freq_hz); + qdev_prop_set_uint32(dev, "systemid", system_id); + qdev_prop_set_uint32(dev, "capabilities", capabilities); + qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, gpio_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, timer0_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, timer1_irq); + + return dev; +} + +static inline DeviceState *milkymist_pfpu_create(target_phys_addr_t base, + qemu_irq irq) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-pfpu"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + return dev; +} + +#ifdef CONFIG_OPENGL +#include <X11/Xlib.h> +#include <GL/glx.h> +static const int glx_fbconfig_attr[] = { + GLX_GREEN_SIZE, 5, + GLX_GREEN_SIZE, 6, + GLX_BLUE_SIZE, 5, + None +}; +#endif + +static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base, + qemu_irq irq) +{ +#ifdef CONFIG_OPENGL + DeviceState *dev; + Display *d; + GLXFBConfig *configs; + int nelements; + int ver_major, ver_minor; + + if (display_type == DT_NOGRAPHIC) { + return NULL; + } + + /* check that GLX will work */ + d = XOpenDisplay(NULL); + if (d == NULL) { + return NULL; + } + + if (!glXQueryVersion(d, &ver_major, &ver_minor)) { + /* Yeah, sometimes getting the GLX version can fail. + * Isn't X beautiful? */ + XCloseDisplay(d); + return NULL; + } + + if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) { + printf("Your GLX version is %d.%d," + "but TMU emulation needs at least 1.3. TMU disabled.\n", + ver_major, ver_minor); + XCloseDisplay(d); + return NULL; + } + + configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements); + if (configs == NULL) { + XCloseDisplay(d); + return NULL; + } + + XFree(configs); + XCloseDisplay(d); + + dev = qdev_create(NULL, "milkymist-tmu2"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + + return dev; +#else + return NULL; +#endif +} + +static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base, + qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq, + qemu_irq dmaw_irq) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-ac97"); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, crrequest_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, crreply_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, dmar_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 3, dmaw_irq); + + return dev; +} + +static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base, + qemu_irq rx_irq, qemu_irq tx_irq) +{ + DeviceState *dev; + + qemu_check_nic_model(&nd_table[0], "minimac"); + dev = qdev_create(NULL, "milkymist-minimac"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq); + + return dev; +} + +static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base, + qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size, + uint32_t dmem_base, uint32_t dmem_size) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "milkymist-softusb"); + qdev_prop_set_uint32(dev, "pmem_base", pmem_base); + qdev_prop_set_uint32(dev, "pmem_size", pmem_size); + qdev_prop_set_uint32(dev, "dmem_base", dmem_base); + qdev_prop_set_uint32(dev, "dmem_size", dmem_size); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + + return dev; +} + +#endif /* QEMU_HW_MILKYMIST_H */ From 5052d2277fdcc08afda245ebfce3163935dc7dfb Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:44 +0100 Subject: [PATCH 092/386] lm32: add support for the Milkymist board This patch adds almost complete support for the Milkymist system-on-chip (http://www.milkymist.org). Additional to running bare metal applications, booting a linux kernel with initrd is supported. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 1 + default-configs/lm32-softmmu.mak | 1 + hw/milkymist.c | 216 +++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 hw/milkymist.c diff --git a/Makefile.target b/Makefile.target index 2a65e15be9..2f7671454c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -260,6 +260,7 @@ obj-ppc-y += xilinx_ethlite.o # LM32 boards obj-lm32-y += lm32_boards.o +obj-lm32-y += milkymist.o # LM32 peripherals obj-lm32-y += lm32_pic.o diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak index 3e7f57e700..0d19974b40 100644 --- a/default-configs/lm32-softmmu.mak +++ b/default-configs/lm32-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for lm32-softmmu CONFIG_PTIMER=y +CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_SD=y diff --git a/hw/milkymist.c b/hw/milkymist.c new file mode 100644 index 0000000000..8defad8024 --- /dev/null +++ b/hw/milkymist.c @@ -0,0 +1,216 @@ +/* + * QEMU model for the Milkymist board. + * + * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "sysbus.h" +#include "hw.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "devices.h" +#include "boards.h" +#include "loader.h" +#include "elf.h" +#include "blockdev.h" +#include "milkymist-hw.h" +#include "lm32.h" + +#define BIOS_FILENAME "mmone-bios.bin" +#define BIOS_OFFSET 0x00860000 +#define BIOS_SIZE (512*1024) +#define KERNEL_LOAD_ADDR 0x40000000 + +typedef struct { + CPUState *env; + target_phys_addr_t bootstrap_pc; + target_phys_addr_t flash_base; + target_phys_addr_t initrd_base; + size_t initrd_size; + target_phys_addr_t cmdline_base; +} ResetInfo; + +static void cpu_irq_handler(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + if (level) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +static void main_cpu_reset(void *opaque) +{ + ResetInfo *reset_info = opaque; + CPUState *env = reset_info->env; + + cpu_reset(env); + + /* init defaults */ + env->pc = reset_info->bootstrap_pc; + env->regs[R_R1] = reset_info->cmdline_base; + env->regs[R_R2] = reset_info->initrd_base; + env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size; + env->eba = reset_info->flash_base; + env->deba = reset_info->flash_base; +} + +static void +milkymist_init(ram_addr_t ram_size_not_used, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + int kernel_size; + DriveInfo *dinfo; + ram_addr_t phys_sdram; + ram_addr_t phys_flash; + qemu_irq irq[32], *cpu_irq; + int i; + char *bios_filename; + ResetInfo *reset_info; + + /* memory map */ + target_phys_addr_t flash_base = 0x00000000; + size_t flash_sector_size = 128 * 1024; + size_t flash_size = 32 * 1024 * 1024; + target_phys_addr_t sdram_base = 0x40000000; + size_t sdram_size = 128 * 1024 * 1024; + + target_phys_addr_t initrd_base = sdram_base + 0x1002000; + target_phys_addr_t cmdline_base = sdram_base + 0x1000000; + size_t initrd_max = sdram_size - 0x1002000; + + reset_info = qemu_mallocz(sizeof(ResetInfo)); + + if (cpu_model == NULL) { + cpu_model = "lm32-full"; + } + env = cpu_init(cpu_model); + reset_info->env = env; + + cpu_lm32_set_phys_msb_ignore(env, 1); + + phys_sdram = qemu_ram_alloc(NULL, "milkymist.sdram", sdram_size); + cpu_register_physical_memory(sdram_base, sdram_size, + phys_sdram | IO_MEM_RAM); + + phys_flash = qemu_ram_alloc(NULL, "milkymist.flash", flash_size); + dinfo = drive_get(IF_PFLASH, 0, 0); + /* Numonyx JS28F256J3F105 */ + pflash_cfi01_register(flash_base, phys_flash, + dinfo ? dinfo->bdrv : NULL, flash_sector_size, + flash_size / flash_sector_size, 2, + 0x00, 0x89, 0x00, 0x1d, 1); + + /* create irq lines */ + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + env->pic_state = lm32_pic_init(*cpu_irq); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_gpio_in(env->pic_state, i); + } + + /* load bios rom */ + if (bios_name == NULL) { + bios_name = BIOS_FILENAME; + } + bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + + if (bios_filename) { + load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE); + } + + reset_info->bootstrap_pc = BIOS_OFFSET; + + /* if no kernel is given no valid bios rom is a fatal error */ + if (!kernel_filename && !dinfo && !bios_filename) { + fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n", + bios_name); + exit(1); + } + + milkymist_uart_create(0x60000000, irq[0], irq[1]); + milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4], + 80000000, 0x10014d31, 0x0000041f, 0x00000001); + milkymist_hpdmc_create(0x60002000); + milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff); + milkymist_memcard_create(0x60004000); + milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]); + milkymist_pfpu_create(0x60006000, irq[9]); + milkymist_tmu2_create(0x60007000, irq[10]); + milkymist_minimac_create(0x60008000, irq[11], irq[12]); + milkymist_softusb_create(0x6000f000, irq[17], + 0x20000000, 0x1000, 0x20020000, 0x2000); + + /* make sure juart isn't the first chardev */ + env->juart_state = lm32_juart_init(); + + if (kernel_filename) { + uint64_t entry; + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL, + 1, ELF_MACHINE, 0); + reset_info->bootstrap_pc = entry; + + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, sdram_base, + sdram_size); + reset_info->bootstrap_pc = sdram_base; + } + + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + if (kernel_cmdline && strlen(kernel_cmdline)) { + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, + kernel_cmdline); + reset_info->cmdline_base = (uint32_t)cmdline_base; + } + + if (initrd_filename) { + size_t initrd_size; + initrd_size = load_image_targphys(initrd_filename, initrd_base, + initrd_max); + reset_info->initrd_base = (uint32_t)initrd_base; + reset_info->initrd_size = (uint32_t)initrd_size; + } + + qemu_register_reset(main_cpu_reset, reset_info); +} + +static QEMUMachine milkymist_machine = { + .name = "milkymist", + .desc = "Milkymist One", + .init = milkymist_init, + .is_default = 0 +}; + +static void milkymist_machine_init(void) +{ + qemu_register_machine(&milkymist_machine); +} + +machine_init(milkymist_machine_init); From d118aa6b4a8fecb1c5a4747fd0f88a015883bf85 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Mon, 7 Mar 2011 23:32:45 +0100 Subject: [PATCH 093/386] MAINTAINERS: add Milkymist board Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9f3ff0e471..e6f853dfff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -214,6 +214,11 @@ M: Michael Walle <michael@walle.cc> S: Maintained F: hw/lm32_boards.c +milkymist +M: Michael Walle <michael@walle.cc> +S: Maintained +F: hw/milkymist.c + M68K Machines ------------- an5206 From c53c1258a455cbe9afd7e5c572578646df30d438 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Mon, 4 Apr 2011 14:48:08 +1000 Subject: [PATCH 094/386] Fix non-portable format string in usb-ccid.c At one point, usb-ccid.c attempts to use a %lX format specifier to print a uint64_t, which is only correct on some host platforms. This patch corrects the statement to use the stdint specified PRIX64 constant instead. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/usb-ccid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 723b2e325f..44156cc1d8 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -1199,7 +1199,7 @@ void ccid_card_card_error(CCIDCardState *card, uint64_t error) s->bmCommandStatus = COMMAND_STATUS_FAILED; s->last_answer_error = error; - DPRINTF(s, 1, "VSC_Error: %lX\n", s->last_answer_error); + DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error); /* TODO: these error's should be more verbose and propogated to the guest.*/ /* * We flush all pending answers on CardRemove message in ccid-card-passthru, From 348883d4828d7434e1053407818598f7fb15e594 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 4 Apr 2011 11:46:32 +0100 Subject: [PATCH 095/386] Makefile.target: Allow target helpers to be in any *_helper.c file Build all files matching *_helper.c with HELPER_CFLAGS, not just op_helper.c. This allows you to put target helper functions which use the global 'env' variable in multiple source files. This only affects the ARM target as all the other targets currently only have op_helper.c. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 2f7671454c..d5761b72f5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -94,7 +94,7 @@ tcg/tcg.o: cpu.h # HELPER_CFLAGS is used for all the code compiled with static register # variables -op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +%_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in cpu-exec.c. From 2a3f75b42ac255be09ec2939b96c549ec830efd3 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 4 Apr 2011 11:46:33 +0100 Subject: [PATCH 096/386] target-arm: Use global env in neon_helper.c helpers Use the global 'env' variable in the helper functions in neon_helper.c. This means we don't need to pass env as an argument to them any more. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helpers.h | 134 ++++++++++++++++++------------------ target-arm/neon_helper.c | 144 +++++++++++++++++++-------------------- target-arm/translate.c | 119 +++++++++++++++----------------- 3 files changed, 191 insertions(+), 206 deletions(-) diff --git a/target-arm/helpers.h b/target-arm/helpers.h index 9de10e352f..0705b9c70a 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -154,22 +154,22 @@ DEF_HELPER_2(sar_cc, i32, i32, i32) DEF_HELPER_2(ror_cc, i32, i32, i32) /* neon_helper.c */ -DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qadd_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qadd_s64, i64, env, i64, i64) -DEF_HELPER_3(neon_qsub_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qsub_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_qadd_u8, i32, i32, i32) +DEF_HELPER_2(neon_qadd_s8, i32, i32, i32) +DEF_HELPER_2(neon_qadd_u16, i32, i32, i32) +DEF_HELPER_2(neon_qadd_s16, i32, i32, i32) +DEF_HELPER_2(neon_qadd_u32, i32, i32, i32) +DEF_HELPER_2(neon_qadd_s32, i32, i32, i32) +DEF_HELPER_2(neon_qsub_u8, i32, i32, i32) +DEF_HELPER_2(neon_qsub_s8, i32, i32, i32) +DEF_HELPER_2(neon_qsub_u16, i32, i32, i32) +DEF_HELPER_2(neon_qsub_s16, i32, i32, i32) +DEF_HELPER_2(neon_qsub_u32, i32, i32, i32) +DEF_HELPER_2(neon_qsub_s32, i32, i32, i32) +DEF_HELPER_2(neon_qadd_u64, i64, i64, i64) +DEF_HELPER_2(neon_qadd_s64, i64, i64, i64) +DEF_HELPER_2(neon_qsub_u64, i64, i64, i64) +DEF_HELPER_2(neon_qsub_s64, i64, i64, i64) DEF_HELPER_2(neon_hadd_s8, i32, i32, i32) DEF_HELPER_2(neon_hadd_u8, i32, i32, i32) @@ -247,26 +247,26 @@ DEF_HELPER_2(neon_rshl_u32, i32, i32, i32) DEF_HELPER_2(neon_rshl_s32, i32, i32, i32) DEF_HELPER_2(neon_rshl_u64, i64, i64, i64) DEF_HELPER_2(neon_rshl_s64, i64, i64, i64) -DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64) -DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32); -DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32); -DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32); -DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64); -DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_qshl_u8, i32, i32, i32) +DEF_HELPER_2(neon_qshl_s8, i32, i32, i32) +DEF_HELPER_2(neon_qshl_u16, i32, i32, i32) +DEF_HELPER_2(neon_qshl_s16, i32, i32, i32) +DEF_HELPER_2(neon_qshl_u32, i32, i32, i32) +DEF_HELPER_2(neon_qshl_s32, i32, i32, i32) +DEF_HELPER_2(neon_qshl_u64, i64, i64, i64) +DEF_HELPER_2(neon_qshl_s64, i64, i64, i64) +DEF_HELPER_2(neon_qshlu_s8, i32, i32, i32); +DEF_HELPER_2(neon_qshlu_s16, i32, i32, i32); +DEF_HELPER_2(neon_qshlu_s32, i32, i32, i32); +DEF_HELPER_2(neon_qshlu_s64, i64, i64, i64); +DEF_HELPER_2(neon_qrshl_u8, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_s8, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_u16, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_s16, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_u32, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_s32, i32, i32, i32) +DEF_HELPER_2(neon_qrshl_u64, i64, i64, i64) +DEF_HELPER_2(neon_qrshl_s64, i64, i64, i64) DEF_HELPER_2(neon_add_u8, i32, i32, i32) DEF_HELPER_2(neon_add_u16, i32, i32, i32) @@ -295,22 +295,22 @@ DEF_HELPER_1(neon_cls_s16, i32, i32) DEF_HELPER_1(neon_cls_s32, i32, i32) DEF_HELPER_1(neon_cnt_u8, i32, i32) -DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) +DEF_HELPER_2(neon_qdmulh_s16, i32, i32, i32) +DEF_HELPER_2(neon_qrdmulh_s16, i32, i32, i32) +DEF_HELPER_2(neon_qdmulh_s32, i32, i32, i32) +DEF_HELPER_2(neon_qrdmulh_s32, i32, i32, i32) DEF_HELPER_1(neon_narrow_u8, i32, i64) DEF_HELPER_1(neon_narrow_u16, i32, i64) -DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64) -DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64) -DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64) -DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64) +DEF_HELPER_1(neon_unarrow_sat8, i32, i64) +DEF_HELPER_1(neon_narrow_sat_u8, i32, i64) +DEF_HELPER_1(neon_narrow_sat_s8, i32, i64) +DEF_HELPER_1(neon_unarrow_sat16, i32, i64) +DEF_HELPER_1(neon_narrow_sat_u16, i32, i64) +DEF_HELPER_1(neon_narrow_sat_s16, i32, i64) +DEF_HELPER_1(neon_unarrow_sat32, i32, i64) +DEF_HELPER_1(neon_narrow_sat_u32, i32, i64) +DEF_HELPER_1(neon_narrow_sat_s32, i32, i64) DEF_HELPER_1(neon_narrow_high_u8, i32, i64) DEF_HELPER_1(neon_narrow_high_u16, i32, i64) DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) @@ -326,8 +326,8 @@ DEF_HELPER_2(neon_paddl_u16, i64, i64, i64) DEF_HELPER_2(neon_paddl_u32, i64, i64, i64) DEF_HELPER_2(neon_subl_u16, i64, i64, i64) DEF_HELPER_2(neon_subl_u32, i64, i64, i64) -DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) -DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_addl_saturate_s32, i64, i64, i64) +DEF_HELPER_2(neon_addl_saturate_s64, i64, i64, i64) DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) DEF_HELPER_2(neon_abdl_s16, i64, i32, i32) DEF_HELPER_2(neon_abdl_u32, i64, i32, i32) @@ -343,12 +343,12 @@ DEF_HELPER_1(neon_negl_u16, i64, i64) DEF_HELPER_1(neon_negl_u32, i64, i64) DEF_HELPER_1(neon_negl_u64, i64, i64) -DEF_HELPER_2(neon_qabs_s8, i32, env, i32) -DEF_HELPER_2(neon_qabs_s16, i32, env, i32) -DEF_HELPER_2(neon_qabs_s32, i32, env, i32) -DEF_HELPER_2(neon_qneg_s8, i32, env, i32) -DEF_HELPER_2(neon_qneg_s16, i32, env, i32) -DEF_HELPER_2(neon_qneg_s32, i32, env, i32) +DEF_HELPER_1(neon_qabs_s8, i32, i32) +DEF_HELPER_1(neon_qabs_s16, i32, i32) +DEF_HELPER_1(neon_qabs_s32, i32, i32) +DEF_HELPER_1(neon_qneg_s8, i32, i32) +DEF_HELPER_1(neon_qneg_s16, i32, i32) +DEF_HELPER_1(neon_qneg_s32, i32, i32) DEF_HELPER_2(neon_min_f32, i32, i32, i32) DEF_HELPER_2(neon_max_f32, i32, i32, i32) @@ -461,15 +461,15 @@ DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) DEF_HELPER_2(set_teecr, void, env, i32) -DEF_HELPER_3(neon_unzip8, void, env, i32, i32) -DEF_HELPER_3(neon_unzip16, void, env, i32, i32) -DEF_HELPER_3(neon_qunzip8, void, env, i32, i32) -DEF_HELPER_3(neon_qunzip16, void, env, i32, i32) -DEF_HELPER_3(neon_qunzip32, void, env, i32, i32) -DEF_HELPER_3(neon_zip8, void, env, i32, i32) -DEF_HELPER_3(neon_zip16, void, env, i32, i32) -DEF_HELPER_3(neon_qzip8, void, env, i32, i32) -DEF_HELPER_3(neon_qzip16, void, env, i32, i32) -DEF_HELPER_3(neon_qzip32, void, env, i32, i32) +DEF_HELPER_2(neon_unzip8, void, i32, i32) +DEF_HELPER_2(neon_unzip16, void, i32, i32) +DEF_HELPER_2(neon_qunzip8, void, i32, i32) +DEF_HELPER_2(neon_qunzip16, void, i32, i32) +DEF_HELPER_2(neon_qunzip32, void, i32, i32) +DEF_HELPER_2(neon_zip8, void, i32, i32) +DEF_HELPER_2(neon_zip16, void, i32, i32) +DEF_HELPER_2(neon_qzip8, void, i32, i32) +DEF_HELPER_2(neon_qzip16, void, i32, i32) +DEF_HELPER_2(neon_qzip32, void, i32, i32) #include "def-helper.h" diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 71f1a7ead0..315e69337e 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -10,7 +10,7 @@ #include <stdio.h> #include "cpu.h" -#include "exec-all.h" +#include "exec.h" #include "helpers.h" #define SIGNBIT (uint32_t)0x80000000 @@ -116,10 +116,6 @@ NEON_TYPE1(u32, uint32_t) uint32_t HELPER(glue(neon_,name))(uint32_t arg1, uint32_t arg2) \ NEON_VOP_BODY(vtype, n) -#define NEON_VOP_ENV(name, vtype, n) \ -uint32_t HELPER(glue(neon_,name))(CPUState *env, uint32_t arg1, uint32_t arg2) \ -NEON_VOP_BODY(vtype, n) - /* Pairwise operations. */ /* For 32-bit elements each segment only contains a single element, so the elementwise and pairwise operations are the same. */ @@ -168,14 +164,14 @@ uint32_t HELPER(glue(neon_,name))(uint32_t arg) \ dest = tmp; \ }} while(0) #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) -NEON_VOP_ENV(qadd_u8, neon_u8, 4) +NEON_VOP(qadd_u8, neon_u8, 4) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) -NEON_VOP_ENV(qadd_u16, neon_u16, 2) +NEON_VOP(qadd_u16, neon_u16, 2) #undef NEON_FN #undef NEON_USAT -uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b) +uint32_t HELPER(neon_qadd_u32)(uint32_t a, uint32_t b) { uint32_t res = a + b; if (res < a) { @@ -185,7 +181,7 @@ uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b) return res; } -uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2) +uint64_t HELPER(neon_qadd_u64)(uint64_t src1, uint64_t src2) { uint64_t res; @@ -210,14 +206,14 @@ uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2) dest = tmp; \ } while(0) #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) -NEON_VOP_ENV(qadd_s8, neon_s8, 4) +NEON_VOP(qadd_s8, neon_s8, 4) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) -NEON_VOP_ENV(qadd_s16, neon_s16, 2) +NEON_VOP(qadd_s16, neon_s16, 2) #undef NEON_FN #undef NEON_SSAT -uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b) +uint32_t HELPER(neon_qadd_s32)(uint32_t a, uint32_t b) { uint32_t res = a + b; if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { @@ -227,7 +223,7 @@ uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b) return res; } -uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2) +uint64_t HELPER(neon_qadd_s64)(uint64_t src1, uint64_t src2) { uint64_t res; @@ -248,14 +244,14 @@ uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2) dest = tmp; \ }} while(0) #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) -NEON_VOP_ENV(qsub_u8, neon_u8, 4) +NEON_VOP(qsub_u8, neon_u8, 4) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) -NEON_VOP_ENV(qsub_u16, neon_u16, 2) +NEON_VOP(qsub_u16, neon_u16, 2) #undef NEON_FN #undef NEON_USAT -uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b) +uint32_t HELPER(neon_qsub_u32)(uint32_t a, uint32_t b) { uint32_t res = a - b; if (res > a) { @@ -265,7 +261,7 @@ uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b) return res; } -uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2) +uint64_t HELPER(neon_qsub_u64)(uint64_t src1, uint64_t src2) { uint64_t res; @@ -291,14 +287,14 @@ uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2) dest = tmp; \ } while(0) #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) -NEON_VOP_ENV(qsub_s8, neon_s8, 4) +NEON_VOP(qsub_s8, neon_s8, 4) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) -NEON_VOP_ENV(qsub_s16, neon_s16, 2) +NEON_VOP(qsub_s16, neon_s16, 2) #undef NEON_FN #undef NEON_SSAT -uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b) +uint32_t HELPER(neon_qsub_s32)(uint32_t a, uint32_t b) { uint32_t res = a - b; if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { @@ -308,7 +304,7 @@ uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b) return res; } -uint64_t HELPER(neon_qsub_s64)(CPUState *env, uint64_t src1, uint64_t src2) +uint64_t HELPER(neon_qsub_s64)(uint64_t src1, uint64_t src2) { uint64_t res; @@ -659,12 +655,12 @@ uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop) dest = ~0; \ } \ }} while (0) -NEON_VOP_ENV(qshl_u8, neon_u8, 4) -NEON_VOP_ENV(qshl_u16, neon_u16, 2) -NEON_VOP_ENV(qshl_u32, neon_u32, 1) +NEON_VOP(qshl_u8, neon_u8, 4) +NEON_VOP(qshl_u16, neon_u16, 2) +NEON_VOP(qshl_u32, neon_u32, 1) #undef NEON_FN -uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +uint64_t HELPER(neon_qshl_u64)(uint64_t val, uint64_t shiftop) { int8_t shift = (int8_t)shiftop; if (shift >= 64) { @@ -714,12 +710,12 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) } \ } \ }} while (0) -NEON_VOP_ENV(qshl_s8, neon_s8, 4) -NEON_VOP_ENV(qshl_s16, neon_s16, 2) -NEON_VOP_ENV(qshl_s32, neon_s32, 1) +NEON_VOP(qshl_s8, neon_s8, 4) +NEON_VOP(qshl_s16, neon_s16, 2) +NEON_VOP(qshl_s32, neon_s32, 1) #undef NEON_FN -uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +uint64_t HELPER(neon_qshl_s64)(uint64_t valop, uint64_t shiftop) { int8_t shift = (uint8_t)shiftop; int64_t val = valop; @@ -769,26 +765,26 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) } \ } \ }} while (0) -NEON_VOP_ENV(qshlu_s8, neon_u8, 4) -NEON_VOP_ENV(qshlu_s16, neon_u16, 2) +NEON_VOP(qshlu_s8, neon_u8, 4) +NEON_VOP(qshlu_s16, neon_u16, 2) #undef NEON_FN -uint32_t HELPER(neon_qshlu_s32)(CPUState *env, uint32_t valop, uint32_t shiftop) +uint32_t HELPER(neon_qshlu_s32)(uint32_t valop, uint32_t shiftop) { if ((int32_t)valop < 0) { SET_QC(); return 0; } - return helper_neon_qshl_u32(env, valop, shiftop); + return helper_neon_qshl_u32(valop, shiftop); } -uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +uint64_t HELPER(neon_qshlu_s64)(uint64_t valop, uint64_t shiftop) { if ((int64_t)valop < 0) { SET_QC(); return 0; } - return helper_neon_qshl_u64(env, valop, shiftop); + return helper_neon_qshl_u64(valop, shiftop); } /* FIXME: This is wrong. */ @@ -815,13 +811,13 @@ uint64_t HELPER(neon_qshlu_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) dest = ~0; \ } \ }} while (0) -NEON_VOP_ENV(qrshl_u8, neon_u8, 4) -NEON_VOP_ENV(qrshl_u16, neon_u16, 2) +NEON_VOP(qrshl_u8, neon_u8, 4) +NEON_VOP(qrshl_u16, neon_u16, 2) #undef NEON_FN /* The addition of the rounding constant may overflow, so we use an * intermediate 64 bits accumulator. */ -uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop) +uint32_t HELPER(neon_qrshl_u32)(uint32_t val, uint32_t shiftop) { uint32_t dest; int8_t shift = (int8_t)shiftop; @@ -851,7 +847,7 @@ uint32_t HELPER(neon_qrshl_u32)(CPUState *env, uint32_t val, uint32_t shiftop) /* Handling addition overflow with 64 bits inputs values is more * tricky than with 32 bits values. */ -uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) +uint64_t HELPER(neon_qrshl_u64)(uint64_t val, uint64_t shiftop) { int8_t shift = (int8_t)shiftop; if (shift >= 64) { @@ -912,13 +908,13 @@ uint64_t HELPER(neon_qrshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) } \ } \ }} while (0) -NEON_VOP_ENV(qrshl_s8, neon_s8, 4) -NEON_VOP_ENV(qrshl_s16, neon_s16, 2) +NEON_VOP(qrshl_s8, neon_s8, 4) +NEON_VOP(qrshl_s16, neon_s16, 2) #undef NEON_FN /* The addition of the rounding constant may overflow, so we use an * intermediate 64 bits accumulator. */ -uint32_t HELPER(neon_qrshl_s32)(CPUState *env, uint32_t valop, uint32_t shiftop) +uint32_t HELPER(neon_qrshl_s32)(uint32_t valop, uint32_t shiftop) { int32_t dest; int32_t val = (int32_t)valop; @@ -947,7 +943,7 @@ uint32_t HELPER(neon_qrshl_s32)(CPUState *env, uint32_t valop, uint32_t shiftop) /* Handling addition overflow with 64 bits inputs values is more * tricky than with 32 bits values. */ -uint64_t HELPER(neon_qrshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) +uint64_t HELPER(neon_qrshl_s64)(uint64_t valop, uint64_t shiftop) { int8_t shift = (uint8_t)shiftop; int64_t val = valop; @@ -1156,10 +1152,10 @@ uint32_t HELPER(neon_cnt_u8)(uint32_t x) dest = tmp >> 16; \ } while(0) #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) -NEON_VOP_ENV(qdmulh_s16, neon_s16, 2) +NEON_VOP(qdmulh_s16, neon_s16, 2) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) -NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2) +NEON_VOP(qrdmulh_s16, neon_s16, 2) #undef NEON_FN #undef NEON_QDMULH16 @@ -1182,10 +1178,10 @@ NEON_VOP_ENV(qrdmulh_s16, neon_s16, 2) dest = tmp >> 32; \ } while(0) #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) -NEON_VOP_ENV(qdmulh_s32, neon_s32, 1) +NEON_VOP(qdmulh_s32, neon_s32, 1) #undef NEON_FN #define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) -NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1) +NEON_VOP(qrdmulh_s32, neon_s32, 1) #undef NEON_FN #undef NEON_QDMULH32 @@ -1226,7 +1222,7 @@ uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x) return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000); } -uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_unarrow_sat8)(uint64_t x) { uint16_t s; uint8_t d; @@ -1253,7 +1249,7 @@ uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x) return res; } -uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_u8)(uint64_t x) { uint16_t s; uint8_t d; @@ -1276,7 +1272,7 @@ uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x) return res; } -uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_s8)(uint64_t x) { int16_t s; uint8_t d; @@ -1299,7 +1295,7 @@ uint32_t HELPER(neon_narrow_sat_s8)(CPUState *env, uint64_t x) return res; } -uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_unarrow_sat16)(uint64_t x) { uint32_t high; uint32_t low; @@ -1322,7 +1318,7 @@ uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x) return low | (high << 16); } -uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_u16)(uint64_t x) { uint32_t high; uint32_t low; @@ -1339,7 +1335,7 @@ uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x) return low | (high << 16); } -uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_s16)(uint64_t x) { int32_t low; int32_t high; @@ -1356,7 +1352,7 @@ uint32_t HELPER(neon_narrow_sat_s16)(CPUState *env, uint64_t x) return (uint16_t)low | (high << 16); } -uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_unarrow_sat32)(uint64_t x) { if (x & 0x8000000000000000ull) { SET_QC(); @@ -1369,7 +1365,7 @@ uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x) return x; } -uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_u32)(uint64_t x) { if (x > 0xffffffffu) { SET_QC(); @@ -1378,7 +1374,7 @@ uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x) return x; } -uint32_t HELPER(neon_narrow_sat_s32)(CPUState *env, uint64_t x) +uint32_t HELPER(neon_narrow_sat_s32)(uint64_t x) { if ((int64_t)x != (int32_t)x) { SET_QC(); @@ -1485,7 +1481,7 @@ uint64_t HELPER(neon_subl_u32)(uint64_t a, uint64_t b) return (a - b) ^ mask; } -uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(neon_addl_saturate_s32)(uint64_t a, uint64_t b) { uint32_t x, y; uint32_t low, high; @@ -1507,7 +1503,7 @@ uint64_t HELPER(neon_addl_saturate_s32)(CPUState *env, uint64_t a, uint64_t b) return low | ((uint64_t)high << 32); } -uint64_t HELPER(neon_addl_saturate_s64)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(neon_addl_saturate_s64)(uint64_t a, uint64_t b) { uint64_t result; @@ -1679,7 +1675,7 @@ uint64_t HELPER(neon_negl_u64)(uint64_t x) } else if (x < 0) { \ x = -x; \ }} while (0) -uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qabs_s8)(uint32_t x) { neon_s8 vec; NEON_UNPACK(neon_s8, vec, x); @@ -1699,7 +1695,7 @@ uint32_t HELPER(neon_qabs_s8)(CPUState *env, uint32_t x) } else { \ x = -x; \ }} while (0) -uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qneg_s8)(uint32_t x) { neon_s8 vec; NEON_UNPACK(neon_s8, vec, x); @@ -1719,7 +1715,7 @@ uint32_t HELPER(neon_qneg_s8)(CPUState *env, uint32_t x) } else if (x < 0) { \ x = -x; \ }} while (0) -uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qabs_s16)(uint32_t x) { neon_s16 vec; NEON_UNPACK(neon_s16, vec, x); @@ -1737,7 +1733,7 @@ uint32_t HELPER(neon_qabs_s16)(CPUState *env, uint32_t x) } else { \ x = -x; \ }} while (0) -uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qneg_s16)(uint32_t x) { neon_s16 vec; NEON_UNPACK(neon_s16, vec, x); @@ -1748,7 +1744,7 @@ uint32_t HELPER(neon_qneg_s16)(CPUState *env, uint32_t x) } #undef DO_QNEG16 -uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qabs_s32)(uint32_t x) { if (x == SIGNBIT) { SET_QC(); @@ -1759,7 +1755,7 @@ uint32_t HELPER(neon_qabs_s32)(CPUState *env, uint32_t x) return x; } -uint32_t HELPER(neon_qneg_s32)(CPUState *env, uint32_t x) +uint32_t HELPER(neon_qneg_s32)(uint32_t x) { if (x == SIGNBIT) { SET_QC(); @@ -1842,7 +1838,7 @@ uint32_t HELPER(neon_acgt_f32)(uint32_t a, uint32_t b) #define ELEM(V, N, SIZE) (((V) >> ((N) * (SIZE))) & ((1ull << (SIZE)) - 1)) -void HELPER(neon_qunzip8)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qunzip8)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1870,7 +1866,7 @@ void HELPER(neon_qunzip8)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_qunzip16)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qunzip16)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1890,7 +1886,7 @@ void HELPER(neon_qunzip16)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_qunzip32)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qunzip32)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1906,7 +1902,7 @@ void HELPER(neon_qunzip32)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_unzip8)(uint32_t rd, uint32_t rm) { uint64_t zm = float64_val(env->vfp.regs[rm]); uint64_t zd = float64_val(env->vfp.regs[rd]); @@ -1922,7 +1918,7 @@ void HELPER(neon_unzip8)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd] = make_float64(d0); } -void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_unzip16)(uint32_t rd, uint32_t rm) { uint64_t zm = float64_val(env->vfp.regs[rm]); uint64_t zd = float64_val(env->vfp.regs[rd]); @@ -1934,7 +1930,7 @@ void HELPER(neon_unzip16)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd] = make_float64(d0); } -void HELPER(neon_qzip8)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qzip8)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1962,7 +1958,7 @@ void HELPER(neon_qzip8)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_qzip16)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qzip16)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1982,7 +1978,7 @@ void HELPER(neon_qzip16)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_qzip32)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_qzip32)(uint32_t rd, uint32_t rm) { uint64_t zm0 = float64_val(env->vfp.regs[rm]); uint64_t zm1 = float64_val(env->vfp.regs[rm + 1]); @@ -1998,7 +1994,7 @@ void HELPER(neon_qzip32)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd + 1] = make_float64(d1); } -void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_zip8)(uint32_t rd, uint32_t rm) { uint64_t zm = float64_val(env->vfp.regs[rm]); uint64_t zd = float64_val(env->vfp.regs[rd]); @@ -2014,7 +2010,7 @@ void HELPER(neon_zip8)(CPUState *env, uint32_t rd, uint32_t rm) env->vfp.regs[rd] = make_float64(d0); } -void HELPER(neon_zip16)(CPUState *env, uint32_t rd, uint32_t rm) +void HELPER(neon_zip16)(uint32_t rd, uint32_t rm) { uint64_t zm = float64_val(env->vfp.regs[rm]); uint64_t zd = float64_val(env->vfp.regs[rd]); diff --git a/target-arm/translate.c b/target-arm/translate.c index 33417e6825..53c40acca9 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3656,13 +3656,13 @@ static int gen_neon_unzip(int rd, int rm, int size, int q) if (q) { switch (size) { case 0: - gen_helper_neon_qunzip8(cpu_env, tmp, tmp2); + gen_helper_neon_qunzip8(tmp, tmp2); break; case 1: - gen_helper_neon_qunzip16(cpu_env, tmp, tmp2); + gen_helper_neon_qunzip16(tmp, tmp2); break; case 2: - gen_helper_neon_qunzip32(cpu_env, tmp, tmp2); + gen_helper_neon_qunzip32(tmp, tmp2); break; default: abort(); @@ -3670,10 +3670,10 @@ static int gen_neon_unzip(int rd, int rm, int size, int q) } else { switch (size) { case 0: - gen_helper_neon_unzip8(cpu_env, tmp, tmp2); + gen_helper_neon_unzip8(tmp, tmp2); break; case 1: - gen_helper_neon_unzip16(cpu_env, tmp, tmp2); + gen_helper_neon_unzip16(tmp, tmp2); break; default: abort(); @@ -3695,13 +3695,13 @@ static int gen_neon_zip(int rd, int rm, int size, int q) if (q) { switch (size) { case 0: - gen_helper_neon_qzip8(cpu_env, tmp, tmp2); + gen_helper_neon_qzip8(tmp, tmp2); break; case 1: - gen_helper_neon_qzip16(cpu_env, tmp, tmp2); + gen_helper_neon_qzip16(tmp, tmp2); break; case 2: - gen_helper_neon_qzip32(cpu_env, tmp, tmp2); + gen_helper_neon_qzip32(tmp, tmp2); break; default: abort(); @@ -3709,10 +3709,10 @@ static int gen_neon_zip(int rd, int rm, int size, int q) } else { switch (size) { case 0: - gen_helper_neon_zip8(cpu_env, tmp, tmp2); + gen_helper_neon_zip8(tmp, tmp2); break; case 1: - gen_helper_neon_zip16(cpu_env, tmp, tmp2); + gen_helper_neon_zip16(tmp, tmp2); break; default: abort(); @@ -4063,9 +4063,9 @@ static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src) static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src) { switch (size) { - case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; + case 0: gen_helper_neon_narrow_sat_s8(dest, src); break; + case 1: gen_helper_neon_narrow_sat_s16(dest, src); break; + case 2: gen_helper_neon_narrow_sat_s32(dest, src); break; default: abort(); } } @@ -4073,9 +4073,9 @@ static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src) static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src) { switch (size) { - case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; + case 0: gen_helper_neon_narrow_sat_u8(dest, src); break; + case 1: gen_helper_neon_narrow_sat_u16(dest, src); break; + case 2: gen_helper_neon_narrow_sat_u32(dest, src); break; default: abort(); } } @@ -4083,9 +4083,9 @@ static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src) static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src) { switch (size) { - case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break; - case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break; - case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break; + case 0: gen_helper_neon_unarrow_sat8(dest, src); break; + case 1: gen_helper_neon_unarrow_sat16(dest, src); break; + case 2: gen_helper_neon_unarrow_sat32(dest, src); break; default: abort(); } } @@ -4177,8 +4177,8 @@ static inline void gen_neon_negl(TCGv_i64 var, int size) static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size) { switch (size) { - case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break; - case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break; + case 1: gen_helper_neon_addl_saturate_s32(op0, op0, op1); break; + case 2: gen_helper_neon_addl_saturate_s64(op0, op0, op1); break; default: abort(); } } @@ -4271,20 +4271,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) switch (op) { case 1: /* VQADD */ if (u) { - gen_helper_neon_qadd_u64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); + gen_helper_neon_qadd_u64(cpu_V0, cpu_V0, cpu_V1); } else { - gen_helper_neon_qadd_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); + gen_helper_neon_qadd_s64(cpu_V0, cpu_V0, cpu_V1); } break; case 5: /* VQSUB */ if (u) { - gen_helper_neon_qsub_u64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); + gen_helper_neon_qsub_u64(cpu_V0, cpu_V0, cpu_V1); } else { - gen_helper_neon_qsub_s64(cpu_V0, cpu_env, - cpu_V0, cpu_V1); + gen_helper_neon_qsub_s64(cpu_V0, cpu_V0, cpu_V1); } break; case 8: /* VSHL */ @@ -4296,11 +4292,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 9: /* VQSHL */ if (u) { - gen_helper_neon_qshl_u64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); + gen_helper_neon_qshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { - gen_helper_neon_qshl_s64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); + gen_helper_neon_qshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; case 10: /* VRSHL */ @@ -4312,11 +4306,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 11: /* VQRSHL */ if (u) { - gen_helper_neon_qrshl_u64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); + gen_helper_neon_qrshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { - gen_helper_neon_qrshl_s64(cpu_V0, cpu_env, - cpu_V1, cpu_V0); + gen_helper_neon_qrshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; case 16: @@ -4388,7 +4380,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(hadd); break; case 1: /* VQADD */ - GEN_NEON_INTEGER_OP_ENV(qadd); + GEN_NEON_INTEGER_OP(qadd); break; case 2: /* VRHADD */ GEN_NEON_INTEGER_OP(rhadd); @@ -4431,7 +4423,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(hsub); break; case 5: /* VQSUB */ - GEN_NEON_INTEGER_OP_ENV(qsub); + GEN_NEON_INTEGER_OP(qsub); break; case 6: /* VCGT */ GEN_NEON_INTEGER_OP(cgt); @@ -4443,13 +4435,13 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(shl); break; case 9: /* VQSHL */ - GEN_NEON_INTEGER_OP_ENV(qshl); + GEN_NEON_INTEGER_OP(qshl); break; case 10: /* VRSHL */ GEN_NEON_INTEGER_OP(rshl); break; case 11: /* VQRSHL */ - GEN_NEON_INTEGER_OP_ENV(qrshl); + GEN_NEON_INTEGER_OP(qrshl); break; case 12: /* VMAX */ GEN_NEON_INTEGER_OP(max); @@ -4532,14 +4524,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 22: /* Hultiply high. */ if (!u) { /* VQDMULH */ switch (size) { - case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break; - case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + case 1: gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); break; default: return 1; } } else { /* VQRDHMUL */ switch (size) { - case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break; - case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break; + case 1: gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); break; + case 2: gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); break; default: return 1; } } @@ -4710,7 +4702,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 6: /* VQSHLU */ if (u) { - gen_helper_neon_qshlu_s64(cpu_V0, cpu_env, + gen_helper_neon_qshlu_s64(cpu_V0, cpu_V0, cpu_V1); } else { return 1; @@ -4718,10 +4710,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 7: /* VQSHL */ if (u) { - gen_helper_neon_qshl_u64(cpu_V0, cpu_env, + gen_helper_neon_qshl_u64(cpu_V0, cpu_V0, cpu_V1); } else { - gen_helper_neon_qshl_s64(cpu_V0, cpu_env, + gen_helper_neon_qshl_s64(cpu_V0, cpu_V0, cpu_V1); } break; @@ -4780,23 +4772,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } switch (size) { case 0: - gen_helper_neon_qshlu_s8(tmp, cpu_env, - tmp, tmp2); + gen_helper_neon_qshlu_s8(tmp, tmp, tmp2); break; case 1: - gen_helper_neon_qshlu_s16(tmp, cpu_env, - tmp, tmp2); + gen_helper_neon_qshlu_s16(tmp, tmp, tmp2); break; case 2: - gen_helper_neon_qshlu_s32(tmp, cpu_env, - tmp, tmp2); + gen_helper_neon_qshlu_s32(tmp, tmp, tmp2); break; default: return 1; } break; case 7: /* VQSHL */ - GEN_NEON_INTEGER_OP_ENV(qshl); + GEN_NEON_INTEGER_OP(qshl); break; } tcg_temp_free_i32(tmp2); @@ -5259,15 +5248,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rn, pass); if (op == 12) { if (size == 1) { - gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); + gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); } else { - gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); + gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); } } else if (op == 13) { if (size == 1) { - gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); + gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); } else { - gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); + gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); } } else if (op & 1) { gen_helper_neon_mul_f32(tmp, tmp, tmp2); @@ -5614,17 +5603,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 14: /* VQABS */ switch (size) { - case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break; - case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break; - case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break; + case 0: gen_helper_neon_qabs_s8(tmp, tmp); break; + case 1: gen_helper_neon_qabs_s16(tmp, tmp); break; + case 2: gen_helper_neon_qabs_s32(tmp, tmp); break; default: return 1; } break; case 15: /* VQNEG */ switch (size) { - case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break; - case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break; - case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break; + case 0: gen_helper_neon_qneg_s8(tmp, tmp); break; + case 1: gen_helper_neon_qneg_s16(tmp, tmp); break; + case 2: gen_helper_neon_qneg_s32(tmp, tmp); break; default: return 1; } break; From 947a2fa21b61703802a660a938cabd7b3600ee79 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 4 Apr 2011 11:46:34 +0100 Subject: [PATCH 097/386] target-arm: Use global env in iwmmxt_helper.c helpers Use the global 'env' variable in the helper functions in iwmmxt_helper.c. This means we don't need to pass env as an argument to them any more. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helpers.h | 108 ++++++++++++++++----------------- target-arm/iwmmxt_helper.c | 80 +++++++++++-------------- target-arm/translate.c | 119 +++++++++++++++++-------------------- 3 files changed, 144 insertions(+), 163 deletions(-) diff --git a/target-arm/helpers.h b/target-arm/helpers.h index 0705b9c70a..ae701e8451 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -375,47 +375,47 @@ DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64) DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64) DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64) -#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ -DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \ -DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \ -DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \ +#define DEF_IWMMXT_HELPER_SIZE(name) \ +DEF_HELPER_2(iwmmxt_##name##b, i64, i64, i64) \ +DEF_HELPER_2(iwmmxt_##name##w, i64, i64, i64) \ +DEF_HELPER_2(iwmmxt_##name##l, i64, i64, i64) \ -DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) -DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) +DEF_IWMMXT_HELPER_SIZE(unpackl) +DEF_IWMMXT_HELPER_SIZE(unpackh) -DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64) +DEF_HELPER_1(iwmmxt_unpacklub, i64, i64) +DEF_HELPER_1(iwmmxt_unpackluw, i64, i64) +DEF_HELPER_1(iwmmxt_unpacklul, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhub, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhuw, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhul, i64, i64) +DEF_HELPER_1(iwmmxt_unpacklsb, i64, i64) +DEF_HELPER_1(iwmmxt_unpacklsw, i64, i64) +DEF_HELPER_1(iwmmxt_unpacklsl, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhsb, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhsw, i64, i64) +DEF_HELPER_1(iwmmxt_unpackhsl, i64, i64) -DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) -DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) -DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) +DEF_IWMMXT_HELPER_SIZE(cmpeq) +DEF_IWMMXT_HELPER_SIZE(cmpgtu) +DEF_IWMMXT_HELPER_SIZE(cmpgts) -DEF_IWMMXT_HELPER_SIZE_ENV(mins) -DEF_IWMMXT_HELPER_SIZE_ENV(minu) -DEF_IWMMXT_HELPER_SIZE_ENV(maxs) -DEF_IWMMXT_HELPER_SIZE_ENV(maxu) +DEF_IWMMXT_HELPER_SIZE(mins) +DEF_IWMMXT_HELPER_SIZE(minu) +DEF_IWMMXT_HELPER_SIZE(maxs) +DEF_IWMMXT_HELPER_SIZE(maxu) -DEF_IWMMXT_HELPER_SIZE_ENV(subn) -DEF_IWMMXT_HELPER_SIZE_ENV(addn) -DEF_IWMMXT_HELPER_SIZE_ENV(subu) -DEF_IWMMXT_HELPER_SIZE_ENV(addu) -DEF_IWMMXT_HELPER_SIZE_ENV(subs) -DEF_IWMMXT_HELPER_SIZE_ENV(adds) +DEF_IWMMXT_HELPER_SIZE(subn) +DEF_IWMMXT_HELPER_SIZE(addn) +DEF_IWMMXT_HELPER_SIZE(subu) +DEF_IWMMXT_HELPER_SIZE(addu) +DEF_IWMMXT_HELPER_SIZE(subs) +DEF_IWMMXT_HELPER_SIZE(adds) -DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64) +DEF_HELPER_2(iwmmxt_avgb0, i64, i64, i64) +DEF_HELPER_2(iwmmxt_avgb1, i64, i64, i64) +DEF_HELPER_2(iwmmxt_avgw0, i64, i64, i64) +DEF_HELPER_2(iwmmxt_avgw1, i64, i64, i64) DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64) @@ -434,26 +434,26 @@ DEF_HELPER_1(iwmmxt_msbb, i32, i64) DEF_HELPER_1(iwmmxt_msbw, i32, i64) DEF_HELPER_1(iwmmxt_msbl, i32, i64) -DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32) +DEF_HELPER_2(iwmmxt_srlw, i64, i64, i32) +DEF_HELPER_2(iwmmxt_srll, i64, i64, i32) +DEF_HELPER_2(iwmmxt_srlq, i64, i64, i32) +DEF_HELPER_2(iwmmxt_sllw, i64, i64, i32) +DEF_HELPER_2(iwmmxt_slll, i64, i64, i32) +DEF_HELPER_2(iwmmxt_sllq, i64, i64, i32) +DEF_HELPER_2(iwmmxt_sraw, i64, i64, i32) +DEF_HELPER_2(iwmmxt_sral, i64, i64, i32) +DEF_HELPER_2(iwmmxt_sraq, i64, i64, i32) +DEF_HELPER_2(iwmmxt_rorw, i64, i64, i32) +DEF_HELPER_2(iwmmxt_rorl, i64, i64, i32) +DEF_HELPER_2(iwmmxt_rorq, i64, i64, i32) +DEF_HELPER_2(iwmmxt_shufh, i64, i64, i32) -DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64) +DEF_HELPER_2(iwmmxt_packuw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_packul, i64, i64, i64) +DEF_HELPER_2(iwmmxt_packuq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_packsw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_packsl, i64, i64, i64) +DEF_HELPER_2(iwmmxt_packsq, i64, i64, i64) DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c index 3332f708c9..3941f1fd89 100644 --- a/target-arm/iwmmxt_helper.c +++ b/target-arm/iwmmxt_helper.c @@ -23,7 +23,7 @@ #include <stdio.h> #include "cpu.h" -#include "exec-all.h" +#include "exec.h" #include "helpers.h" /* iwMMXt macros extracted from GNU gdb. */ @@ -162,8 +162,7 @@ uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b) SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ SIMD64_SET(ZBIT64(x), SIMD_ZBIT) #define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(uint64_t a, uint64_t b) \ { \ a = \ (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \ @@ -177,8 +176,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUState *env, \ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ return a; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(uint64_t a, uint64_t b) \ { \ a = \ (((a >> SH0) & 0xffff) << 0) | \ @@ -190,8 +188,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUState *env, \ NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \ return a; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(uint64_t a, uint64_t b) \ { \ a = \ (((a >> SH0) & 0xffffffff) << 0) | \ @@ -200,8 +197,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUState *env, \ NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \ return a; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(uint64_t x) \ { \ x = \ (((x >> SH0) & 0xff) << 0) | \ @@ -213,8 +209,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUState *env, \ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ return x; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(uint64_t x) \ { \ x = \ (((x >> SH0) & 0xffff) << 0) | \ @@ -223,15 +218,13 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUState *env, \ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ return x; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(uint64_t x) \ { \ x = (((x >> SH0) & 0xffffffff) << 0); \ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ return x; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(uint64_t x) \ { \ x = \ ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \ @@ -243,8 +236,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUState *env, \ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \ return x; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(uint64_t x) \ { \ x = \ ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \ @@ -253,8 +245,7 @@ uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUState *env, \ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \ return x; \ } \ -uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUState *env, \ - uint64_t x) \ +uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(uint64_t x) \ { \ x = EXTEND32((x >> SH0) & 0xffffffff); \ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \ @@ -264,8 +255,7 @@ IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) #define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ -uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(uint64_t a, uint64_t b) \ { \ a = \ CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ @@ -279,8 +269,7 @@ uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUState *env, \ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \ return a; \ } \ -uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(uint64_t a, uint64_t b) \ { \ a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ @@ -289,8 +278,7 @@ uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUState *env, \ NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \ return a; \ } \ -uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUState *env, \ - uint64_t a, uint64_t b) \ +uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(uint64_t a, uint64_t b) \ { \ a = CMP(0, Tl, O, 0xffffffff) | \ CMP(32, Tl, O, 0xffffffff); \ @@ -329,7 +317,7 @@ IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) #define AVGB(SHR) ((( \ ((a >> SHR) & 0xff) + ((b >> SHR) & 0xff) + round) >> 1) << SHR) #define IWMMXT_OP_AVGB(r) \ -uint64_t HELPER(iwmmxt_avgb##r)(CPUState *env, uint64_t a, uint64_t b) \ +uint64_t HELPER(iwmmxt_avgb##r)(uint64_t a, uint64_t b) \ { \ const int round = r; \ a = AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | \ @@ -353,7 +341,7 @@ IWMMXT_OP_AVGB(1) #define AVGW(SHR) ((( \ ((a >> SHR) & 0xffff) + ((b >> SHR) & 0xffff) + round) >> 1) << SHR) #define IWMMXT_OP_AVGW(r) \ -uint64_t HELPER(iwmmxt_avgw##r)(CPUState *env, uint64_t a, uint64_t b) \ +uint64_t HELPER(iwmmxt_avgw##r)(uint64_t a, uint64_t b) \ { \ const int round = r; \ a = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); \ @@ -464,7 +452,7 @@ uint32_t HELPER(iwmmxt_msbl)(uint64_t x) } /* FIXME: Split wCASF setting into a separate op to avoid env use. */ -uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_srlw)(uint64_t x, uint32_t n) { x = (((x & (0xffffll << 0)) >> n) & (0xffffll << 0)) | (((x & (0xffffll << 16)) >> n) & (0xffffll << 16)) | @@ -476,7 +464,7 @@ uint64_t HELPER(iwmmxt_srlw)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_srll)(uint64_t x, uint32_t n) { x = ((x & (0xffffffffll << 0)) >> n) | ((x >> n) & (0xffffffffll << 32)); @@ -485,14 +473,14 @@ uint64_t HELPER(iwmmxt_srll)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_srlq)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_srlq)(uint64_t x, uint32_t n) { x >>= n; env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); return x; } -uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_sllw)(uint64_t x, uint32_t n) { x = (((x & (0xffffll << 0)) << n) & (0xffffll << 0)) | (((x & (0xffffll << 16)) << n) & (0xffffll << 16)) | @@ -504,7 +492,7 @@ uint64_t HELPER(iwmmxt_sllw)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_slll)(uint64_t x, uint32_t n) { x = ((x << n) & (0xffffffffll << 0)) | ((x & (0xffffffffll << 32)) << n); @@ -513,14 +501,14 @@ uint64_t HELPER(iwmmxt_slll)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_sllq)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_sllq)(uint64_t x, uint32_t n) { x <<= n; env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); return x; } -uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_sraw)(uint64_t x, uint32_t n) { x = ((uint64_t) ((EXTEND16(x >> 0) >> n) & 0xffff) << 0) | ((uint64_t) ((EXTEND16(x >> 16) >> n) & 0xffff) << 16) | @@ -532,7 +520,7 @@ uint64_t HELPER(iwmmxt_sraw)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_sral)(uint64_t x, uint32_t n) { x = (((EXTEND32(x >> 0) >> n) & 0xffffffff) << 0) | (((EXTEND32(x >> 32) >> n) & 0xffffffff) << 32); @@ -541,14 +529,14 @@ uint64_t HELPER(iwmmxt_sral)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_sraq)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_sraq)(uint64_t x, uint32_t n) { x = (int64_t) x >> n; env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); return x; } -uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_rorw)(uint64_t x, uint32_t n) { x = ((((x & (0xffffll << 0)) >> n) | ((x & (0xffffll << 0)) << (16 - n))) & (0xffffll << 0)) | @@ -564,7 +552,7 @@ uint64_t HELPER(iwmmxt_rorw)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_rorl)(uint64_t x, uint32_t n) { x = ((x & (0xffffffffll << 0)) >> n) | ((x >> n) & (0xffffffffll << 32)) | @@ -575,14 +563,14 @@ uint64_t HELPER(iwmmxt_rorl)(CPUState *env, uint64_t x, uint32_t n) return x; } -uint64_t HELPER(iwmmxt_rorq)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_rorq)(uint64_t x, uint32_t n) { x = (x >> n) | (x << (64 - n)); env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x); return x; } -uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n) +uint64_t HELPER(iwmmxt_shufh)(uint64_t x, uint32_t n) { x = (((x >> ((n << 4) & 0x30)) & 0xffff) << 0) | (((x >> ((n << 2) & 0x30)) & 0xffff) << 16) | @@ -595,7 +583,7 @@ uint64_t HELPER(iwmmxt_shufh)(CPUState *env, uint64_t x, uint32_t n) } /* TODO: Unsigned-Saturation */ -uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packuw)(uint64_t a, uint64_t b) { a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | @@ -609,7 +597,7 @@ uint64_t HELPER(iwmmxt_packuw)(CPUState *env, uint64_t a, uint64_t b) return a; } -uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packul)(uint64_t a, uint64_t b) { a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); @@ -619,7 +607,7 @@ uint64_t HELPER(iwmmxt_packul)(CPUState *env, uint64_t a, uint64_t b) return a; } -uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packuq)(uint64_t a, uint64_t b) { a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = @@ -628,7 +616,7 @@ uint64_t HELPER(iwmmxt_packuq)(CPUState *env, uint64_t a, uint64_t b) } /* TODO: Signed-Saturation */ -uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packsw)(uint64_t a, uint64_t b) { a = (((a >> 0) & 0xff) << 0) | (((a >> 16) & 0xff) << 8) | (((a >> 32) & 0xff) << 16) | (((a >> 48) & 0xff) << 24) | @@ -642,7 +630,7 @@ uint64_t HELPER(iwmmxt_packsw)(CPUState *env, uint64_t a, uint64_t b) return a; } -uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packsl)(uint64_t a, uint64_t b) { a = (((a >> 0) & 0xffff) << 0) | (((a >> 32) & 0xffff) << 16) | (((b >> 0) & 0xffff) << 32) | (((b >> 32) & 0xffff) << 48); @@ -652,7 +640,7 @@ uint64_t HELPER(iwmmxt_packsl)(CPUState *env, uint64_t a, uint64_t b) return a; } -uint64_t HELPER(iwmmxt_packsq)(CPUState *env, uint64_t a, uint64_t b) +uint64_t HELPER(iwmmxt_packsq)(uint64_t a, uint64_t b) { a = (a & 0xffffffff) | ((b & 0xffffffff) << 32); env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = diff --git a/target-arm/translate.c b/target-arm/translate.c index 53c40acca9..c6cb39ad2b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1159,22 +1159,15 @@ static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \ } -#define IWMMXT_OP_ENV(name) \ -static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \ -{ \ - iwmmxt_load_reg(cpu_V1, rn); \ - gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \ -} +#define IWMMXT_OP_SIZE(name) \ +IWMMXT_OP(name##b) \ +IWMMXT_OP(name##w) \ +IWMMXT_OP(name##l) -#define IWMMXT_OP_ENV_SIZE(name) \ -IWMMXT_OP_ENV(name##b) \ -IWMMXT_OP_ENV(name##w) \ -IWMMXT_OP_ENV(name##l) - -#define IWMMXT_OP_ENV1(name) \ +#define IWMMXT_OP_1(name) \ static inline void gen_op_iwmmxt_##name##_M0(void) \ { \ - gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \ + gen_helper_iwmmxt_##name(cpu_M0, cpu_M0); \ } IWMMXT_OP(maddsq) @@ -1188,51 +1181,51 @@ IWMMXT_OP(muluhw) IWMMXT_OP(macsw) IWMMXT_OP(macuw) -IWMMXT_OP_ENV_SIZE(unpackl) -IWMMXT_OP_ENV_SIZE(unpackh) +IWMMXT_OP_SIZE(unpackl) +IWMMXT_OP_SIZE(unpackh) -IWMMXT_OP_ENV1(unpacklub) -IWMMXT_OP_ENV1(unpackluw) -IWMMXT_OP_ENV1(unpacklul) -IWMMXT_OP_ENV1(unpackhub) -IWMMXT_OP_ENV1(unpackhuw) -IWMMXT_OP_ENV1(unpackhul) -IWMMXT_OP_ENV1(unpacklsb) -IWMMXT_OP_ENV1(unpacklsw) -IWMMXT_OP_ENV1(unpacklsl) -IWMMXT_OP_ENV1(unpackhsb) -IWMMXT_OP_ENV1(unpackhsw) -IWMMXT_OP_ENV1(unpackhsl) +IWMMXT_OP_1(unpacklub) +IWMMXT_OP_1(unpackluw) +IWMMXT_OP_1(unpacklul) +IWMMXT_OP_1(unpackhub) +IWMMXT_OP_1(unpackhuw) +IWMMXT_OP_1(unpackhul) +IWMMXT_OP_1(unpacklsb) +IWMMXT_OP_1(unpacklsw) +IWMMXT_OP_1(unpacklsl) +IWMMXT_OP_1(unpackhsb) +IWMMXT_OP_1(unpackhsw) +IWMMXT_OP_1(unpackhsl) -IWMMXT_OP_ENV_SIZE(cmpeq) -IWMMXT_OP_ENV_SIZE(cmpgtu) -IWMMXT_OP_ENV_SIZE(cmpgts) +IWMMXT_OP_SIZE(cmpeq) +IWMMXT_OP_SIZE(cmpgtu) +IWMMXT_OP_SIZE(cmpgts) -IWMMXT_OP_ENV_SIZE(mins) -IWMMXT_OP_ENV_SIZE(minu) -IWMMXT_OP_ENV_SIZE(maxs) -IWMMXT_OP_ENV_SIZE(maxu) +IWMMXT_OP_SIZE(mins) +IWMMXT_OP_SIZE(minu) +IWMMXT_OP_SIZE(maxs) +IWMMXT_OP_SIZE(maxu) -IWMMXT_OP_ENV_SIZE(subn) -IWMMXT_OP_ENV_SIZE(addn) -IWMMXT_OP_ENV_SIZE(subu) -IWMMXT_OP_ENV_SIZE(addu) -IWMMXT_OP_ENV_SIZE(subs) -IWMMXT_OP_ENV_SIZE(adds) +IWMMXT_OP_SIZE(subn) +IWMMXT_OP_SIZE(addn) +IWMMXT_OP_SIZE(subu) +IWMMXT_OP_SIZE(addu) +IWMMXT_OP_SIZE(subs) +IWMMXT_OP_SIZE(adds) -IWMMXT_OP_ENV(avgb0) -IWMMXT_OP_ENV(avgb1) -IWMMXT_OP_ENV(avgw0) -IWMMXT_OP_ENV(avgw1) +IWMMXT_OP(avgb0) +IWMMXT_OP(avgb1) +IWMMXT_OP(avgw0) +IWMMXT_OP(avgw1) IWMMXT_OP(msadb) -IWMMXT_OP_ENV(packuw) -IWMMXT_OP_ENV(packul) -IWMMXT_OP_ENV(packuq) -IWMMXT_OP_ENV(packsw) -IWMMXT_OP_ENV(packsl) -IWMMXT_OP_ENV(packsq) +IWMMXT_OP(packuw) +IWMMXT_OP(packul) +IWMMXT_OP(packuq) +IWMMXT_OP(packsw) +IWMMXT_OP(packsl) +IWMMXT_OP(packsq) static void gen_op_iwmmxt_set_mup(void) { @@ -1966,13 +1959,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srlw(cpu_M0, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srll(cpu_M0, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_srlq(cpu_M0, cpu_M0, tmp); break; } tcg_temp_free_i32(tmp); @@ -1994,13 +1987,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sraw(cpu_M0, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sral(cpu_M0, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sraq(cpu_M0, cpu_M0, tmp); break; } tcg_temp_free_i32(tmp); @@ -2022,13 +2015,13 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) } switch ((insn >> 22) & 3) { case 1: - gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sllw(cpu_M0, cpu_M0, tmp); break; case 2: - gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_slll(cpu_M0, cpu_M0, tmp); break; case 3: - gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_sllq(cpu_M0, cpu_M0, tmp); break; } tcg_temp_free_i32(tmp); @@ -2050,21 +2043,21 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp); return 1; } - gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorw(cpu_M0, cpu_M0, tmp); break; case 2: if (gen_iwmmxt_shift(insn, 0x1f, tmp)) { tcg_temp_free_i32(tmp); return 1; } - gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorl(cpu_M0, cpu_M0, tmp); break; case 3: if (gen_iwmmxt_shift(insn, 0x3f, tmp)) { tcg_temp_free_i32(tmp); return 1; } - gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_rorq(cpu_M0, cpu_M0, tmp); break; } tcg_temp_free_i32(tmp); @@ -2198,7 +2191,7 @@ static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) rd0 = (insn >> 16) & 0xf; gen_op_iwmmxt_movq_M0_wRn(rd0); tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f)); - gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp); + gen_helper_iwmmxt_shufh(cpu_M0, cpu_M0, tmp); tcg_temp_free(tmp); gen_op_iwmmxt_movq_wRn_M0(wrd); gen_op_iwmmxt_set_mup(); From cc49f2178041d5754368d4b62cb56b735aafbe9f Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 4 Apr 2011 11:46:35 +0100 Subject: [PATCH 098/386] target-arm: Make Neon helper routines use correct FP status Make the Neon helper routines use the correct FP status from the CPUEnv rather than using a dummy static one. This means they will correctly handle denormals and NaNs and will set FPSCR exception bits properly. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 315e69337e..c3ac96a099 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -18,8 +18,7 @@ #define SET_QC() env->vfp.xregs[ARM_VFP_FPSCR] = CPSR_Q -static float_status neon_float_status; -#define NFS &neon_float_status +#define NFS (&env->vfp.standard_fp_status) #define NEON_TYPE1(name, type) \ typedef struct \ From c8f930c0eeb696d638f4d4bf654e955fa44ff40f Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 4 Apr 2011 12:09:22 +0100 Subject: [PATCH 099/386] cpu-all.h: Remove unnecessary target-specific ifdef for CPU_QuadU CPU_QuadU isn't used on all targets, but there's no harm in defining the typedef anyway. It only needs to be guarded by CONFIG_SOFTFLOAT, because softfloat-native doesn't have a float128 type. This avoids the need for every new target which uses CPU_QuadU to add itself to an #ifdef in what ought to be target-agnostic code. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- cpu-all.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 4cc445ffc3..dc0f2f02ab 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -138,11 +138,10 @@ typedef union { uint64_t ll; } CPU_DoubleU; -#if defined(TARGET_SPARC) || defined(TARGET_S390X) +#if defined(CONFIG_SOFTFLOAT) typedef union { float128 q; -#if defined(HOST_WORDS_BIGENDIAN) \ - || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) +#if defined(HOST_WORDS_BIGENDIAN) struct { uint32_t upmost; uint32_t upper; From 99123e139d698bee1531e8887e1a58207a52082b Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@gentoo.org> Date: Thu, 7 Apr 2011 01:12:28 -0400 Subject: [PATCH 100/386] configure: add --version flag Standard autoconf scripts include a --version flag so people can easily query things. Add this to qemu's configure so it too can integrate with build systems that have standard autotool helpers. Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index faaed60540..ae97e11a97 100755 --- a/configure +++ b/configure @@ -494,6 +494,8 @@ for opt do case "$opt" in --help|-h) show_help=yes ;; + --version|-V) exec cat $source_path/VERSION + ;; --prefix=*) prefix="$optarg" ;; --interp-prefix=*) interp_prefix="$optarg" From 3b8e6a2db1946b5f21e69fde31b39f43367f1928 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> Date: Tue, 5 Apr 2011 13:00:36 +0200 Subject: [PATCH 101/386] exec: Handle registrations of the entire address space Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- exec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index 964ce318fb..983c0db3f7 100644 --- a/exec.c +++ b/exec.c @@ -2611,6 +2611,7 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, ram_addr_t orig_size = size; subpage_t *subpage; + assert(size); cpu_notify_set_memory(start_addr, size, phys_offset); if (phys_offset == IO_MEM_UNASSIGNED) { @@ -2619,7 +2620,9 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, region_offset &= TARGET_PAGE_MASK; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + (target_phys_addr_t)size; - for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { + + addr = start_addr; + do { p = phys_page_find(addr >> TARGET_PAGE_BITS); if (p && p->phys_offset != IO_MEM_UNASSIGNED) { ram_addr_t orig_memory = p->phys_offset; @@ -2671,7 +2674,8 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, } } region_offset += TARGET_PAGE_SIZE; - } + addr += TARGET_PAGE_SIZE; + } while (addr != end_addr); /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ From f6ec953ca329d4509e5a1a1ff051365fccdbb6b7 Mon Sep 17 00:00:00 2001 From: Feiran Zheng <famcool@gmail.com> Date: Tue, 29 Mar 2011 09:00:15 +0800 Subject: [PATCH 102/386] hw/xen_disk: ioreq not finished on error Bug fix: routines 'ioreq_runio_qemu_sync' and 'ioreq_runio_qemu_aio' won't call 'ioreq_unmap' or 'ioreq_finish' on errors, leaving ioreq in the blkdev->inflight list and a leak. Signed-off-by: Feiran Zheng <famcool@gmail.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/xen_disk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 445bf03aa0..558bf8ae25 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -310,7 +310,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq) off_t pos; if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) - goto err; + goto err_no_map; if (ioreq->presync) bdrv_flush(blkdev->bs); @@ -364,6 +364,9 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq) return 0; err: + ioreq_unmap(ioreq); +err_no_map: + ioreq_finish(ioreq); ioreq->status = BLKIF_RSP_ERROR; return -1; } @@ -393,7 +396,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) struct XenBlkDev *blkdev = ioreq->blkdev; if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) - goto err; + goto err_no_map; ioreq->aio_inflight++; if (ioreq->presync) @@ -427,6 +430,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) return 0; err: + ioreq_unmap(ioreq); +err_no_map: + ioreq_finish(ioreq); ioreq->status = BLKIF_RSP_ERROR; return -1; } From d22b2f41c470067758b3636a01b452dfeda7069f Mon Sep 17 00:00:00 2001 From: Ryan Harper <ryanh@us.ibm.com> Date: Tue, 29 Mar 2011 20:51:47 -0500 Subject: [PATCH 103/386] Do not delete BlockDriverState when deleting the drive When removing a drive from the host-side via drive_del we currently have the following path: drive_del qemu_aio_flush() bdrv_close() // zaps bs->drv, which makes any subsequent I/O get // dropped. Works as designed drive_uninit() bdrv_delete() // frees the bs. Since the device is still connected to // bs, any subsequent I/O is a use-after-free. The value of bs->drv becomes unpredictable on free. As long as it remains null, I/O still gets dropped, however it could become non-null at any point after the free resulting SEGVs or other QEMU state corruption. To resolve this issue as simply as possible, we can chose to not actually delete the BlockDriverState pointer. Since bdrv_close() handles setting the drv pointer to NULL, we just need to remove the BlockDriverState from the QLIST that is used to enumerate the block devices. This is currently handled within bdrv_delete, so move this into its own function, bdrv_make_anon(). The result is that we can now invoke drive_del, this closes the file descriptors and sets BlockDriverState->drv to NULL which prevents futher IO to the device, and since we do not free BlockDriverState, we don't have to worry about the copy retained in the block devices. We also don't attempt to remove the qdev property since we are no longer deleting the BlockDriverState on drives with associated drives. This also allows for removing Drives with no devices associated either. Reported-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Ryan Harper <ryanh@us.ibm.com> Acked-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block.c | 14 +++++++++++--- block.h | 1 + blockdev.c | 25 ++++++++----------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index c8e2f97614..c93ec6d418 100644 --- a/block.c +++ b/block.c @@ -697,14 +697,22 @@ void bdrv_close_all(void) } } +/* make a BlockDriverState anonymous by removing from bdrv_state list. + Also, NULL terminate the device_name to prevent double remove */ +void bdrv_make_anon(BlockDriverState *bs) +{ + if (bs->device_name[0] != '\0') { + QTAILQ_REMOVE(&bdrv_states, bs, list); + } + bs->device_name[0] = '\0'; +} + void bdrv_delete(BlockDriverState *bs) { assert(!bs->peer); /* remove from list, if necessary */ - if (bs->device_name[0] != '\0') { - QTAILQ_REMOVE(&bdrv_states, bs, list); - } + bdrv_make_anon(bs); bdrv_close(bs); if (bs->file != NULL) { diff --git a/block.h b/block.h index 5d78fc0ed7..52e9cad55c 100644 --- a/block.h +++ b/block.h @@ -66,6 +66,7 @@ int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options); int bdrv_create_file(const char* filename, QEMUOptionParameter *options); BlockDriverState *bdrv_new(const char *device_name); +void bdrv_make_anon(BlockDriverState *bs); void bdrv_delete(BlockDriverState *bs); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); int bdrv_open(BlockDriverState *bs, const char *filename, int flags, diff --git a/blockdev.c b/blockdev.c index bbe92fe196..5429621f0c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -737,8 +737,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) { const char *id = qdict_get_str(qdict, "id"); BlockDriverState *bs; - BlockDriverState **ptr; - Property *prop; bs = bdrv_find(id); if (!bs) { @@ -755,24 +753,17 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) bdrv_flush(bs); bdrv_close(bs); - /* clean up guest state from pointing to host resource by - * finding and removing DeviceState "drive" property */ + /* if we have a device associated with this BlockDriverState (bs->peer) + * then we need to make the drive anonymous until the device + * can be removed. If this is a drive with no device backing + * then we can just get rid of the block driver state right here. + */ if (bs->peer) { - for (prop = bs->peer->info->props; prop && prop->name; prop++) { - if (prop->info->type == PROP_TYPE_DRIVE) { - ptr = qdev_get_prop_ptr(bs->peer, prop); - if (*ptr == bs) { - bdrv_detach(bs, bs->peer); - *ptr = NULL; - break; - } - } - } + bdrv_make_anon(bs); + } else { + drive_uninit(drive_get_by_blockdev(bs)); } - /* clean up host side */ - drive_uninit(drive_get_by_blockdev(bs)); - return 0; } From b8c6d0958943c96ca9401961a1200568c7ec0268 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Tue, 29 Mar 2011 20:04:40 +0100 Subject: [PATCH 104/386] trace: Trace bdrv_set_locked() It can be handy to know when the guest locks/unlocks the CD-ROM tray. This trace event makes that possible. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block.c | 2 ++ trace-events | 1 + 2 files changed, 3 insertions(+) diff --git a/block.c b/block.c index c93ec6d418..d8da3b09d3 100644 --- a/block.c +++ b/block.c @@ -2817,6 +2817,8 @@ void bdrv_set_locked(BlockDriverState *bs, int locked) { BlockDriver *drv = bs->drv; + trace_bdrv_set_locked(bs, locked); + bs->locked = locked; if (drv && drv->bdrv_set_locked) { drv->bdrv_set_locked(bs, locked); diff --git a/trace-events b/trace-events index 06efdb7753..703b745bc4 100644 --- a/trace-events +++ b/trace-events @@ -54,6 +54,7 @@ disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d" disable bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" +disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d" # hw/virtio-blk.c disable virtio_blk_req_complete(void *req, int status) "req %p status %d" From 46a4e4e6085c1e5ae498e350009ff6d321d9ee67 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Tue, 29 Mar 2011 20:04:41 +0100 Subject: [PATCH 105/386] block: Do not cache device size for removable media The block layer caches the device size to avoid doing lseek(fd, 0, SEEK_END) every time this value is needed. For removable media the device size becomes stale if a new medium is inserted. This patch simply prevents device size caching for removable media. A smarter solution is to update the cached device size when a new medium is inserted. Given that there are currently bugs with CD-ROM media change I do not want to implement that approach until we've gotten things correct first. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index d8da3b09d3..f731c7afbf 100644 --- a/block.c +++ b/block.c @@ -1161,14 +1161,12 @@ int64_t bdrv_getlength(BlockDriverState *bs) if (!drv) return -ENOMEDIUM; - /* Fixed size devices use the total_sectors value for speed instead of - issuing a length query (like lseek) on each call. Also, legacy block - drivers don't provide a bdrv_getlength function and must use - total_sectors. */ - if (!bs->growable || !drv->bdrv_getlength) { - return bs->total_sectors * BDRV_SECTOR_SIZE; + if (bs->growable || bs->removable) { + if (drv->bdrv_getlength) { + return drv->bdrv_getlength(bs); + } } - return drv->bdrv_getlength(bs); + return bs->total_sectors * BDRV_SECTOR_SIZE; } /* return 0 as number of sectors if no device present or error */ From 6b837bc4a4d81861027c74f882d8c1d43f4ec30c Mon Sep 17 00:00:00 2001 From: Jes Sorensen <Jes.Sorensen@redhat.com> Date: Wed, 30 Mar 2011 14:16:25 +0200 Subject: [PATCH 106/386] qemu-img: Initial progress printing support This adds the basic infrastructure for supporting progress output on the command line, as well as progress support for qemu-img commands 'rebase' and 'convert'. Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- Makefile.objs | 2 +- qemu-common.h | 4 +++ qemu-img-cmds.hx | 4 +-- qemu-img.c | 38 +++++++++++++++++++-- qemu-progress.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 qemu-progress.c diff --git a/Makefile.objs b/Makefile.objs index c05f5e59be..94587e1740 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -14,7 +14,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o -block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o +block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o diff --git a/qemu-common.h b/qemu-common.h index 8ecb48820a..82e27c18d3 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -334,6 +334,10 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count); void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count, size_t skip); +void qemu_progress_init(int enabled, float min_skip); +void qemu_progress_end(void); +void qemu_progress_print(float percent, int max); + /* Convert a byte between binary and BCD. */ static inline uint8_t to_bcd(uint8_t val) { diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 6c7176f8b4..3072d383cf 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -28,7 +28,7 @@ STEXI ETEXI DEF("convert", img_convert, - "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") + "convert [-c] [-p] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") STEXI @item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI @@ -46,7 +46,7 @@ STEXI ETEXI DEF("rebase", img_rebase, - "rebase [-f fmt] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [-f fmt] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI @item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI diff --git a/qemu-img.c b/qemu-img.c index 7e3cc4cbd5..074388ce89 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -77,6 +77,7 @@ static void help(void) " match exactly. The image doesn't need a working backing file before\n" " rebasing in this case (useful for renaming the backing file)\n" " '-h' with or without a command shows this help and lists the supported formats\n" + " '-p' show progress of command (only certain commands)\n" "\n" "Parameters to snapshot subcommand:\n" " 'snapshot' is the name of the snapshot to create, apply or delete\n" @@ -567,6 +568,7 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n, static int img_convert(int argc, char **argv) { int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors; + int progress = 0; const char *fmt, *out_fmt, *out_baseimg, *out_filename; BlockDriver *drv, *proto_drv; BlockDriverState **bs = NULL, *out_bs = NULL; @@ -579,13 +581,14 @@ static int img_convert(int argc, char **argv) QEMUOptionParameter *out_baseimg_param; char *options = NULL; const char *snapshot_name = NULL; + float local_progress; fmt = NULL; out_fmt = "raw"; out_baseimg = NULL; compress = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:s:hce6o:"); + c = getopt(argc, argv, "f:O:B:s:hce6o:p"); if (c == -1) { break; } @@ -620,6 +623,9 @@ static int img_convert(int argc, char **argv) case 's': snapshot_name = optarg; break; + case 'p': + progress = 1; + break; } } @@ -642,6 +648,9 @@ static int img_convert(int argc, char **argv) goto out; } + qemu_progress_init(progress, 2.0); + qemu_progress_print(0, 100); + bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *)); total_sectors = 0; @@ -773,6 +782,11 @@ static int img_convert(int argc, char **argv) } cluster_sectors = cluster_size >> 9; sector_num = 0; + + nb_sectors = total_sectors; + local_progress = (float)100 / + (nb_sectors / MIN(nb_sectors, (cluster_sectors))); + for(;;) { int64_t bs_num; int remainder; @@ -832,6 +846,7 @@ static int img_convert(int argc, char **argv) } } sector_num += n; + qemu_progress_print(local_progress, 100); } /* signal EOF to align */ bdrv_write_compressed(out_bs, 0, NULL, 0); @@ -839,6 +854,10 @@ static int img_convert(int argc, char **argv) int has_zero_init = bdrv_has_zero_init(out_bs); sector_num = 0; // total number of sectors converted so far + nb_sectors = total_sectors - sector_num; + local_progress = (float)100 / + (nb_sectors / MIN(nb_sectors, (IO_BUF_SIZE / 512))); + for(;;) { nb_sectors = total_sectors - sector_num; if (nb_sectors <= 0) { @@ -912,9 +931,11 @@ static int img_convert(int argc, char **argv) n -= n1; buf1 += n1 * 512; } + qemu_progress_print(local_progress, 100); } } out: + qemu_progress_end(); free_option_parameters(create_options); free_option_parameters(param); qemu_free(buf); @@ -1184,6 +1205,7 @@ static int img_rebase(int argc, char **argv) const char *fmt, *out_basefmt, *out_baseimg; int c, flags, ret; int unsafe = 0; + int progress = 0; /* Parse commandline parameters */ fmt = NULL; @@ -1191,7 +1213,7 @@ static int img_rebase(int argc, char **argv) out_basefmt = NULL; for(;;) { - c = getopt(argc, argv, "uhf:F:b:"); + c = getopt(argc, argv, "uhf:F:b:p"); if (c == -1) { break; } @@ -1212,6 +1234,9 @@ static int img_rebase(int argc, char **argv) case 'u': unsafe = 1; break; + case 'p': + progress = 1; + break; } } @@ -1220,6 +1245,9 @@ static int img_rebase(int argc, char **argv) } filename = argv[optind++]; + qemu_progress_init(progress, 2.0); + qemu_progress_print(0, 100); + /* * Open the images. * @@ -1295,12 +1323,15 @@ static int img_rebase(int argc, char **argv) int n; uint8_t * buf_old; uint8_t * buf_new; + float local_progress; buf_old = qemu_malloc(IO_BUF_SIZE); buf_new = qemu_malloc(IO_BUF_SIZE); bdrv_get_geometry(bs, &num_sectors); + local_progress = (float)100 / + (num_sectors / MIN(num_sectors, (IO_BUF_SIZE / 512))); for (sector = 0; sector < num_sectors; sector += n) { /* How many sectors can we handle with the next read? */ @@ -1348,6 +1379,7 @@ static int img_rebase(int argc, char **argv) written += pnum; } + qemu_progress_print(local_progress, 100); } qemu_free(buf_old); @@ -1368,6 +1400,7 @@ static int img_rebase(int argc, char **argv) out_baseimg, strerror(-ret)); } + qemu_progress_print(100, 0); /* * TODO At this point it is possible to check if any clusters that are * allocated in the COW file are the same in the backing file. If so, they @@ -1375,6 +1408,7 @@ static int img_rebase(int argc, char **argv) * backing file, in case of a crash this would lead to corruption. */ out: + qemu_progress_end(); /* Cleanup */ if (!unsafe) { bdrv_delete(bs_old_backing); diff --git a/qemu-progress.c b/qemu-progress.c new file mode 100644 index 0000000000..656e065b1d --- /dev/null +++ b/qemu-progress.c @@ -0,0 +1,89 @@ +/* + * QEMU progress printing utility functions + * + * Copyright (C) 2011 Jes Sorensen <Jes.Sorensen@redhat.com> + * + * 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 "qemu-common.h" +#include "osdep.h" +#include "sysemu.h" +#include <stdio.h> + +struct progress_state { + int enabled; + float current; + float last_print; + float min_skip; +}; + +static struct progress_state state; + +/* + * Simple progress print function. + * @percent relative percent of current operation + * @max percent of total operation + */ +static void progress_simple_print(void) +{ + if (state.enabled) { + printf(" (%3.2f/100%%)\r", state.current); + fflush(stdout); + } +} + +static void progress_simple_end(void) +{ + if (state.enabled) { + printf("\n"); + } +} + +void qemu_progress_init(int enabled, float min_skip) +{ + state.enabled = enabled; + state.min_skip = min_skip; +} + +void qemu_progress_end(void) +{ + progress_simple_end(); +} + +void qemu_progress_print(float percent, int max) +{ + float current; + + if (max == 0) { + current = percent; + } else { + current = state.current + percent / 100 * max; + } + if (current > 100) { + current = 100; + } + state.current = current; + + if (current > (state.last_print + state.min_skip) || + (current == 100) || (current == 0)) { + state.last_print = state.current; + progress_simple_print(); + } +} From eb863add0204210480d018a3298ca22e4eadf3ce Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Thu, 31 Mar 2011 12:39:51 +0200 Subject: [PATCH 107/386] qemu-img rebase: Fix segfault if backing file can't be opened bdrv_delete must not be called for a NULL BlockDriverState. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- qemu-img.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 074388ce89..d9c2c12fa0 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1411,8 +1411,12 @@ out: qemu_progress_end(); /* Cleanup */ if (!unsafe) { - bdrv_delete(bs_old_backing); - bdrv_delete(bs_new_backing); + if (bs_old_backing != NULL) { + bdrv_delete(bs_old_backing); + } + if (bs_new_backing != NULL) { + bdrv_delete(bs_new_backing); + } } bdrv_delete(bs); From e2982c3a27ab4c0879e61de3c9c57b838f7d0966 Mon Sep 17 00:00:00 2001 From: Michael Tokarev <mjt@tls.msk.ru> Date: Wed, 30 Mar 2011 16:31:05 +0400 Subject: [PATCH 108/386] exit if -drive specified is invalid instead of ignoring the "wrong" -drive This fixes the problem when qemu continues even if -drive specification is somehow invalid, resulting in a mess. Applicable for both current master and for stable-0.14 (and the same issue exist 0.13 and 0.12 too). The prob can actually be seriuos: when you start guest with two drives and make an error in the specification of one of them, and the guest has something like a raid array on the two drives, guest may start failing that array or kick "missing" drives which may result in a mess - this is what actually happened to me, I did't want a resync at all, and a resync resulted in re-writing (and allocating) a 4TB virtual drive I used for testing, which in turn resulted in my filesystem filling up and whole thing failing badly. Yes it was just testing VM, I experimented with larger raid arrays, but the end result was quite, well, unexpected. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index de232b75e6..68c3b532bc 100644 --- a/vl.c +++ b/vl.c @@ -2102,7 +2102,9 @@ int main(int argc, char **argv, char **envp) HD_OPTS); break; case QEMU_OPTION_drive: - drive_def(optarg); + if (drive_def(optarg) == NULL) { + exit(1); + } break; case QEMU_OPTION_set: if (qemu_set_option(optarg) != 0) From 757179038c4884dc43c2ecd0f4da3facb24f262c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Sun, 3 Apr 2011 20:32:46 +0900 Subject: [PATCH 109/386] ide: consolidate drive_get(IF_IDE) factor out ide initialization to call drive_get(IF_IDE) Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide.h | 3 +++ hw/ide/core.c | 14 ++++++++++++++ hw/mips_fulong2e.c | 9 +-------- hw/mips_malta.c | 10 +--------- hw/mips_r4k.c | 10 +--------- hw/pc_piix.c | 10 +--------- hw/ppc_newworld.c | 11 ++--------- hw/ppc_oldworld.c | 11 +++-------- hw/ppc_prep.c | 10 +--------- hw/sun4u.c | 9 +-------- 10 files changed, 28 insertions(+), 69 deletions(-) diff --git a/hw/ide.h b/hw/ide.h index 73fb550574..34d9394bcc 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -28,4 +28,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, void ide_get_bs(BlockDriverState *bs[], BusState *qbus); +/* ide/core.c */ +void ide_drive_get(DriveInfo **hd, int max_bus); + #endif /* HW_IDE_H */ diff --git a/hw/ide/core.c b/hw/ide/core.c index 007a4ee0c9..c11d457b7a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2826,3 +2826,17 @@ const VMStateDescription vmstate_ide_bus = { VMSTATE_END_OF_LIST() } }; + +void ide_drive_get(DriveInfo **hd, int max_bus) +{ + int i; + + if (drive_get_max_bus(IF_IDE) >= max_bus) { + fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus); + exit(1); + } + + for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) { + hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + } +} diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index f5ae63980c..0e90d684b4 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -338,14 +338,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); /* South bridge */ - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } + ide_drive_get(hd, MAX_IDE_BUS); via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); if (via_devfn < 0) { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index d8baa6d7e3..bf0d76d03d 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -905,15 +905,7 @@ void mips_malta_init (ram_addr_t ram_size, pci_bus = gt64120_register(i8259); /* Southbridge */ - - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } + ide_drive_get(hd, MAX_IDE_BUS); piix4_devfn = piix4_init(pci_bus, 80); isa_bus_irqs(i8259); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 8feb46163f..2834a46d52 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -287,15 +287,7 @@ void mips_r4k_init (ram_addr_t ram_size, if (nd_table[0].vlan) isa_ne2000_init(0x300, 9, &nd_table[0]); - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } - + ide_drive_get(hd, MAX_IDE_BUS); for(i = 0; i < MAX_IDE_BUS; i++) isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[MAX_IDE_DEVS * i], diff --git a/hw/pc_piix.c b/hw/pc_piix.c index b3ede8941f..4d54ca1832 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -129,15 +129,7 @@ static void pc_init1(ram_addr_t ram_size, pci_nic_init_nofail(nd, "e1000", NULL); } - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } - + ide_drive_get(hd, MAX_IDE_BUS); if (pci_enabled) { PCIDevice *dev; dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index b9245f066a..86f1cfbee9 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -325,20 +325,13 @@ static void ppc_core99_init (ram_addr_t ram_size, for(i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } + ide_drive_get(hd, MAX_IDE_BUS); dbdma = DBDMA_init(&dbdma_mem_index); /* We only emulate 2 out of 3 IDE controllers for now */ ide_mem_index[0] = -1; - hd[0] = drive_get(IF_IDE, 0, 0); - hd[1] = drive_get(IF_IDE, 0, 1); ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); - hd[0] = drive_get(IF_IDE, 1, 0); - hd[1] = drive_get(IF_IDE, 1, 1); - ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]); + ide_mem_index[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]); /* cuda also initialize ADB */ if (machine_arch == ARCH_MAC99_U3) { diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 8a4e088a38..75a312742e 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -236,21 +236,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size, pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } + ide_drive_get(hd, MAX_IDE_BUS); /* First IDE channel is a MAC IDE on the MacIO bus */ - hd[0] = drive_get(IF_IDE, 0, 0); - hd[1] = drive_get(IF_IDE, 0, 1); dbdma = DBDMA_init(&dbdma_mem_index); ide_mem_index[0] = -1; ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]); /* Second IDE channel is a CMD646 on the PCI bus */ - hd[0] = drive_get(IF_IDE, 1, 0); - hd[1] = drive_get(IF_IDE, 1, 1); + hd[0] = hd[MAX_IDE_DEVS]; + hd[1] = hd[MAX_IDE_DEVS + 1]; hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 5615ef9ad8..0e9cfc24cd 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -681,15 +681,7 @@ static void ppc_prep_init (ram_addr_t ram_size, } } - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } - + ide_drive_get(hd, MAX_IDE_BUS); for(i = 0; i < MAX_IDE_BUS; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[2 * i], diff --git a/hw/sun4u.c b/hw/sun4u.c index dbb5a15066..5eb38cf27d 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -793,14 +793,7 @@ static void sun4uv_init(ram_addr_t RAM_size, for(i = 0; i < nb_nics; i++) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); - if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { - fprintf(stderr, "qemu: too many IDE bus\n"); - exit(1); - } - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, - i % MAX_IDE_DEVS); - } + ide_drive_get(hd, MAX_IDE_BUS); pci_cmd646_ide_init(pci_bus, hd, 1); From b2e3d87f043d02f2fba03c8463c9ad3d0478c869 Mon Sep 17 00:00:00 2001 From: Nick Thomas <nick@bytemark.co.uk> Date: Tue, 22 Feb 2011 15:44:51 +0000 Subject: [PATCH 110/386] NBD library: whitespace changes Signed-off-by: Nick Thomas <nick@bytemark.co.uk> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- nbd.c | 725 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 363 insertions(+), 362 deletions(-) diff --git a/nbd.c b/nbd.c index d8ebc4298f..abe0ecb17e 100644 --- a/nbd.c +++ b/nbd.c @@ -49,7 +49,7 @@ /* This is all part of the "official" NBD API */ -#define NBD_REPLY_SIZE (4 + 4 + 8) +#define NBD_REPLY_SIZE (4 + 4 + 8) #define NBD_REQUEST_MAGIC 0x25609513 #define NBD_REPLY_MAGIC 0x67446698 @@ -59,11 +59,11 @@ #define NBD_DO_IT _IO(0xab, 3) #define NBD_CLEAR_SOCK _IO(0xab, 4) #define NBD_CLEAR_QUE _IO(0xab, 5) -#define NBD_PRINT_DEBUG _IO(0xab, 6) -#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) +#define NBD_PRINT_DEBUG _IO(0xab, 6) +#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) #define NBD_DISCONNECT _IO(0xab, 8) -#define NBD_OPT_EXPORT_NAME (1 << 0) +#define NBD_OPT_EXPORT_NAME (1 << 0) /* That's all folks */ @@ -273,241 +273,241 @@ int unix_socket_outgoing(const char *path) int nbd_negotiate(int csock, off_t size) { - char buf[8 + 8 + 8 + 128]; + char buf[8 + 8 + 8 + 128]; - /* Negotiate - [ 0 .. 7] passwd ("NBDMAGIC") - [ 8 .. 15] magic (0x00420281861253) - [16 .. 23] size - [24 .. 151] reserved (0) - */ + /* Negotiate + [ 0 .. 7] passwd ("NBDMAGIC") + [ 8 .. 15] magic (0x00420281861253) + [16 .. 23] size + [24 .. 151] reserved (0) + */ - TRACE("Beginning negotiation."); - memcpy(buf, "NBDMAGIC", 8); - cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL); - cpu_to_be64w((uint64_t*)(buf + 16), size); - memset(buf + 24, 0, 128); + TRACE("Beginning negotiation."); + memcpy(buf, "NBDMAGIC", 8); + cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL); + cpu_to_be64w((uint64_t*)(buf + 16), size); + memset(buf + 24, 0, 128); - if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { - LOG("write failed"); - errno = EINVAL; - return -1; - } + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("write failed"); + errno = EINVAL; + return -1; + } - TRACE("Negotation succeeded."); + TRACE("Negotation succeeded."); - return 0; + return 0; } int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, off_t *size, size_t *blocksize) { - char buf[256]; - uint64_t magic, s; - uint16_t tmp; + char buf[256]; + uint64_t magic, s; + uint16_t tmp; - TRACE("Receiving negotation."); + TRACE("Receiving negotation."); - if (read_sync(csock, buf, 8) != 8) { - LOG("read failed"); - errno = EINVAL; - return -1; - } + if (read_sync(csock, buf, 8) != 8) { + LOG("read failed"); + errno = EINVAL; + return -1; + } - buf[8] = '\0'; - if (strlen(buf) == 0) { - LOG("server connection closed"); - errno = EINVAL; - return -1; - } + buf[8] = '\0'; + if (strlen(buf) == 0) { + LOG("server connection closed"); + errno = EINVAL; + return -1; + } - TRACE("Magic is %c%c%c%c%c%c%c%c", - qemu_isprint(buf[0]) ? buf[0] : '.', - qemu_isprint(buf[1]) ? buf[1] : '.', - qemu_isprint(buf[2]) ? buf[2] : '.', - qemu_isprint(buf[3]) ? buf[3] : '.', - qemu_isprint(buf[4]) ? buf[4] : '.', - qemu_isprint(buf[5]) ? buf[5] : '.', - qemu_isprint(buf[6]) ? buf[6] : '.', - qemu_isprint(buf[7]) ? buf[7] : '.'); + TRACE("Magic is %c%c%c%c%c%c%c%c", + qemu_isprint(buf[0]) ? buf[0] : '.', + qemu_isprint(buf[1]) ? buf[1] : '.', + qemu_isprint(buf[2]) ? buf[2] : '.', + qemu_isprint(buf[3]) ? buf[3] : '.', + qemu_isprint(buf[4]) ? buf[4] : '.', + qemu_isprint(buf[5]) ? buf[5] : '.', + qemu_isprint(buf[6]) ? buf[6] : '.', + qemu_isprint(buf[7]) ? buf[7] : '.'); - if (memcmp(buf, "NBDMAGIC", 8) != 0) { - LOG("Invalid magic received"); - errno = EINVAL; - return -1; - } + if (memcmp(buf, "NBDMAGIC", 8) != 0) { + LOG("Invalid magic received"); + errno = EINVAL; + return -1; + } - if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { - LOG("read failed"); - errno = EINVAL; - return -1; - } - magic = be64_to_cpu(magic); - TRACE("Magic is 0x%" PRIx64, magic); + if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + magic = be64_to_cpu(magic); + TRACE("Magic is 0x%" PRIx64, magic); - if (name) { - uint32_t reserved = 0; - uint32_t opt; - uint32_t namesize; + if (name) { + uint32_t reserved = 0; + uint32_t opt; + uint32_t namesize; - TRACE("Checking magic (opts_magic)"); - if (magic != 0x49484156454F5054LL) { - LOG("Bad magic received"); - errno = EINVAL; - return -1; - } - if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { - LOG("flags read failed"); - errno = EINVAL; - return -1; - } - *flags = be16_to_cpu(tmp) << 16; - /* reserved for future use */ - if (write_sync(csock, &reserved, sizeof(reserved)) != - sizeof(reserved)) { - LOG("write failed (reserved)"); - errno = EINVAL; - return -1; - } - /* write the export name */ - magic = cpu_to_be64(magic); - if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { - LOG("write failed (magic)"); - errno = EINVAL; - return -1; - } - opt = cpu_to_be32(NBD_OPT_EXPORT_NAME); - if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) { - LOG("write failed (opt)"); - errno = EINVAL; - return -1; - } - namesize = cpu_to_be32(strlen(name)); - if (write_sync(csock, &namesize, sizeof(namesize)) != - sizeof(namesize)) { - LOG("write failed (namesize)"); - errno = EINVAL; - return -1; - } - if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) { - LOG("write failed (name)"); - errno = EINVAL; - return -1; - } - } else { - TRACE("Checking magic (cli_magic)"); + TRACE("Checking magic (opts_magic)"); + if (magic != 0x49484156454F5054LL) { + LOG("Bad magic received"); + errno = EINVAL; + return -1; + } + if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { + LOG("flags read failed"); + errno = EINVAL; + return -1; + } + *flags = be16_to_cpu(tmp) << 16; + /* reserved for future use */ + if (write_sync(csock, &reserved, sizeof(reserved)) != + sizeof(reserved)) { + LOG("write failed (reserved)"); + errno = EINVAL; + return -1; + } + /* write the export name */ + magic = cpu_to_be64(magic); + if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { + LOG("write failed (magic)"); + errno = EINVAL; + return -1; + } + opt = cpu_to_be32(NBD_OPT_EXPORT_NAME); + if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) { + LOG("write failed (opt)"); + errno = EINVAL; + return -1; + } + namesize = cpu_to_be32(strlen(name)); + if (write_sync(csock, &namesize, sizeof(namesize)) != + sizeof(namesize)) { + LOG("write failed (namesize)"); + errno = EINVAL; + return -1; + } + if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) { + LOG("write failed (name)"); + errno = EINVAL; + return -1; + } + } else { + TRACE("Checking magic (cli_magic)"); - if (magic != 0x00420281861253LL) { - LOG("Bad magic received"); - errno = EINVAL; - return -1; - } - } + if (magic != 0x00420281861253LL) { + LOG("Bad magic received"); + errno = EINVAL; + return -1; + } + } - if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) { - LOG("read failed"); - errno = EINVAL; - return -1; - } - *size = be64_to_cpu(s); - *blocksize = 1024; - TRACE("Size is %" PRIu64, *size); + if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } + *size = be64_to_cpu(s); + *blocksize = 1024; + TRACE("Size is %" PRIu64, *size); - if (!name) { - if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) { - LOG("read failed (flags)"); - errno = EINVAL; - return -1; - } - *flags = be32_to_cpup(flags); - } else { - if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { - LOG("read failed (tmp)"); - errno = EINVAL; - return -1; - } - *flags |= be32_to_cpu(tmp); - } - if (read_sync(csock, &buf, 124) != 124) { - LOG("read failed (buf)"); - errno = EINVAL; - return -1; - } + if (!name) { + if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) { + LOG("read failed (flags)"); + errno = EINVAL; + return -1; + } + *flags = be32_to_cpup(flags); + } else { + if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { + LOG("read failed (tmp)"); + errno = EINVAL; + return -1; + } + *flags |= be32_to_cpu(tmp); + } + if (read_sync(csock, &buf, 124) != 124) { + LOG("read failed (buf)"); + errno = EINVAL; + return -1; + } return 0; } #ifndef _WIN32 int nbd_init(int fd, int csock, off_t size, size_t blocksize) { - TRACE("Setting block size to %lu", (unsigned long)blocksize); + TRACE("Setting block size to %lu", (unsigned long)blocksize); - if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) { - int serrno = errno; - LOG("Failed setting NBD block size"); - errno = serrno; - return -1; - } + if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) { + int serrno = errno; + LOG("Failed setting NBD block size"); + errno = serrno; + return -1; + } TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize)); - if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) { - int serrno = errno; - LOG("Failed setting size (in blocks)"); - errno = serrno; - return -1; - } + if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) { + int serrno = errno; + LOG("Failed setting size (in blocks)"); + errno = serrno; + return -1; + } - TRACE("Clearing NBD socket"); + TRACE("Clearing NBD socket"); - if (ioctl(fd, NBD_CLEAR_SOCK) == -1) { - int serrno = errno; - LOG("Failed clearing NBD socket"); - errno = serrno; - return -1; - } + if (ioctl(fd, NBD_CLEAR_SOCK) == -1) { + int serrno = errno; + LOG("Failed clearing NBD socket"); + errno = serrno; + return -1; + } - TRACE("Setting NBD socket"); + TRACE("Setting NBD socket"); - if (ioctl(fd, NBD_SET_SOCK, csock) == -1) { - int serrno = errno; - LOG("Failed to set NBD socket"); - errno = serrno; - return -1; - } + if (ioctl(fd, NBD_SET_SOCK, csock) == -1) { + int serrno = errno; + LOG("Failed to set NBD socket"); + errno = serrno; + return -1; + } - TRACE("Negotiation ended"); + TRACE("Negotiation ended"); - return 0; + return 0; } int nbd_disconnect(int fd) { - ioctl(fd, NBD_CLEAR_QUE); - ioctl(fd, NBD_DISCONNECT); - ioctl(fd, NBD_CLEAR_SOCK); - return 0; + ioctl(fd, NBD_CLEAR_QUE); + ioctl(fd, NBD_DISCONNECT); + ioctl(fd, NBD_CLEAR_SOCK); + return 0; } int nbd_client(int fd) { - int ret; - int serrno; + int ret; + int serrno; - TRACE("Doing NBD loop"); + TRACE("Doing NBD loop"); - ret = ioctl(fd, NBD_DO_IT); - serrno = errno; + ret = ioctl(fd, NBD_DO_IT); + serrno = errno; - TRACE("NBD loop returned %d: %s", ret, strerror(serrno)); + TRACE("NBD loop returned %d: %s", ret, strerror(serrno)); - TRACE("Clearing NBD queue"); - ioctl(fd, NBD_CLEAR_QUE); + TRACE("Clearing NBD queue"); + ioctl(fd, NBD_CLEAR_QUE); - TRACE("Clearing NBD socket"); - ioctl(fd, NBD_CLEAR_SOCK); + TRACE("Clearing NBD socket"); + ioctl(fd, NBD_CLEAR_SOCK); - errno = serrno; - return ret; + errno = serrno; + return ret; } #else int nbd_init(int fd, int csock, off_t size, size_t blocksize) @@ -531,235 +531,236 @@ int nbd_client(int fd) int nbd_send_request(int csock, struct nbd_request *request) { - uint8_t buf[4 + 4 + 8 + 8 + 4]; + uint8_t buf[4 + 4 + 8 + 8 + 4]; - cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC); - cpu_to_be32w((uint32_t*)(buf + 4), request->type); - cpu_to_be64w((uint64_t*)(buf + 8), request->handle); - cpu_to_be64w((uint64_t*)(buf + 16), request->from); - cpu_to_be32w((uint32_t*)(buf + 24), request->len); + cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC); + cpu_to_be32w((uint32_t*)(buf + 4), request->type); + cpu_to_be64w((uint64_t*)(buf + 8), request->handle); + cpu_to_be64w((uint64_t*)(buf + 16), request->from); + cpu_to_be32w((uint32_t*)(buf + 24), request->len); - TRACE("Sending request to client"); + TRACE("Sending request to client: " + "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}", + request->from, request->len, request->handle, request->type); - if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { - LOG("writing to socket failed"); - errno = EINVAL; - return -1; - } - return 0; + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + return 0; } - static int nbd_receive_request(int csock, struct nbd_request *request) { - uint8_t buf[4 + 4 + 8 + 8 + 4]; - uint32_t magic; + uint8_t buf[4 + 4 + 8 + 8 + 4]; + uint32_t magic; - if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { - LOG("read failed"); - errno = EINVAL; - return -1; - } + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } - /* Request - [ 0 .. 3] magic (NBD_REQUEST_MAGIC) - [ 4 .. 7] type (0 == READ, 1 == WRITE) - [ 8 .. 15] handle - [16 .. 23] from - [24 .. 27] len - */ + /* Request + [ 0 .. 3] magic (NBD_REQUEST_MAGIC) + [ 4 .. 7] type (0 == READ, 1 == WRITE) + [ 8 .. 15] handle + [16 .. 23] from + [24 .. 27] len + */ - magic = be32_to_cpup((uint32_t*)buf); - request->type = be32_to_cpup((uint32_t*)(buf + 4)); - request->handle = be64_to_cpup((uint64_t*)(buf + 8)); - request->from = be64_to_cpup((uint64_t*)(buf + 16)); - request->len = be32_to_cpup((uint32_t*)(buf + 24)); + magic = be32_to_cpup((uint32_t*)buf); + request->type = be32_to_cpup((uint32_t*)(buf + 4)); + request->handle = be64_to_cpup((uint64_t*)(buf + 8)); + request->from = be64_to_cpup((uint64_t*)(buf + 16)); + request->len = be32_to_cpup((uint32_t*)(buf + 24)); - TRACE("Got request: " - "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }", - magic, request->type, request->from, request->len); + TRACE("Got request: " + "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }", + magic, request->type, request->from, request->len); - if (magic != NBD_REQUEST_MAGIC) { - LOG("invalid magic (got 0x%x)", magic); - errno = EINVAL; - return -1; - } - return 0; + if (magic != NBD_REQUEST_MAGIC) { + LOG("invalid magic (got 0x%x)", magic); + errno = EINVAL; + return -1; + } + return 0; } int nbd_receive_reply(int csock, struct nbd_reply *reply) { - uint8_t buf[NBD_REPLY_SIZE]; - uint32_t magic; + uint8_t buf[NBD_REPLY_SIZE]; + uint32_t magic; - memset(buf, 0xAA, sizeof(buf)); + memset(buf, 0xAA, sizeof(buf)); - if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { - LOG("read failed"); - errno = EINVAL; - return -1; - } + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("read failed"); + errno = EINVAL; + return -1; + } - /* Reply - [ 0 .. 3] magic (NBD_REPLY_MAGIC) - [ 4 .. 7] error (0 == no error) - [ 7 .. 15] handle - */ + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ - magic = be32_to_cpup((uint32_t*)buf); - reply->error = be32_to_cpup((uint32_t*)(buf + 4)); - reply->handle = be64_to_cpup((uint64_t*)(buf + 8)); + magic = be32_to_cpup((uint32_t*)buf); + reply->error = be32_to_cpup((uint32_t*)(buf + 4)); + reply->handle = be64_to_cpup((uint64_t*)(buf + 8)); - TRACE("Got reply: " - "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }", - magic, reply->error, reply->handle); + TRACE("Got reply: " + "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }", + magic, reply->error, reply->handle); - if (magic != NBD_REPLY_MAGIC) { - LOG("invalid magic (got 0x%x)", magic); - errno = EINVAL; - return -1; - } - return 0; + if (magic != NBD_REPLY_MAGIC) { + LOG("invalid magic (got 0x%x)", magic); + errno = EINVAL; + return -1; + } + return 0; } static int nbd_send_reply(int csock, struct nbd_reply *reply) { - uint8_t buf[4 + 4 + 8]; + uint8_t buf[4 + 4 + 8]; - /* Reply - [ 0 .. 3] magic (NBD_REPLY_MAGIC) - [ 4 .. 7] error (0 == no error) - [ 7 .. 15] handle - */ - cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC); - cpu_to_be32w((uint32_t*)(buf + 4), reply->error); - cpu_to_be64w((uint64_t*)(buf + 8), reply->handle); + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ + cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC); + cpu_to_be32w((uint32_t*)(buf + 4), reply->error); + cpu_to_be64w((uint64_t*)(buf + 8), reply->handle); - TRACE("Sending response to client"); + TRACE("Sending response to client"); - if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { - LOG("writing to socket failed"); - errno = EINVAL; - return -1; - } - return 0; + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + return 0; } int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly, uint8_t *data, int data_size) { - struct nbd_request request; - struct nbd_reply reply; + struct nbd_request request; + struct nbd_reply reply; - TRACE("Reading request."); + TRACE("Reading request."); - if (nbd_receive_request(csock, &request) == -1) - return -1; + if (nbd_receive_request(csock, &request) == -1) + return -1; - if (request.len + NBD_REPLY_SIZE > data_size) { - LOG("len (%u) is larger than max len (%u)", - request.len + NBD_REPLY_SIZE, data_size); - errno = EINVAL; - return -1; - } + if (request.len + NBD_REPLY_SIZE > data_size) { + LOG("len (%u) is larger than max len (%u)", + request.len + NBD_REPLY_SIZE, data_size); + errno = EINVAL; + return -1; + } - if ((request.from + request.len) < request.from) { - LOG("integer overflow detected! " - "you're probably being attacked"); - errno = EINVAL; - return -1; - } + if ((request.from + request.len) < request.from) { + LOG("integer overflow detected! " + "you're probably being attacked"); + errno = EINVAL; + return -1; + } - if ((request.from + request.len) > size) { - LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 - ", Offset: %" PRIu64 "\n", + if ((request.from + request.len) > size) { + LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 + ", Offset: %" PRIu64 "\n", request.from, request.len, (uint64_t)size, dev_offset); - LOG("requested operation past EOF--bad client?"); - errno = EINVAL; - return -1; - } + LOG("requested operation past EOF--bad client?"); + errno = EINVAL; + return -1; + } - TRACE("Decoding type"); + TRACE("Decoding type"); - reply.handle = request.handle; - reply.error = 0; + reply.handle = request.handle; + reply.error = 0; - switch (request.type) { - case NBD_CMD_READ: - TRACE("Request type is READ"); + switch (request.type) { + case NBD_CMD_READ: + TRACE("Request type is READ"); - if (bdrv_read(bs, (request.from + dev_offset) / 512, - data + NBD_REPLY_SIZE, - request.len / 512) == -1) { - LOG("reading from file failed"); - errno = EINVAL; - return -1; - } - *offset += request.len; + if (bdrv_read(bs, (request.from + dev_offset) / 512, + data + NBD_REPLY_SIZE, + request.len / 512) == -1) { + LOG("reading from file failed"); + errno = EINVAL; + return -1; + } + *offset += request.len; - TRACE("Read %u byte(s)", request.len); + TRACE("Read %u byte(s)", request.len); - /* Reply - [ 0 .. 3] magic (NBD_REPLY_MAGIC) - [ 4 .. 7] error (0 == no error) - [ 7 .. 15] handle - */ + /* Reply + [ 0 .. 3] magic (NBD_REPLY_MAGIC) + [ 4 .. 7] error (0 == no error) + [ 7 .. 15] handle + */ - cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC); - cpu_to_be32w((uint32_t*)(data + 4), reply.error); - cpu_to_be64w((uint64_t*)(data + 8), reply.handle); + cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC); + cpu_to_be32w((uint32_t*)(data + 4), reply.error); + cpu_to_be64w((uint64_t*)(data + 8), reply.handle); - TRACE("Sending data to client"); + TRACE("Sending data to client"); - if (write_sync(csock, data, - request.len + NBD_REPLY_SIZE) != - request.len + NBD_REPLY_SIZE) { - LOG("writing to socket failed"); - errno = EINVAL; - return -1; - } - break; - case NBD_CMD_WRITE: - TRACE("Request type is WRITE"); + if (write_sync(csock, data, + request.len + NBD_REPLY_SIZE) != + request.len + NBD_REPLY_SIZE) { + LOG("writing to socket failed"); + errno = EINVAL; + return -1; + } + break; + case NBD_CMD_WRITE: + TRACE("Request type is WRITE"); - TRACE("Reading %u byte(s)", request.len); + TRACE("Reading %u byte(s)", request.len); - if (read_sync(csock, data, request.len) != request.len) { - LOG("reading from socket failed"); - errno = EINVAL; - return -1; - } + if (read_sync(csock, data, request.len) != request.len) { + LOG("reading from socket failed"); + errno = EINVAL; + return -1; + } - if (readonly) { - TRACE("Server is read-only, return error"); - reply.error = 1; - } else { - TRACE("Writing to device"); + if (readonly) { + TRACE("Server is read-only, return error"); + reply.error = 1; + } else { + TRACE("Writing to device"); - if (bdrv_write(bs, (request.from + dev_offset) / 512, - data, request.len / 512) == -1) { - LOG("writing to file failed"); - errno = EINVAL; - return -1; - } + if (bdrv_write(bs, (request.from + dev_offset) / 512, + data, request.len / 512) == -1) { + LOG("writing to file failed"); + errno = EINVAL; + return -1; + } - *offset += request.len; - } + *offset += request.len; + } - if (nbd_send_reply(csock, &reply) == -1) - return -1; - break; - case NBD_CMD_DISC: - TRACE("Request type is DISCONNECT"); - errno = 0; - return 1; - default: - LOG("invalid request type (%u) received", request.type); - errno = EINVAL; - return -1; - } + if (nbd_send_reply(csock, &reply) == -1) + return -1; + break; + case NBD_CMD_DISC: + TRACE("Request type is DISCONNECT"); + errno = 0; + return 1; + default: + LOG("invalid request type (%u) received", request.type); + errno = EINVAL; + return -1; + } - TRACE("Request/Reply complete"); + TRACE("Request/Reply complete"); - return 0; + return 0; } From b82eac92ac69a22243d341dde0213b7d15d7ba24 Mon Sep 17 00:00:00 2001 From: Nick Thomas <nick@bytemark.co.uk> Date: Tue, 22 Feb 2011 15:44:52 +0000 Subject: [PATCH 111/386] Set errno=ENOTSUP for attempts to use UNIX sockets on Windows platforms Signed-off-by: Nick Thomas <nick@bytemark.co.uk> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-sockets.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-sockets.c b/qemu-sockets.c index c526324998..eda1850e9c 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -627,24 +627,28 @@ int unix_connect(const char *path) int unix_listen_opts(QemuOpts *opts) { fprintf(stderr, "unix sockets are not available on windows\n"); + errno = ENOTSUP; return -1; } int unix_connect_opts(QemuOpts *opts) { fprintf(stderr, "unix sockets are not available on windows\n"); + errno = ENOTSUP; return -1; } int unix_listen(const char *path, char *ostr, int olen) { fprintf(stderr, "unix sockets are not available on windows\n"); + errno = ENOTSUP; return -1; } int unix_connect(const char *path) { fprintf(stderr, "unix sockets are not available on windows\n"); + errno = ENOTSUP; return -1; } From c12504ceef999c80b82c69c0154205ca23247fd5 Mon Sep 17 00:00:00 2001 From: Nick Thomas <nick@bytemark.co.uk> Date: Tue, 22 Feb 2011 15:44:53 +0000 Subject: [PATCH 112/386] NBD: Use qemu_socket functions to open TCP and UNIX sockets This commit has the side-effect of making the qemu-nbd binary capable of binding to IPv6 addresses. ("-b ::1", for instance). block/nbd.c fails to parse IPv6 IP addresses correctly at this point, but will work over IPv6 when given a hostname. It still works over IPv4 as before. We move the qemu-sockets object from the 'common' to the 'block' list in the Makefile. The common list includes the block list, so this is effectively a no-op for the rest of the code. We also add 32-bit 'magic' attributes to nbd_(request|reply) to facilitate calculating maximum request/response sizes later. Signed-off-by: Nick Thomas <nick@bytemark.co.uk> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- Makefile.objs | 4 +- nbd.c | 164 ++++++++++---------------------------------------- nbd.h | 9 ++- 3 files changed, 41 insertions(+), 136 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 94587e1740..44ce368d05 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -14,7 +14,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o -block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o +block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o @@ -94,7 +94,7 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o common-obj-y += bt-hci-csr.o -common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o +common-obj-y += buffered_file.o migration.o migration-tcp.o common-obj-y += qemu-char.o savevm.o #aio.o common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o diff --git a/nbd.c b/nbd.c index abe0ecb17e..0dcd86b52f 100644 --- a/nbd.c +++ b/nbd.c @@ -107,155 +107,55 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read) return offset; } +static void combine_addr(char *buf, size_t len, const char* address, + uint16_t port) +{ + /* If the address-part contains a colon, it's an IPv6 IP so needs [] */ + if (strstr(address, ":")) { + snprintf(buf, len, "[%s]:%u", address, port); + } else { + snprintf(buf, len, "%s:%u", address, port); + } +} + int tcp_socket_outgoing(const char *address, uint16_t port) { - int s; - struct in_addr in; - struct sockaddr_in addr; + char address_and_port[128]; + combine_addr(address_and_port, 128, address, port); + return tcp_socket_outgoing_spec(address_and_port); +} - s = socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) { - return -1; - } - - if (inet_aton(address, &in) == 0) { - struct hostent *ent; - - ent = gethostbyname(address); - if (ent == NULL) { - goto error; - } - - memcpy(&in, ent->h_addr, sizeof(in)); - } - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr.s_addr, &in, sizeof(in)); - - if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - goto error; - } - - return s; -error: - closesocket(s); - return -1; +int tcp_socket_outgoing_spec(const char *address_and_port) +{ + return inet_connect(address_and_port, SOCK_STREAM); } int tcp_socket_incoming(const char *address, uint16_t port) { - int s; - struct in_addr in; - struct sockaddr_in addr; - int opt; - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) { - return -1; - } - - if (inet_aton(address, &in) == 0) { - struct hostent *ent; - - ent = gethostbyname(address); - if (ent == NULL) { - goto error; - } - - memcpy(&in, ent->h_addr, sizeof(in)); - } - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr.s_addr, &in, sizeof(in)); - - opt = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &opt, sizeof(opt)) == -1) { - goto error; - } - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - goto error; - } - - if (listen(s, 128) == -1) { - goto error; - } - - return s; -error: - closesocket(s); - return -1; + char address_and_port[128]; + combine_addr(address_and_port, 128, address, port); + return tcp_socket_incoming_spec(address_and_port); +} + +int tcp_socket_incoming_spec(const char *address_and_port) +{ + char *ostr = NULL; + int olen = 0; + return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0); } -#ifndef _WIN32 int unix_socket_incoming(const char *path) { - int s; - struct sockaddr_un addr; + char *ostr = NULL; + int olen = 0; - s = socket(PF_UNIX, SOCK_STREAM, 0); - if (s == -1) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - pstrcpy(addr.sun_path, sizeof(addr.sun_path), path); - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - goto error; - } - - if (listen(s, 128) == -1) { - goto error; - } - - return s; -error: - closesocket(s); - return -1; + return unix_listen(path, ostr, olen); } int unix_socket_outgoing(const char *path) { - int s; - struct sockaddr_un addr; - - s = socket(PF_UNIX, SOCK_STREAM, 0); - if (s == -1) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - pstrcpy(addr.sun_path, sizeof(addr.sun_path), path); - - if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - goto error; - } - - return s; -error: - closesocket(s); - return -1; + return unix_connect(path); } -#else -int unix_socket_incoming(const char *path) -{ - errno = ENOTSUP; - return -1; -} - -int unix_socket_outgoing(const char *path) -{ - errno = ENOTSUP; - return -1; -} -#endif - /* Basic flow diff --git a/nbd.h b/nbd.h index fc3a5944f4..b38d0d08de 100644 --- a/nbd.h +++ b/nbd.h @@ -22,19 +22,22 @@ #include <sys/types.h> #include <qemu-common.h> + #include "block_int.h" struct nbd_request { + uint32_t magic; uint32_t type; uint64_t handle; uint64_t from; uint32_t len; -}; +} __attribute__ ((__packed__)); struct nbd_reply { + uint32_t magic; uint32_t error; uint64_t handle; -}; +} __attribute__ ((__packed__)); enum { NBD_CMD_READ = 0, @@ -47,6 +50,8 @@ enum { size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); int tcp_socket_outgoing(const char *address, uint16_t port); int tcp_socket_incoming(const char *address, uint16_t port); +int tcp_socket_outgoing_spec(const char *address_and_port); +int tcp_socket_incoming_spec(const char *address_and_port); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); From 33897dc7d62970acb731aab2ef2a65c225a8d64c Mon Sep 17 00:00:00 2001 From: Nick Thomas <nick@bytemark.co.uk> Date: Tue, 22 Feb 2011 15:44:54 +0000 Subject: [PATCH 113/386] NBD device: Separate out parsing configuration and opening sockets. We also change the way the file parameter is parsed so IPv6 IP addresses can be used, e.g.: "drive=nbd:[::1]:5000" Signed-off-by: Nick Thomas <nick@bytemark.co.uk> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/nbd.c | 175 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 64 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index c8dc763c6b..1d6b22561b 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -29,98 +29,154 @@ #include "qemu-common.h" #include "nbd.h" #include "module.h" +#include "qemu_socket.h" #include <sys/types.h> #include <unistd.h> #define EN_OPTSTR ":exportname=" +/* #define DEBUG_NBD */ + +#if defined(DEBUG_NBD) +#define logout(fmt, ...) \ + fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__) +#else +#define logout(fmt, ...) ((void)0) +#endif + typedef struct BDRVNBDState { int sock; off_t size; size_t blocksize; + char *export_name; /* An NBD server may export several devices */ + + /* If it begins with '/', this is a UNIX domain socket. Otherwise, + * it's a string of the form <hostname|ip4|\[ip6\]>:port + */ + char *host_spec; } BDRVNBDState; -static int nbd_open(BlockDriverState *bs, const char* filename, int flags) +static int nbd_config(BDRVNBDState *s, const char *filename, int flags) { - BDRVNBDState *s = bs->opaque; - uint32_t nbdflags; - char *file; - char *name; - const char *host; + char *export_name; + const char *host_spec; const char *unixpath; - int sock; - off_t size; - size_t blocksize; - int ret; int err = -EINVAL; file = qemu_strdup(filename); - name = strstr(file, EN_OPTSTR); - if (name) { - if (name[strlen(EN_OPTSTR)] == 0) { + export_name = strstr(file, EN_OPTSTR); + if (export_name) { + if (export_name[strlen(EN_OPTSTR)] == 0) { goto out; } - name[0] = 0; - name += strlen(EN_OPTSTR); + export_name[0] = 0; /* truncate 'file' */ + export_name += strlen(EN_OPTSTR); + s->export_name = qemu_strdup(export_name); } - if (!strstart(file, "nbd:", &host)) { + /* extract the host_spec - fail if it's not nbd:... */ + if (!strstart(file, "nbd:", &host_spec)) { goto out; } - if (strstart(host, "unix:", &unixpath)) { - - if (unixpath[0] != '/') { + /* are we a UNIX or TCP socket? */ + if (strstart(host_spec, "unix:", &unixpath)) { + if (unixpath[0] != '/') { /* We demand an absolute path*/ goto out; } - - sock = unix_socket_outgoing(unixpath); - + s->host_spec = qemu_strdup(unixpath); } else { - uint16_t port = NBD_DEFAULT_PORT; - char *p, *r; - char hostname[128]; - - pstrcpy(hostname, 128, host); - - p = strchr(hostname, ':'); - if (p != NULL) { - *p = '\0'; - p++; - - port = strtol(p, &r, 0); - if (r == p) { - goto out; - } - } - - sock = tcp_socket_outgoing(hostname, port); + s->host_spec = qemu_strdup(host_spec); } - if (sock == -1) { - err = -errno; - goto out; - } - - ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize); - if (ret == -1) { - err = -errno; - goto out; - } - - s->sock = sock; - s->size = size; - s->blocksize = blocksize; err = 0; out: qemu_free(file); + if (err != 0) { + qemu_free(s->export_name); + qemu_free(s->host_spec); + } return err; } +static int nbd_establish_connection(BlockDriverState *bs) +{ + BDRVNBDState *s = bs->opaque; + int sock; + int ret; + off_t size; + size_t blocksize; + uint32_t nbdflags; + + if (s->host_spec[0] == '/') { + sock = unix_socket_outgoing(s->host_spec); + } else { + sock = tcp_socket_outgoing_spec(s->host_spec); + } + + /* Failed to establish connection */ + if (sock == -1) { + logout("Failed to establish connection to NBD server\n"); + return -errno; + } + + /* NBD handshake */ + ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size, + &blocksize); + if (ret == -1) { + logout("Failed to negotiate with the NBD server\n"); + closesocket(sock); + return -errno; + } + + /* Now that we're connected, set the socket to be non-blocking */ + socket_set_nonblock(sock); + + s->sock = sock; + s->size = size; + s->blocksize = blocksize; + + logout("Established connection with NBD server\n"); + return 0; +} + +static void nbd_teardown_connection(BlockDriverState *bs) +{ + BDRVNBDState *s = bs->opaque; + struct nbd_request request; + + request.type = NBD_CMD_DISC; + request.handle = (uint64_t)(intptr_t)bs; + request.from = 0; + request.len = 0; + nbd_send_request(s->sock, &request); + + closesocket(s->sock); +} + +static int nbd_open(BlockDriverState *bs, const char* filename, int flags) +{ + BDRVNBDState *s = bs->opaque; + int result; + + /* Pop the config into our state object. Exit if invalid. */ + result = nbd_config(s, filename, flags); + if (result != 0) { + return result; + } + + /* establish TCP connection, return error if it fails + * TODO: Configurable retry-until-timeout behaviour. + */ + result = nbd_establish_connection(bs); + + return result; +} + static int nbd_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { @@ -183,16 +239,7 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num, static void nbd_close(BlockDriverState *bs) { - BDRVNBDState *s = bs->opaque; - struct nbd_request request; - - request.type = NBD_CMD_DISC; - request.handle = (uint64_t)(intptr_t)bs; - request.from = 0; - request.len = 0; - nbd_send_request(s->sock, &request); - - close(s->sock); + nbd_teardown_connection(bs); } static int64_t nbd_getlength(BlockDriverState *bs) From 7d905f716bea633f2836e1d661387983aacdc6d6 Mon Sep 17 00:00:00 2001 From: Jason Wang <jasowang@redhat.com> Date: Wed, 6 Apr 2011 18:34:31 +0800 Subject: [PATCH 114/386] floppy: save and restore DIR register We need to keep DIR register unchanged across migration, but currently it depends on the media_changed flags from block layer. Since we do not save/restore it and the bdrv_open() called in dest node may set the media_changed flag when trying to open floppy image, guest driver may think the floppy have changed after migration. To fix this, a new filed media_changed in FDrive strcutre was introduced in order to save and restore the it from block layer through pre_save/post_load callbacks. Signed-off-by: Jason Wang <jasowang@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/fdc.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/hw/fdc.c b/hw/fdc.c index 9fdbc750b5..edf0360d1b 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -36,6 +36,7 @@ #include "qdev-addr.h" #include "blockdev.h" #include "sysemu.h" +#include "block_int.h" /********************************************************/ /* debug Floppy devices */ @@ -82,6 +83,7 @@ typedef struct FDrive { uint8_t max_track; /* Nb of tracks */ uint16_t bps; /* Bytes per sector */ uint8_t ro; /* Is read-only */ + uint8_t media_changed; /* Is media changed */ } FDrive; static void fd_init(FDrive *drv) @@ -533,16 +535,63 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = { NULL, }; +static void fdrive_media_changed_pre_save(void *opaque) +{ + FDrive *drive = opaque; + + drive->media_changed = drive->bs->media_changed; +} + +static int fdrive_media_changed_post_load(void *opaque, int version_id) +{ + FDrive *drive = opaque; + + if (drive->bs != NULL) { + drive->bs->media_changed = drive->media_changed; + } + + /* User ejected the floppy when drive->bs == NULL */ + return 0; +} + +static bool fdrive_media_changed_needed(void *opaque) +{ + FDrive *drive = opaque; + + return (drive->bs != NULL && drive->bs->media_changed != 1); +} + +static const VMStateDescription vmstate_fdrive_media_changed = { + .name = "fdrive/media_changed", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = fdrive_media_changed_pre_save, + .post_load = fdrive_media_changed_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(media_changed, FDrive), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_fdrive = { .name = "fdrive", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(head, FDrive), VMSTATE_UINT8(track, FDrive), VMSTATE_UINT8(sect, FDrive), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_fdrive_media_changed, + .needed = &fdrive_media_changed_needed, + } , { + /* empty */ + } } }; From 155eb9aa09249874b4ff49e94c58595ad82d3abb Mon Sep 17 00:00:00 2001 From: Avishay Traeger <AVISHAY@il.ibm.com> Date: Wed, 6 Apr 2011 10:45:36 +0300 Subject: [PATCH 115/386] Fix integer overflow in block migration bandwidth calculation block_mig_state.reads is an int, and multiplying by BLOCK_SIZE yielded a negative number, resulting in a negative bandwidth (running on a 32-bit machine). Change order to avoid. Signed-off-by: Avishay Traeger <avishay@il.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block-migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-migration.c b/block-migration.c index 8218bac09c..576e55a6a3 100644 --- a/block-migration.c +++ b/block-migration.c @@ -140,7 +140,7 @@ static inline void add_avg_read_time(int64_t time) static inline long double compute_read_bwidth(void) { assert(block_mig_state.total_time != 0); - return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time; + return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE; } static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) From 62a2ab6aed53f30080c4151044c90945d16ac5fd Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Tue, 5 Apr 2011 07:54:04 +1000 Subject: [PATCH 116/386] usb-ccid: Spelling fixes While looking at David Gibson's build-fix for hw/usb-ccid.c, I noticed a spello in a comment on the following (unchanged) line. Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/usb-ccid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 44156cc1d8..079b4a2555 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -22,7 +22,7 @@ * "Universal Serial Bus, Device Class: Smart Card" * Specification for Integrated Circuit(s) Cards Interface Devices * - * Endianess note: from the spec (1.3) + * Endianness note: from the spec (1.3) * "Fields that are larger than a byte are stored in little endian" * * KNOWN BUGS @@ -172,7 +172,7 @@ enum { CLOCK_STATUS_RUNNING = 0, /* * 0 - Clock Running, 1 - Clock stopped in State L, 2 - H, - * 3 - unkonwn state. rest are RFU + * 3 - unknown state. rest are RFU */ }; @@ -1200,7 +1200,7 @@ void ccid_card_card_error(CCIDCardState *card, uint64_t error) s->bmCommandStatus = COMMAND_STATUS_FAILED; s->last_answer_error = error; DPRINTF(s, 1, "VSC_Error: %" PRIX64 "\n", s->last_answer_error); - /* TODO: these error's should be more verbose and propogated to the guest.*/ + /* TODO: these errors should be more verbose and propagated to the guest.*/ /* * We flush all pending answers on CardRemove message in ccid-card-passthru, * so check that first to not trigger abort @@ -1319,7 +1319,7 @@ static void ccid_pre_save(void *opaque) if (s->dev.attached) { /* * Migrating an open device, ignore reconnection CHR_EVENT to avoid an - * erronous detach. + * erroneous detach. */ s->migration_state = MIGRATION_MIGRATED; } From 3b29a1018457875a983bf10667cfe3a80c9d6dfd Mon Sep 17 00:00:00 2001 From: Michael Tokarev <mjt@tls.msk.ru> Date: Wed, 6 Apr 2011 17:51:59 +0400 Subject: [PATCH 117/386] qdev: Fix comment around qdev_init_nofail() In previous life qdev_init_nofail() used to call hw_error() which did register dump and other scary things. Now it calls error_report() and does a regular exit(1). Fix the comment to match reality. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/qdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/qdev.c b/hw/qdev.c index 1aa1ea0e26..9519f5dd57 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -358,7 +358,8 @@ int qdev_simple_unplug_cb(DeviceState *dev) return 0; } -/* Like qdev_init(), but terminate program via hw_error() instead of + +/* Like qdev_init(), but terminate program via error_report() instead of returning an error value. This is okay during machine creation. Don't use for hotplug, because there callers need to recover from failure. Exception: if you know the device's init() callback can't From fa227023f044552ec48ca851411dba2f268a912c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy <aik@ozlabs.ru> Date: Thu, 7 Apr 2011 13:02:02 +1000 Subject: [PATCH 118/386] spapr_llan: Fix warning when compiled with -dDEBUG Compiling with the DEBUG macro causes leaves hw/spapr_llan.c with an unused variable, which is treated as an error in the qemu build. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/spapr_llan.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 1d83fd58fd..ff3a78f729 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -274,9 +274,6 @@ static target_ulong h_register_logical_lan(CPUState *env, VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; vlan_bd_t filter_list_bd; -#ifdef DEBUG - target_ulong mac_address = args[4]; -#endif if (!dev) { return H_PARAMETER; From 4e37bfc1f0fcd17e48bfae233e0b45066830e126 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy <aik@ozlabs.ru> Date: Thu, 7 Apr 2011 13:02:03 +1000 Subject: [PATCH 119/386] virtio-9p: fixed LE-to-host conversion bug when QEMU is called from guest The 9p code already contains an attempt at the necessary endian conversions, but it's broken. The code which does conversion from host to guest does it correctly and this code was copied to the function which does guest to host conversion. However the copied code hasn't been correctly updated, so it first endian converts some garbage on the stack and then overwrites it with a field from incoming packet without conversion. The patch fixes the mistakes. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/virtio-9p.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 7c59988a51..7e29535672 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -696,25 +696,22 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) case 'w': { uint16_t val, *valp; valp = va_arg(ap, uint16_t *); - val = le16_to_cpupu(valp); offset += pdu_unpack(&val, pdu, offset, sizeof(val)); - *valp = val; + *valp = le16_to_cpu(val); break; } case 'd': { uint32_t val, *valp; valp = va_arg(ap, uint32_t *); - val = le32_to_cpupu(valp); offset += pdu_unpack(&val, pdu, offset, sizeof(val)); - *valp = val; + *valp = le32_to_cpu(val); break; } case 'q': { uint64_t val, *valp; valp = va_arg(ap, uint64_t *); - val = le64_to_cpup(valp); offset += pdu_unpack(&val, pdu, offset, sizeof(val)); - *valp = val; + *valp = le64_to_cpu(val); break; } case 'v': { From e54f17713f638189e79dac5ba0aa0ce606788777 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy <aik@ozlabs.ru> Date: Thu, 7 Apr 2011 13:02:04 +1000 Subject: [PATCH 120/386] virtio-balloon: fixed endianness bug in the config space The specification for the virtio balloon device requres that the values in the config space be encoded little-endian. This differs from most virtio things, where guest-native endian is the norm. Currently, the qemu virtio-balloon code correctly makes the conversion on get_config(), but doesn't on set_config for the 'actual' field. The kernel driver, on the other hand, correctly converts when setting the actual field, but does not convert when reading the config space. The upshot is that virtio-balloon will only work correctly if both host and guest are LE, making all the conversions nops. This patch corrects the qemu side, correctly doing host-native <-> LE conversions when accessing the config space. This won't break any setups that aren't already broken, and fixes the case of BE host, LE guest. Fixing the BE guest case will require kernel fixes as well. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/virtio-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 8adddeaa53..257baf8d4f 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -191,7 +191,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, VirtIOBalloon *dev = to_virtio_balloon(vdev); struct virtio_balloon_config config; memcpy(&config, config_data, 8); - dev->actual = config.actual; + dev->actual = le32_to_cpu(config.actual); } static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) From 52c050236eaa4f0b5e1d160cd66dc18106445c4d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <hch@lst.de> Date: Wed, 6 Apr 2011 20:28:34 +0200 Subject: [PATCH 121/386] virtio-blk: fail unaligned requests Like all block drivers virtio-blk should not allow small than block size granularity access. But given that the protocol specifies a byte unit length field we currently accept such requests, which cause qemu to abort() in lower layers. Add checks to the main read and write handlers to catch them early. Reported-by: Conor Murphy <conor_murphy_virt@hotmail.com> Tested-by: Conor Murphy <conor_murphy_virt@hotmail.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/virtio-blk.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index b14fb995e8..91e0394af9 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -290,6 +290,10 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb) virtio_blk_rw_complete(req, -EIO); return; } + if (req->qiov.size % req->dev->conf->logical_block_size) { + virtio_blk_rw_complete(req, -EIO); + return; + } if (mrb->num_writes == 32) { virtio_submit_multiwrite(req->dev->bs, mrb); @@ -317,6 +321,10 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req) virtio_blk_rw_complete(req, -EIO); return; } + if (req->qiov.size % req->dev->conf->logical_block_size) { + virtio_blk_rw_complete(req, -EIO); + return; + } acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov, req->qiov.size / BDRV_SECTOR_SIZE, From 64a4d100b502f24d0116437b9e5678c032a233e6 Mon Sep 17 00:00:00 2001 From: Scott Wood <scottwood@freescale.com> Date: Mon, 4 Oct 2010 11:15:58 +0000 Subject: [PATCH 122/386] Don't call cpu_synchronize_state() from machine init. This will deadlock when the I/O thread is used, since the CPU thread is blocked waiting for qemu_system_ready. The synchronization is unnecessary since this is before cpu_synchronize_all_post_init(). Signed-off-by: Scott Wood <scottwood@freescale.com> Acked-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/ppc440_bamboo.c | 2 -- hw/ppce500_mpc8544ds.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 34ddf45477..645e84fd36 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -156,8 +156,6 @@ static void bamboo_init(ram_addr_t ram_size, exit(1); } - cpu_synchronize_state(env); - /* Set initial guest state. */ env->gpr[1] = (16<<20) - 8; env->gpr[3] = FDT_ADDR; diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index b7670ae27c..e111dda5f4 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -268,8 +268,6 @@ static void mpc8544ds_init(ram_addr_t ram_size, exit(1); } - cpu_synchronize_state(env); - /* Set initial guest state. */ env->gpr[1] = (16<<20) - 8; env->gpr[3] = dt_base; From 8804f57b531e4887ad9521c9abb9e0bbbcb1dd4e Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 3 Apr 2011 18:21:24 +0200 Subject: [PATCH 123/386] spapr_vscsi: Set uninitialized variable cppcheck reports this error: hw/spapr_vscsi.c:274: error: Uninitialized variable: rc If llen == 0, rc was indeed used without being initialized. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr_vscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index e142dae624..992833450c 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -255,7 +255,7 @@ static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req, { struct srp_direct_buf *md = req->cur_desc; uint32_t llen; - int rc; + int rc = 0; dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n", len, (unsigned long long)md->va, md->len); From c7a5c0c9280c2ddaa875e3cafb3df16a96af809c Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Tue, 5 Apr 2011 15:12:09 +1000 Subject: [PATCH 124/386] pseries: Abolish envs array Currently the pseries machine init code builds up an array, envs, of CPUState pointers for all the cpus in the system. This is kind of pointless, given the generic code already has a perfectly good linked list of the cpus. In addition, there are a number of places which assume that the cpu's cpu_index field is equal to its index in this array. This is true in practice, because cpu_index values are just assigned sequentially, but it's conceptually incorrect and may not always be true. Therefore, this patch abolishes the envs array, and explicitly uses the generic cpu linked list and cpu_index values throughout. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 49 ++++++++++++++++++++++++------------------------- hw/xics.c | 32 +++++++++++++++++++++----------- hw/xics.h | 3 +-- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 1152a25b2e..f80873cfd2 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -57,7 +57,7 @@ sPAPREnvironment *spapr; static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, - const char *cpu_model, CPUState *envs[], + const char *cpu_model, sPAPREnvironment *spapr, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, @@ -68,6 +68,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, long hash_shift) { void *fdt; + CPUState *env; uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); @@ -135,14 +136,14 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, modelname[i] = toupper(modelname[i]); } - for (i = 0; i < smp_cpus; i++) { - CPUState *env = envs[i]; - uint32_t gserver_prop[] = {cpu_to_be32(i), 0}; /* HACK! */ + for (env = first_cpu; env != NULL; env = env->next_cpu) { + int index = env->cpu_index; + uint32_t gserver_prop[] = {cpu_to_be32(index), 0}; /* HACK! */ char *nodename; uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; - if (asprintf(&nodename, "%s@%x", modelname, i) < 0) { + if (asprintf(&nodename, "%s@%x", modelname, index) < 0) { fprintf(stderr, "Allocation failure\n"); exit(1); } @@ -151,7 +152,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, free(nodename); - _FDT((fdt_property_cell(fdt, "reg", i))); + _FDT((fdt_property_cell(fdt, "reg", index))); _FDT((fdt_property_string(fdt, "device_type", "cpu"))); _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); @@ -168,11 +169,11 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); - _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", i))); + _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", index))); _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", gserver_prop, sizeof(gserver_prop)))); - if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) { + if (env->mmu_model & POWERPC_MMU_1TSEG) { _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", segs, sizeof(segs)))); } @@ -261,8 +262,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { - CPUState *envs[MAX_CPUS]; void *fdt, *htab; + CPUState *env; int i; ram_addr_t ram_offset; target_phys_addr_t fdt_addr, rtas_addr; @@ -288,7 +289,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, cpu_model = "POWER7"; } for (i = 0; i < smp_cpus; i++) { - CPUState *env = cpu_init(cpu_model); + env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find PowerPC CPU definition\n"); @@ -300,9 +301,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, env->hreset_vector = 0x60; env->hreset_excp_prefix = 0; - env->gpr[3] = i; - - envs[i] = env; + env->gpr[3] = env->cpu_index; } /* allocate RAM */ @@ -315,10 +314,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, htab_size = 1ULL << (pteg_shift + 7); htab = qemu_mallocz(htab_size); - for (i = 0; i < smp_cpus; i++) { - envs[i]->external_htab = htab; - envs[i]->htab_base = -1; - envs[i]->htab_mask = htab_size - 1; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->external_htab = htab; + env->htab_base = -1; + env->htab_mask = htab_size - 1; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); @@ -330,7 +329,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, qemu_free(filename); /* Set up Interrupt Controller */ - spapr->icp = xics_system_init(smp_cpus, envs, XICS_IRQS); + spapr->icp = xics_system_init(XICS_IRQS); /* Set up VIO bus */ spapr->vio_bus = spapr_vio_bus_init(); @@ -416,13 +415,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* SLOF will startup the secondary CPUs using RTAS, rather than expecting a kexec() style entry */ - for (i = 0; i < smp_cpus; i++) { - envs[i]->halted = 1; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->halted = 1; } } /* Prepare the device tree */ - fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, + fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, spapr, initrd_base, initrd_size, boot_device, kernel_cmdline, rtas_addr, rtas_size, pteg_shift + 7); @@ -432,10 +431,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, qemu_free(fdt); - envs[0]->gpr[3] = fdt_addr; - envs[0]->gpr[5] = 0; - envs[0]->hreset_vector = kernel_base; - envs[0]->halted = 0; + first_cpu->gpr[3] = fdt_addr; + first_cpu->gpr[5] = 0; + first_cpu->hreset_vector = kernel_base; + first_cpu->halted = 0; } static QEMUMachine spapr_machine = { diff --git a/hw/xics.c b/hw/xics.c index 66047a6c57..13a1d25944 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -425,27 +425,39 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); /* Success */ } -struct icp_state *xics_system_init(int nr_servers, CPUState *servers[], - int nr_irqs) +struct icp_state *xics_system_init(int nr_irqs) { + CPUState *env; + int max_server_num; int i; struct icp_state *icp; struct ics_state *ics; + max_server_num = -1; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->cpu_index > max_server_num) { + max_server_num = env->cpu_index; + } + } + icp = qemu_mallocz(sizeof(*icp)); - icp->nr_servers = nr_servers; - icp->ss = qemu_mallocz(nr_servers * sizeof(struct icp_server_state)); + icp->nr_servers = max_server_num + 1; + icp->ss = qemu_mallocz(icp->nr_servers*sizeof(struct icp_server_state)); - for (i = 0; i < nr_servers; i++) { - servers[i]->cpu_index = i; + for (i = 0; i < icp->nr_servers; i++) { + icp->ss[i].mfrr = 0xff; + } - switch (PPC_INPUT(servers[i])) { + for (env = first_cpu; env != NULL; env = env->next_cpu) { + struct icp_server_state *ss = &icp->ss[env->cpu_index]; + + switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER7: - icp->ss[i].output = servers[i]->irq_inputs[POWER7_INPUT_INT]; + ss->output = env->irq_inputs[POWER7_INPUT_INT]; break; case PPC_FLAGS_INPUT_970: - icp->ss[i].output = servers[i]->irq_inputs[PPC970_INPUT_INT]; + ss->output = env->irq_inputs[PPC970_INPUT_INT]; break; default: @@ -453,8 +465,6 @@ struct icp_state *xics_system_init(int nr_servers, CPUState *servers[], "model\n"); exit(1); } - - icp->ss[i].mfrr = 0xff; } ics = qemu_mallocz(sizeof(*ics)); diff --git a/hw/xics.h b/hw/xics.h index 096eeb346d..83c1182598 100644 --- a/hw/xics.h +++ b/hw/xics.h @@ -33,7 +33,6 @@ struct icp_state; qemu_irq xics_find_qirq(struct icp_state *icp, int irq); -struct icp_state *xics_system_init(int nr_servers, CPUState *servers[], - int nr_irqs); +struct icp_state *xics_system_init(int nr_irqs); #endif /* __XICS_H__ */ From a3467baa88c5bbb58834952980d2f2206aab4445 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Tue, 5 Apr 2011 15:12:10 +1000 Subject: [PATCH 125/386] Delay creation of pseries device tree until reset At present, the 'pseries' machine creates a flattened device tree in the machine->init function to pass to either the guest kernel or to firmware. However, the machine->init function runs before processing of -device command line options, which means that the device tree so created will be (incorrectly) missing devices specified that way. Supplying a correct device tree is, in any case, part of the required platform entry conditions. Therefore, this patch moves the creation and loading of the device tree from machine->init to a reset callback. The setup of entry point address and initial register state moves with it, which leads to a slight cleanup. This is not, alas, quite enough to make a fully working reset for pseries. For that we would need to reload the firmware images, which on this machine are loaded into RAM. It's a step in the right direction, though. Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/spapr.c | 116 +++++++++++++++++++++++++++++++---------------------- hw/spapr.h | 7 ++++ 2 files changed, 75 insertions(+), 48 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index f80873cfd2..1782cc0a94 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -56,20 +56,16 @@ sPAPREnvironment *spapr; -static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, - const char *cpu_model, - sPAPREnvironment *spapr, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, - const char *boot_device, - const char *kernel_cmdline, - target_phys_addr_t rtas_addr, - target_phys_addr_t rtas_size, - long hash_shift) +static void *spapr_create_fdt_skel(const char *cpu_model, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *boot_device, + const char *kernel_cmdline, + long hash_shift) { void *fdt; CPUState *env; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(ram_size) }; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; @@ -78,7 +74,6 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; int i; char *modelname; - int ret; #define _FDT(exp) \ do { \ @@ -222,8 +217,21 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_end_node(fdt))); /* close root node */ _FDT((fdt_finish(fdt))); - /* re-expand to allow for further tweaks */ - _FDT((fdt_open_into(fdt, fdt, FDT_MAX_SIZE))); + return fdt; +} + +static void spapr_finalize_fdt(sPAPREnvironment *spapr, + target_phys_addr_t fdt_addr, + target_phys_addr_t rtas_addr, + target_phys_addr_t rtas_size) +{ + int ret; + void *fdt; + + fdt = qemu_malloc(FDT_MAX_SIZE); + + /* open out the base tree into a temp buffer for the final tweaks */ + _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { @@ -239,9 +247,9 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_pack(fdt))); - *fdt_size = fdt_totalsize(fdt); + cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); - return fdt; + qemu_free(fdt); } static uint64_t translate_kernel_address(void *opaque, uint64_t addr) @@ -254,6 +262,27 @@ static void emulate_spapr_hypercall(CPUState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } +static void spapr_reset(void *opaque) +{ + sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; + + fprintf(stderr, "sPAPR reset\n"); + + /* flush out the hash table */ + memset(spapr->htab, 0, spapr->htab_size); + + /* Load the fdt */ + spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, + spapr->rtas_size); + + /* Set up the entry state */ + first_cpu->gpr[3] = spapr->fdt_addr; + first_cpu->gpr[5] = 0; + first_cpu->halted = 0; + first_cpu->nip = spapr->entry_point; + +} + /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(ram_addr_t ram_size, const char *boot_device, @@ -262,15 +291,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, const char *initrd_filename, const char *cpu_model) { - void *fdt, *htab; CPUState *env; int i; ram_addr_t ram_offset; - target_phys_addr_t fdt_addr, rtas_addr; - uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size, htab_size, rtas_size, fw_size; + uint32_t initrd_base; + long kernel_size, initrd_size, fw_size; long pteg_shift = 17; - int fdt_size; char *filename; int irq = 16; @@ -280,9 +306,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* We place the device tree just below either the top of RAM, or * 2GB, so that it can be processed with 32-bit code if * necessary */ - fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; - /* RTAS goes just below that */ - rtas_addr = fdt_addr - RTAS_MAX_SIZE; + spapr->fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE; + spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE; /* init CPUs */ if (cpu_model == NULL) { @@ -311,18 +336,19 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest * RAM */ - htab_size = 1ULL << (pteg_shift + 7); - htab = qemu_mallocz(htab_size); + spapr->htab_size = 1ULL << (pteg_shift + 7); + spapr->htab = qemu_malloc(spapr->htab_size); for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->external_htab = htab; + env->external_htab = spapr->htab; env->htab_base = -1; - env->htab_mask = htab_size - 1; + env->htab_mask = spapr->htab_size - 1; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); - rtas_size = load_image_targphys(filename, rtas_addr, ram_size - rtas_addr); - if (rtas_size < 0) { + spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, + ram_size - spapr->rtas_addr); + if (spapr->rtas_size < 0) { hw_error("qemu: could not load LPAR rtas '%s'\n", filename); exit(1); } @@ -368,13 +394,12 @@ static void ppc_spapr_init(ram_addr_t ram_size, if (kernel_filename) { uint64_t lowaddr = 0; - kernel_base = KERNEL_LOAD_ADDR; - kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, kernel_base, - ram_size - kernel_base); + kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", @@ -396,6 +421,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, initrd_base = 0; initrd_size = 0; } + + spapr->entry_point = KERNEL_LOAD_ADDR; } else { if (ram_size < (MIN_RAM_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " @@ -409,7 +436,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, exit(1); } qemu_free(filename); - kernel_base = 0x100; + spapr->entry_point = 0x100; initrd_base = 0; initrd_size = 0; @@ -421,20 +448,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, } /* Prepare the device tree */ - fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, spapr, - initrd_base, initrd_size, - boot_device, kernel_cmdline, - rtas_addr, rtas_size, pteg_shift + 7); - assert(fdt != NULL); + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, + initrd_base, initrd_size, + boot_device, kernel_cmdline, + pteg_shift + 7); + assert(spapr->fdt_skel != NULL); - cpu_physical_memory_write(fdt_addr, fdt, fdt_size); - - qemu_free(fdt); - - first_cpu->gpr[3] = fdt_addr; - first_cpu->gpr[5] = 0; - first_cpu->hreset_vector = kernel_base; - first_cpu->halted = 0; + qemu_register_reset(spapr_reset, spapr); } static QEMUMachine spapr_machine = { diff --git a/hw/spapr.h b/hw/spapr.h index fae8e1351c..b52133a4aa 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -7,6 +7,13 @@ struct icp_state; typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; struct icp_state *icp; + + void *htab; + long htab_size; + target_phys_addr_t fdt_addr, rtas_addr; + long rtas_size; + void *fdt_skel; + target_ulong entry_point; } sPAPREnvironment; #define H_SUCCESS 0 From 3601ff11732160e42d3174d2821d873cfcd52a59 Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Tue, 5 Apr 2011 15:12:11 +1000 Subject: [PATCH 126/386] Use existing helper function to implement popcntd instruction The recent patches adding partial support for POWER7 cpu emulation included implementing the popcntd instruction. The support for this was open coded, but host-utils.h already included a function implementing an equivalent population count function, which uses a gcc builtin (which can use special host instructions) if available. This patch makes the popcntd implementation use the existing, potentially faster, implementation. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/op_helper.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index b1b883d0a7..5882becbc9 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -528,19 +528,7 @@ target_ulong helper_popcntw (target_ulong val) target_ulong helper_popcntd (target_ulong val) { - val = (val & 0x5555555555555555ULL) + ((val >> 1) & - 0x5555555555555555ULL); - val = (val & 0x3333333333333333ULL) + ((val >> 2) & - 0x3333333333333333ULL); - val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & - 0x0f0f0f0f0f0f0f0fULL); - val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & - 0x00ff00ff00ff00ffULL); - val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & - 0x0000ffff0000ffffULL); - val = (val & 0x00000000ffffffffULL) + ((val >> 32) & - 0x00000000ffffffffULL); - return val; + return ctpop64(val); } #else target_ulong helper_popcntb (target_ulong val) From 6957785773e8a3cc8bd51f0e3172eaccbbaa5f3a Mon Sep 17 00:00:00 2001 From: David Gibson <david@gibson.dropbear.id.au> Date: Fri, 8 Apr 2011 20:08:25 +1000 Subject: [PATCH 127/386] ppce500_mpc8544ds: Fix compile with --enable-debug and --disable-kvm When configured with --enable-debug, we compile without optimization. This means that the function mpc8544_copy_soc_cell() in ppce500_mpc8544ds.c is not optimized out, even though it is never called without kvm. That in turn causes a link failure, because it calls the function kvmppc_read_host_property() which is in kvm_ppc.o and therefore not included in a --disable-kvm build. This patch fixes the problem by providing a dummy stub for kvmppc_read_host_property() in kvm_ppc.h when !CONFIG_KVM. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de> --- target-ppc/kvm_ppc.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 5afb308477..45a1373b28 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -11,8 +11,17 @@ void kvmppc_init(void); void kvmppc_fdt_update(void *fdt); +#ifndef CONFIG_KVM +static inline int kvmppc_read_host_property(const char *node_path, const char *prop, + void *val, size_t len) +{ + assert(0); + return -ENOSYS; +} +#else int kvmppc_read_host_property(const char *node_path, const char *prop, void *val, size_t len); +#endif uint32_t kvmppc_get_tbfreq(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); From 31a44434f7b3221d911d478de3d1665bde753c86 Mon Sep 17 00:00:00 2001 From: Alex Williamson <alex.williamson@redhat.com> Date: Fri, 8 Apr 2011 13:03:34 -0600 Subject: [PATCH 128/386] Add ipxe submodule Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- .gitmodules | 3 +++ roms/ipxe | 1 + 2 files changed, 4 insertions(+) create mode 160000 roms/ipxe diff --git a/.gitmodules b/.gitmodules index 44fdd1a02d..788447189e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "roms/SLOF"] path = roms/SLOF url = git://git.qemu.org/SLOF.git +[submodule "roms/ipxe"] + path = roms/ipxe + url = git://git.qemu.org/ipxe.git diff --git a/roms/ipxe b/roms/ipxe new file mode 160000 index 0000000000..7aee315f61 --- /dev/null +++ b/roms/ipxe @@ -0,0 +1 @@ +Subproject commit 7aee315f61aaf1be6d2fff26339f28a1137231a5 From f95857b34d284895816f2091ef4fc6d9460ebf3b Mon Sep 17 00:00:00 2001 From: Adam Lackorzynski <adam@os.inf.tu-dresden.de> Date: Fri, 8 Apr 2011 08:48:42 +0200 Subject: [PATCH 129/386] multiboot: Quote filename in error message Quote filename in error message to spot possible whitespace character in the filename and make error message more meaningful. Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de> Acked-by: Alexander Graf <agraf@suse.de> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/multiboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/multiboot.c b/hw/multiboot.c index 0d2bfb4973..394ed0136e 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -272,7 +272,7 @@ int load_multiboot(void *fw_cfg, mb_debug("multiboot loading module: %s\n", initrd_filename); mb_mod_length = get_image_size(initrd_filename); if (mb_mod_length < 0) { - fprintf(stderr, "failed to get %s image size\n", initrd_filename); + fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); exit(1); } From 97697373b41ec1d337d6826d981a0cb4e75c37f0 Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Sat, 9 Apr 2011 12:11:36 +1000 Subject: [PATCH 130/386] event: trivial coding style fixes Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- input.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/input.c b/input.c index ec05548f7a..5664d3a1e3 100644 --- a/input.c +++ b/input.c @@ -161,15 +161,15 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) if (mouse_event) { if (graphic_rotate) { - if (entry->qemu_put_mouse_event_absolute) + if (entry->qemu_put_mouse_event_absolute) { width = 0x7fff; - else + } else { width = graphic_width - 1; - mouse_event(mouse_event_opaque, - width - dy, dx, dz, buttons_state); - } else - mouse_event(mouse_event_opaque, - dx, dy, dz, buttons_state); + } + mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state); + } else { + mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); + } } } From 72b310e99a5752d520af82d641c6cafa5b1058ea Mon Sep 17 00:00:00 2001 From: Scott Wood <scottwood@freescale.com> Date: Fri, 8 Apr 2011 17:06:37 -0500 Subject: [PATCH 131/386] mpc85xx_pci_map_irq: change "unknow" to "unknown" Signed-off-by: Scott Wood <scottwood@freescale.com> Acked-by: Alexander Graf <agraf@suse.de> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/ppce500_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 11edd03f16..2fc879236a 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -198,7 +198,7 @@ static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) ret = (irq_num + devno - 0x10) % 4; break; default: - printf("Error:%s:unknow dev number\n", __func__); + printf("Error:%s:unknown dev number\n", __func__); } pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, From 29e5badadffe2cc70a911a95e258d1fb01f2db71 Mon Sep 17 00:00:00 2001 From: Scott Wood <scottwood@freescale.com> Date: Fri, 8 Apr 2011 14:15:50 -0500 Subject: [PATCH 132/386] configure: avoid basename usage message basename prints a missing-argument error when sdlconfig is empty and we're cross-compiling. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index ae97e11a97..2bb3faa07e 100755 --- a/configure +++ b/configure @@ -1233,7 +1233,7 @@ else fi sdl=no fi -if test -n "$cross_prefix" && test "`basename $sdlconfig`" = sdl-config; then +if test -n "$cross_prefix" && test "$(basename "$sdlconfig")" = sdl-config; then echo warning: using "\"$sdlconfig\"" to detect cross-compiled sdl >&2 fi From 5145b3d1cc4dc77d82086d99b0690a76e1073071 Mon Sep 17 00:00:00 2001 From: Jordan Justen <jordan.l.justen@intel.com> Date: Sun, 3 Apr 2011 13:16:26 -0700 Subject: [PATCH 133/386] hw/pflash_cfi02: Fix lazy reset of ROMD mode When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region. Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/pflash_cfi02.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 30c8aa4e4f..370c5eef7b 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -112,7 +112,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset); ret = -1; - if (pfl->rom_mode) { + if (!pfl->rom_mode) { /* Lazy reset of to ROMD mode */ if (pfl->wcycle == 0) pflash_register_memory(pfl, 1); From a54d41a8b985cc7ff9d4bc52e6ca20a09216b394 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Fri, 25 Mar 2011 19:54:38 +0900 Subject: [PATCH 134/386] acpi, acpi_piix, vt82c686: factor out PM_TMR logic factor out PM_TMR logic. Later This will be used by ich9 acpi. Also fixes the same bug in vt82c686.c that was fixed by the following commits. > commit 055479feab63607b8042bb8ebb2e0523f17cbc4e > Author: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> > Date: Wed Jan 21 16:31:20 2009 +0000 > > Always return latest pmsts instead of the old one (Xiantao Zhang) > > It may lead to the issue when booting windows guests with acpi=1 > if return the old pmsts. > > Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com> > Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Cc: Blue Swirl <blauwirbel@gmail.com> Cc: Huacai Chen <zltjiangshi@gmail.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ hw/acpi.h | 24 ++++++++++++++++++++++++ hw/acpi_piix4.c | 45 ++++++++++++--------------------------------- hw/vt82c686.c | 47 +++++++++++++++-------------------------------- 4 files changed, 96 insertions(+), 65 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 8071e7beba..08cb12673b 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -197,3 +197,48 @@ out: } return -1; } + +/* ACPI PM_TMR */ +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable) +{ + int64_t expire_time; + + /* schedule a timer interruption if needed */ + if (enable) { + expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(), + PM_TIMER_FREQUENCY); + qemu_mod_timer(tmr->timer, expire_time); + } else { + qemu_del_timer(tmr->timer); + } +} + +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr) +{ + int64_t d = acpi_pm_tmr_get_clock(); + tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL; +} + +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr) +{ + uint32_t d = acpi_pm_tmr_get_clock();; + return d & 0xffffff; +} + +static void acpi_pm_tmr_timer(void *opaque) +{ + ACPIPMTimer *tmr = opaque; + tmr->update_sci(tmr); +} + +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci) +{ + tmr->update_sci = update_sci; + tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr); +} + +void acpi_pm_tmr_reset(ACPIPMTimer *tmr) +{ + tmr->overflow_time = 0; + qemu_del_timer(tmr->timer); +} diff --git a/hw/acpi.h b/hw/acpi.h index 5949958067..fc425012b3 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -74,5 +74,29 @@ #define ACPI_BITMASK_ARB_DISABLE 0x0001 /* PM_TMR */ +struct ACPIPMTimer; +typedef struct ACPIPMTimer ACPIPMTimer; + +typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr); + +struct ACPIPMTimer { + QEMUTimer *timer; + int64_t overflow_time; + + acpi_update_sci_fn update_sci; +}; + +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable); +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr); +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr); +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci); +void acpi_pm_tmr_reset(ACPIPMTimer *tmr); + +#include "qemu-timer.h" +static inline int64_t acpi_pm_tmr_get_clock(void) +{ + return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, + get_ticks_per_sec()); +} #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 74044ddd9b..e4ba8fc252 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -60,8 +60,7 @@ typedef struct PIIX4PMState { APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; @@ -82,20 +81,10 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static uint32_t get_pmtmr(PIIX4PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - static int get_pmsts(PIIX4PMState *s) { - int64_t d; - - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= s->tmr.overflow_time) s->pmsts |= ACPI_BITMASK_TIMER_STATUS; return s->pmsts; } @@ -103,7 +92,6 @@ static int get_pmsts(PIIX4PMState *s) static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; - int64_t expire_time; pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & @@ -115,19 +103,13 @@ static void pm_update_sci(PIIX4PMState *s) qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) && - !(pmsts & ACPI_BITMASK_TIMER_STATUS)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), - PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr); pm_update_sci(s); } @@ -144,14 +126,11 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: { - int64_t d; int pmsts; pmsts = get_pmsts(s); if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) { /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + acpi_pm_tmr_calc_overflow_time(&s->tmr); } s->pmsts &= ~val; pm_update_sci(s); @@ -211,7 +190,7 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, val = s->pmcntrl; break; case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -316,8 +295,8 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(pmen, PIIX4PMState), VMSTATE_UINT16(pmcntrl, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, PIIX4PMState), - VMSTATE_INT64(tmr_overflow_time, PIIX4PMState), + VMSTATE_TIMER(tmr.timer, PIIX4PMState), + VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs), VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, struct pci_status), @@ -414,7 +393,7 @@ static int piix4_pm_initfn(PCIDevice *dev) register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 818460d716..6f9c3847cb 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -160,8 +160,7 @@ typedef struct VT686PMState { uint16_t pmen; uint16_t pmcntrl; APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; } VT686PMState; @@ -183,45 +182,31 @@ typedef struct VT686MC97State { #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static uint32_t get_pmtmr(VT686PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - static int get_pmsts(VT686PMState *s) { - int64_t d; - int pmsts; - pmsts = s->pmsts; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) - s->pmsts |= TMROF_EN; - return pmsts; + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= s->tmr.overflow_time) { + s->pmsts |= ACPI_BITMASK_TIMER_STATUS; + } + return s->pmsts; } static void pm_update_sci(VT686PMState *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); qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - VT686PMState *s = opaque; + VT686PMState *s = container_of(tmr, VT686PMState, tmr); pm_update_sci(s); } @@ -233,13 +218,11 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) 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_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + acpi_pm_tmr_calc_overflow_time(&s->tmr); } s->pmsts &= ~val; pm_update_sci(s); @@ -310,7 +293,7 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) addr &= 0x0f; switch (addr) { case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -365,8 +348,8 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(pmen, VT686PMState), VMSTATE_UINT16(pmcntrl, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, VT686PMState), - VMSTATE_INT64(tmr_overflow_time, VT686PMState), + VMSTATE_TIMER(tmr.timer, VT686PMState), + VMSTATE_INT64(tmr.overflow_time, VT686PMState), VMSTATE_END_OF_LIST() } }; @@ -486,7 +469,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) apm_init(&s->apm, NULL, s); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); pm_smbus_init(&s->dev.qdev, &s->smb); From 04dc308f687d45dacc664251b266b6849f5a79d0 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Fri, 25 Mar 2011 19:54:39 +0900 Subject: [PATCH 135/386] acpi, acpi_piix, vt82c686: factor out PM1a EVT logic factor out ACPI PM1a EVT logic. Later this will be used by ich9 acpi. Cc: Blue Swirl <blauwirbel@gmail.com> Cc: Huacai Chen <zltjiangshi@gmail.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi.c | 37 +++++++++++++++++++++++++++++++++ hw/acpi.h | 13 ++++++++++++ hw/acpi_piix4.c | 52 +++++++++++++++-------------------------------- hw/vt82c686.c | 54 ++++++++++++++----------------------------------- 4 files changed, 81 insertions(+), 75 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 08cb12673b..07283befce 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -15,6 +15,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/> */ +#include "sysemu.h" #include "hw.h" #include "pc.h" #include "acpi.h" @@ -198,6 +199,42 @@ out: return -1; } +/* ACPI PM1a EVT */ +uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time) +{ + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= overflow_time) { + pm1->sts |= ACPI_BITMASK_TIMER_STATUS; + } + return pm1->sts; +} + +void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val) +{ + uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time); + if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { + /* if TMRSTS is reset, then compute the new overflow time */ + acpi_pm_tmr_calc_overflow_time(tmr); + } + pm1->sts &= ~val; +} + +void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr) +{ + if (!pm1) { + qemu_system_shutdown_request(); + } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) { + pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS; + tmr->update_sci(tmr); + } +} + +void acpi_pm1_evt_reset(ACPIPM1EVT *pm1) +{ + pm1->sts = 0; + pm1->en = 0; +} + /* ACPI PM_TMR */ void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable) { diff --git a/hw/acpi.h b/hw/acpi.h index fc425012b3..c286d7d4e2 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -99,4 +99,17 @@ static inline int64_t acpi_pm_tmr_get_clock(void) get_ticks_per_sec()); } +/* PM1a_EVT: piix and ich9 don't implement PM1b. */ +struct ACPIPM1EVT +{ + uint16_t sts; + uint16_t en; +}; +typedef struct ACPIPM1EVT ACPIPM1EVT; + +uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time); +void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val); +void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr); +void acpi_pm1_evt_reset(ACPIPM1EVT *pm1); + #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index e4ba8fc252..fa7c6a9702 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -54,8 +54,7 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; IORange ioport; - uint16_t pmsts; - uint16_t pmen; + ACPIPM1EVT pm1a; uint16_t pmcntrl; APMState apm; @@ -81,20 +80,12 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static int get_pmsts(PIIX4PMState *s) -{ - int64_t d = acpi_pm_tmr_get_clock(); - if (d >= s->tmr.overflow_time) - s->pmsts |= ACPI_BITMASK_TIMER_STATUS; - return s->pmsts; -} - static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; - pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & + pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); + sci_level = (((pmsts & s->pm1a.en) & (ACPI_BITMASK_RT_CLOCK_ENABLE | ACPI_BITMASK_POWER_BUTTON_ENABLE | ACPI_BITMASK_GLOBAL_LOCK_ENABLE | @@ -103,7 +94,7 @@ static void pm_update_sci(PIIX4PMState *s) qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) && !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } @@ -125,19 +116,11 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: - { - int pmsts; - pmsts = get_pmsts(s); - if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) { - /* if TMRSTS is reset, then compute the new overflow time */ - acpi_pm_tmr_calc_overflow_time(&s->tmr); - } - s->pmsts &= ~val; - pm_update_sci(s); - } + acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val); + pm_update_sci(s); break; case 0x02: - s->pmen = val; + s->pm1a.en = val; pm_update_sci(s); break; case 0x04: @@ -154,8 +137,8 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, case 1: /* ACPI_BITMASK_WAKE_STATUS should be set on resume. Pretend that resume was caused by power button */ - s->pmsts |= (ACPI_BITMASK_WAKE_STATUS | - ACPI_BITMASK_POWER_BUTTON_STATUS); + s->pm1a.sts |= (ACPI_BITMASK_WAKE_STATUS | + ACPI_BITMASK_POWER_BUTTON_STATUS); qemu_system_reset_request(); if (s->cmos_s3) { qemu_irq_raise(s->cmos_s3); @@ -181,10 +164,10 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: - val = get_pmsts(s); + val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); break; case 0x02: - val = s->pmen; + val = s->pm1a.en; break; case 0x04: val = s->pmcntrl; @@ -291,8 +274,8 @@ static const VMStateDescription vmstate_acpi = { .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, PIIX4PMState), - VMSTATE_UINT16(pmsts, PIIX4PMState), - VMSTATE_UINT16(pmen, PIIX4PMState), + VMSTATE_UINT16(pm1a.sts, PIIX4PMState), + VMSTATE_UINT16(pm1a.en, PIIX4PMState), VMSTATE_UINT16(pmcntrl, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), VMSTATE_TIMER(tmr.timer, PIIX4PMState), @@ -343,13 +326,10 @@ static void piix4_reset(void *opaque) static void piix4_powerdown(void *opaque, int irq, int power_failing) { PIIX4PMState *s = opaque; + ACPIPM1EVT *pm1a = s? &s->pm1a: NULL; + ACPIPMTimer *tmr = s? &s->tmr: NULL; - if (!s) { - qemu_system_shutdown_request(); - } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) { - s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS; - pm_update_sci(s); - } + acpi_pm1_evt_power_down(pm1a, tmr); } static int piix4_pm_initfn(PCIDevice *dev) diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 6f9c3847cb..10cbc74cf1 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -156,8 +156,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, typedef struct VT686PMState { PCIDevice dev; - uint16_t pmsts; - uint16_t pmen; + ACPIPM1EVT pm1a; uint16_t pmcntrl; APMState apm; ACPIPMTimer tmr; @@ -173,34 +172,19 @@ typedef struct VT686MC97State { PCIDevice dev; } VT686MC97State; -#define RTC_EN (1 << 10) -#define PWRBTN_EN (1 << 8) -#define GBL_EN (1 << 5) -#define TMROF_EN (1 << 0) -#define SUS_EN (1 << 13) - -#define ACPI_ENABLE 0xf1 -#define ACPI_DISABLE 0xf0 - -static int get_pmsts(VT686PMState *s) -{ - int64_t d = acpi_pm_tmr_get_clock(); - if (d >= s->tmr.overflow_time) { - s->pmsts |= ACPI_BITMASK_TIMER_STATUS; - } - return s->pmsts; -} - static void pm_update_sci(VT686PMState *s) { int sci_level, pmsts; - pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & - (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); + pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); + sci_level = (((pmsts & s->pm1a.en) & + (ACPI_BITMASK_RT_CLOCK_ENABLE | + ACPI_BITMASK_POWER_BUTTON_ENABLE | + ACPI_BITMASK_GLOBAL_LOCK_ENABLE | + ACPI_BITMASK_TIMER_ENABLE)) != 0); qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) && !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } @@ -217,19 +201,11 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) addr &= 0x0f; switch (addr) { case 0x00: - { - int pmsts; - pmsts = get_pmsts(s); - if (pmsts & val & TMROF_EN) { - /* if TMRSTS is reset, then compute the new overflow time */ - acpi_pm_tmr_calc_overflow_time(&s->tmr); - } - s->pmsts &= ~val; - pm_update_sci(s); - } + acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val); + pm_update_sci(s); break; case 0x02: - s->pmen = val; + s->pm1a.en = val; pm_update_sci(s); break; case 0x04: @@ -263,10 +239,10 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) addr &= 0x0f; switch (addr) { case 0x00: - val = get_pmsts(s); + val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); break; case 0x02: - val = s->pmen; + val = s->pm1a.en; break; case 0x04: val = s->pmcntrl; @@ -344,8 +320,8 @@ static const VMStateDescription vmstate_acpi = { .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, VT686PMState), - VMSTATE_UINT16(pmsts, VT686PMState), - VMSTATE_UINT16(pmen, VT686PMState), + VMSTATE_UINT16(pm1a.sts, VT686PMState), + VMSTATE_UINT16(pm1a.en, VT686PMState), VMSTATE_UINT16(pmcntrl, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), VMSTATE_TIMER(tmr.timer, VT686PMState), From eaba51c573afbdd45273eed9d61d9effda979b47 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Fri, 25 Mar 2011 19:54:40 +0900 Subject: [PATCH 136/386] acpi, acpi_piix, vt82c686: factor out PM1_CNT logic factor out ACPI PM1_CNT logic. This will be used by ich9 acpi. Cc: Blue Swirl <blauwirbel@gmail.com> Cc: Huacai Chen <zltjiangshi@gmail.com> Cc: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/acpi.h | 14 ++++++++++++++ hw/acpi_piix4.c | 40 ++++++---------------------------------- hw/vt82c686.c | 23 +++++------------------ 4 files changed, 74 insertions(+), 52 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 07283befce..2879eea406 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -279,3 +279,52 @@ void acpi_pm_tmr_reset(ACPIPMTimer *tmr) tmr->overflow_time = 0; qemu_del_timer(tmr->timer); } + +/* ACPI PM1aCNT */ +void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3) +{ + pm1_cnt->cmos_s3 = cmos_s3; +} + +void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val) +{ + pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); + + if (val & ACPI_BITMASK_SLEEP_ENABLE) { + /* change suspend type */ + uint16_t sus_typ = (val >> 10) & 7; + switch(sus_typ) { + case 0: /* soft power off */ + qemu_system_shutdown_request(); + break; + case 1: + /* ACPI_BITMASK_WAKE_STATUS should be set on resume. + Pretend that resume was caused by power button */ + pm1a->sts |= + (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); + qemu_system_reset_request(); + qemu_irq_raise(pm1_cnt->cmos_s3); + default: + break; + } + } +} + +void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, + bool sci_enable, bool sci_disable) +{ + /* ACPI specs 3.0, 4.7.2.5 */ + if (sci_enable) { + pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE; + } else if (sci_disable) { + pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE; + } +} + +void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt) +{ + pm1_cnt->cnt = 0; + if (pm1_cnt->cmos_s3) { + qemu_irq_lower(pm1_cnt->cmos_s3); + } +} diff --git a/hw/acpi.h b/hw/acpi.h index c286d7d4e2..836459e9c1 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -112,4 +112,18 @@ void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val); void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr); void acpi_pm1_evt_reset(ACPIPM1EVT *pm1); +/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */ +struct ACPIPM1CNT { + uint16_t cnt; + + qemu_irq cmos_s3; +}; +typedef struct ACPIPM1CNT ACPIPM1CNT; + +void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3); +void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val); +void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, + bool sci_enable, bool sci_disable); +void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt); + #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index fa7c6a9702..412ace3849 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -55,7 +55,7 @@ typedef struct PIIX4PMState { PCIDevice dev; IORange ioport; ACPIPM1EVT pm1a; - uint16_t pmcntrl; + ACPIPM1CNT pm1_cnt; APMState apm; @@ -65,7 +65,6 @@ typedef struct PIIX4PMState { uint32_t smb_io_base; qemu_irq irq; - qemu_irq cmos_s3; qemu_irq smi_irq; int kvm_enabled; @@ -124,30 +123,7 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, pm_update_sci(s); break; case 0x04: - { - int sus_typ; - s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE); - if (val & ACPI_BITMASK_SLEEP_ENABLE) { - /* change suspend type */ - sus_typ = (val >> 10) & 7; - switch(sus_typ) { - case 0: /* soft power off */ - qemu_system_shutdown_request(); - break; - case 1: - /* ACPI_BITMASK_WAKE_STATUS should be set on resume. - Pretend that resume was caused by power button */ - s->pm1a.sts |= (ACPI_BITMASK_WAKE_STATUS | - ACPI_BITMASK_POWER_BUTTON_STATUS); - qemu_system_reset_request(); - if (s->cmos_s3) { - qemu_irq_raise(s->cmos_s3); - } - default: - break; - } - } - } + acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val); break; default: break; @@ -170,7 +146,7 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, val = s->pm1a.en; break; case 0x04: - val = s->pmcntrl; + val = s->pm1_cnt.cnt; break; case 0x08: val = acpi_pm_tmr_get(&s->tmr); @@ -193,11 +169,7 @@ static void apm_ctrl_changed(uint32_t val, void *arg) PIIX4PMState *s = arg; /* ACPI specs 3.0, 4.7.2.5 */ - if (val == ACPI_ENABLE) { - s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE; - } else if (val == ACPI_DISABLE) { - s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE; - } + acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE); if (s->dev.config[0x5b] & (1 << 1)) { if (s->smi_irq) { @@ -276,7 +248,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_PCI_DEVICE(dev, PIIX4PMState), VMSTATE_UINT16(pm1a.sts, PIIX4PMState), VMSTATE_UINT16(pm1a.en, PIIX4PMState), - VMSTATE_UINT16(pmcntrl, PIIX4PMState), + VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), VMSTATE_TIMER(tmr.timer, PIIX4PMState), VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), @@ -396,7 +368,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s = DO_UPCAST(PIIX4PMState, dev, dev); s->irq = sci_irq; - s->cmos_s3 = cmos_s3; + acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3); s->smi_irq = smi_irq; s->kvm_enabled = kvm_enabled; diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 10cbc74cf1..ca8f826a07 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -157,7 +157,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, typedef struct VT686PMState { PCIDevice dev; ACPIPM1EVT pm1a; - uint16_t pmcntrl; + ACPIPM1CNT pm1_cnt; APMState apm; ACPIPMTimer tmr; PMSMBus smb; @@ -209,21 +209,7 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t 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; - } - } - } + acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val); break; default: break; @@ -245,7 +231,7 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) val = s->pm1a.en; break; case 0x04: - val = s->pmcntrl; + val = s->pm1_cnt.cnt; break; default: val = 0; @@ -322,7 +308,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_PCI_DEVICE(dev, VT686PMState), VMSTATE_UINT16(pm1a.sts, VT686PMState), VMSTATE_UINT16(pm1a.en, VT686PMState), - VMSTATE_UINT16(pmcntrl, VT686PMState), + VMSTATE_UINT16(pm1_cnt.cnt, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), VMSTATE_TIMER(tmr.timer, VT686PMState), VMSTATE_INT64(tmr.overflow_time, VT686PMState), @@ -446,6 +432,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) apm_init(&s->apm, NULL, s); acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); + acpi_pm1_cnt_init(&s->pm1_cnt, NULL); pm_smbus_init(&s->dev.qdev, &s->smb); From a0313c00fcd26530a025ff93edee32959917be8d Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Date: Tue, 5 Apr 2011 23:34:04 +0900 Subject: [PATCH 137/386] lan9118: Ignore write to MAC_VLAN1 register On Mon, 4 Apr 2011 20:15:30 +0200, Aurelien Jarno <aurelien@aurel32.net> wrote: > Is it really safe ignoring write to this register? If yes, it's probably > a good idea to explain why in a comment. In any case, if supporting this > register is easy to do, it would be the best option. I think it is safe. Please see an updated comment below. And though implementing this register might be possible, I suppose it is not worth to supporting FrameTooLong detection, for now at least. Thank you for comments. >8--------------------------------------------------------------------- From: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Date: Tue, 5 Apr 2011 23:12:07 +0900 Subject: [PATCH] lan9118: Ignore write to MAC_VLAN1 register Since linux 2.6.38, smsc911x driver writes to VLAN1 registger. Since this register only affects FrameTooLong detection, ignoring write to this register should be safe. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/lan9118.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/lan9118.c b/hw/lan9118.c index af6949f1bc..2dc8d18549 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -785,6 +785,12 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val) case MAC_FLOW: s->mac_flow = val & 0xffff0000; break; + case MAC_VLAN1: + /* Writing to this register changes a condition for + * FrameTooLong bit in rx_status. Since we do not set + * FrameTooLong anyway, just ignore write to this. + */ + break; default: hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n", s->mac_cmd & 0xf, val); From a88df0b9b517b76c1a0052fb1b0fe83080559197 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Tue, 5 Apr 2011 11:07:06 +0900 Subject: [PATCH 138/386] smbus_eeprom: consolidate smbus eeprom creation oc pc_piix, mips_mapta, mips_fulong consolidate smbus initialization for pc_piix, mips_malta and mips_fulong. Cc: Aurelien Jarno <aurelien@aurel32.net> Cc: Huacai Chen <zltjiangshi@gmail.com> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/mips_fulong2e.c | 9 +-------- hw/mips_malta.c | 12 ++---------- hw/pc_piix.c | 10 ++-------- hw/smbus.h | 3 +++ hw/smbus_eeprom.c | 22 ++++++++++++++++++++-- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 0e90d684b4..420fada25b 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -263,11 +263,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, qemu_irq *cpu_exit_irq; int via_devfn; PCIBus *pci_bus; - uint8_t *eeprom_buf; i2c_bus *smbus; int i; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DeviceState *eeprom; CPUState *env; /* init CPUs */ @@ -353,13 +351,8 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4), 0xeee1, NULL); - eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ - memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd)); /* TODO: Populate SPD eeprom data. */ - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf); - qdev_init_nofail(eeprom); + smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); /* init other devices */ pit = pit_init(0x40, 0); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index bf0d76d03d..ed2a483c9b 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -770,7 +770,6 @@ void mips_malta_init (ram_addr_t ram_size, qemu_irq *i8259; qemu_irq *cpu_exit_irq; int piix4_devfn; - uint8_t *eeprom_buf; i2c_bus *smbus; int i; DriveInfo *dinfo; @@ -913,15 +912,8 @@ void mips_malta_init (ram_addr_t ram_size, usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9), NULL, NULL, 0); - eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ - for (i = 0; i < 8; i++) { - /* TODO: Populate SPD eeprom data. */ - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); - } + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(smbus, 8, NULL, 0); pit = pit_init(0x40, 0); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 4d54ca1832..a85214b7f1 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -37,6 +37,7 @@ #include "sysbus.h" #include "arch_init.h" #include "blockdev.h" +#include "smbus.h" #define MAX_IDE_BUS 2 @@ -154,7 +155,6 @@ static void pc_init1(ram_addr_t ram_size, } if (pci_enabled && acpi_enabled) { - uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ i2c_bus *smbus; cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); @@ -163,13 +163,7 @@ static void pc_init1(ram_addr_t ram_size, smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, isa_get_irq(9), *cmos_s3, *smi_irq, kvm_enabled()); - for (i = 0; i < 8; i++) { - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); - } + smbus_eeprom_init(smbus, 8, NULL, 0); } if (i440fx_state) { diff --git a/hw/smbus.h b/hw/smbus.h index 571c52dfb1..a39871593b 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -66,3 +66,6 @@ void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data); void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data, int len); + +void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, + const uint8_t *eeprom_spd, int size); diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 52463e0f86..3634754891 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -96,7 +96,7 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) return eeprom_receive_byte(dev); } -static int smbus_eeprom_init(SMBusDevice *dev) +static int smbus_eeprom_initfn(SMBusDevice *dev) { SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; @@ -111,7 +111,7 @@ static SMBusDeviceInfo smbus_eeprom_info = { DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), DEFINE_PROP_END_OF_LIST(), }, - .init = smbus_eeprom_init, + .init = smbus_eeprom_initfn, .quick_cmd = eeprom_quick_cmd, .send_byte = eeprom_send_byte, .receive_byte = eeprom_receive_byte, @@ -125,3 +125,21 @@ static void smbus_eeprom_register_devices(void) } device_init(smbus_eeprom_register_devices) + +void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, + const uint8_t *eeprom_spd, int eeprom_spd_size) +{ + int i; + uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ + if (eeprom_spd_size > 0) { + memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size); + } + + for (i = 0; i < nb_eeprom; i++) { + DeviceState *eeprom; + eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); + qdev_prop_set_uint8(eeprom, "address", 0x50 + i); + qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); + qdev_init_nofail(eeprom); + } +} From 2caa9e9d2e0f356cc244bc41ce1d3e81663f6782 Mon Sep 17 00:00:00 2001 From: Michael Tokarev <mjt@tls.msk.ru> Date: Mon, 21 Mar 2011 09:34:35 +0100 Subject: [PATCH 139/386] vnc: tight: Fix crash after 2GB of output fix 2Gb integer overflow in in VNC tight and zlib encodings As found by Roland Dreier <roland@purestorage.com> (excellent catch!), when amount of VNC compressed data produced by zlib and sent to client exceeds 2Gb, integer overflow occurs because currently, we calculate amount of data produced at each step by comparing saved total_out with new total_out, and total_out is something which grows without bounds. Compare it with previous avail_out instead of total_out, and leave total_out alone. The same code is used in vnc-enc-tight.c and vnc-enc-zlib.c, so fix both cases. There, there's no actual need to save previous_out value, since capacity-offset (which is how that value is calculated) stays the same so it can be recalculated again after call to deflate(), but whole thing becomes less readable this way. Reported-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Corentin Chary <corentin.chary@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- ui/vnc-enc-tight.c | 5 +++-- ui/vnc-enc-zlib.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 2522936193..87fdf35d3e 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -868,8 +868,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, zstream->avail_in = vs->tight.tight.offset; zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset; zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset; + previous_out = zstream->avail_out; zstream->data_type = Z_BINARY; - previous_out = zstream->total_out; /* start encoding */ if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { @@ -878,7 +878,8 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, } vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out; - bytes = zstream->total_out - previous_out; + /* ...how much data has actually been produced by deflate() */ + bytes = previous_out - zstream->avail_out; tight_send_compact_size(vs, bytes); vnc_write(vs, vs->tight.zlib.buffer, bytes); diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c index 3c6e6abf94..e32e4cd8a8 100644 --- a/ui/vnc-enc-zlib.c +++ b/ui/vnc-enc-zlib.c @@ -103,8 +103,8 @@ static int vnc_zlib_stop(VncState *vs) zstream->avail_in = vs->zlib.zlib.offset; zstream->next_out = vs->output.buffer + vs->output.offset; zstream->avail_out = vs->output.capacity - vs->output.offset; + previous_out = zstream->avail_out; zstream->data_type = Z_BINARY; - previous_out = zstream->total_out; // start encoding if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { @@ -113,7 +113,7 @@ static int vnc_zlib_stop(VncState *vs) } vs->output.offset = vs->output.capacity - zstream->avail_out; - return zstream->total_out - previous_out; + return previous_out - zstream->avail_out; } int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) From 4b4a72e55660abf7efe85aca78762dcfea5519ad Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sat, 2 Apr 2011 13:36:31 +0200 Subject: [PATCH 140/386] Fix conversions from pointer to tcg_target_long tcg_gen_exit_tb takes a parameter of type tcg_target_long, so the type casts of pointer to long should be replaced by type casts of pointer to tcg_target_long (suggested by Blue Swirl). These changes are needed for build environments where sizeof(long) != sizeof(void *), especially for w64. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- gen-icount.h | 2 +- target-alpha/translate.c | 6 +++--- target-arm/translate.c | 2 +- target-cris/translate.c | 2 +- target-i386/translate.c | 2 +- target-lm32/translate.c | 2 +- target-m68k/translate.c | 2 +- target-microblaze/translate.c | 2 +- target-mips/translate.c | 2 +- target-ppc/translate.c | 2 +- target-sh4/translate.c | 2 +- target-sparc/translate.c | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gen-icount.h b/gen-icount.h index 8879da6335..5fb3829781 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -29,7 +29,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns) if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); - tcg_gen_exit_tb((long)tb + 2); + tcg_gen_exit_tb((tcg_target_long)tb + 2); } } diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 3a1c625f73..96e922b569 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -398,7 +398,7 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp) } else if (use_goto_tb(ctx, dest)) { tcg_gen_goto_tb(0); tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((long)ctx->tb); + tcg_gen_exit_tb((tcg_target_long)ctx->tb); return EXIT_GOTO_TB; } else { tcg_gen_movi_i64(cpu_pc, dest); @@ -417,12 +417,12 @@ static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond, tcg_gen_goto_tb(0); tcg_gen_movi_i64(cpu_pc, ctx->pc); - tcg_gen_exit_tb((long)ctx->tb); + tcg_gen_exit_tb((tcg_target_long)ctx->tb); gen_set_label(lab_true); tcg_gen_goto_tb(1); tcg_gen_movi_i64(cpu_pc, dest); - tcg_gen_exit_tb((long)ctx->tb + 1); + tcg_gen_exit_tb((tcg_target_long)ctx->tb + 1); return EXIT_GOTO_TB; } else { diff --git a/target-arm/translate.c b/target-arm/translate.c index c6cb39ad2b..55d524ba13 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3387,7 +3387,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); gen_set_pc_im(dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_set_pc_im(dest); tcg_gen_exit_tb(0); diff --git a/target-cris/translate.c b/target-cris/translate.c index b4648a01de..1c03fa5fb6 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -596,7 +596,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(env_pc, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(env_pc, dest); tcg_gen_exit_tb(0); diff --git a/target-i386/translate.c b/target-i386/translate.c index c00845038a..7d1340ed01 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2274,7 +2274,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tb_num); gen_jmp_im(eip); - tcg_gen_exit_tb((long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)tb + tb_num); } else { /* jump to another page: currently not optimized */ gen_jmp_im(eip); diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 666d5f4dc3..efc9b5a856 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -138,7 +138,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) likely(!dc->singlestep_enabled)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_pc, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_pc, dest); if (dc->singlestep_enabled) { diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 6f72a2bdd2..038c0af3ef 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -861,7 +861,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_jmp_im(s, dest); tcg_gen_exit_tb(0); diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index b54b169b18..6f4eef1a69 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -146,7 +146,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_SR[SR_PC], dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_SR[SR_PC], dest); tcg_gen_exit_tb(0); diff --git a/target-mips/translate.c b/target-mips/translate.c index 0f93e2abb1..953c528068 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2686,7 +2686,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); gen_save_pc(dest); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_save_pc(dest); if (ctx->singlestep_enabled) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 090795b600..3c3ee24c95 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3347,7 +3347,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_nip, dest & ~3); - tcg_gen_exit_tb((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_tl(cpu_nip, dest & ~3); if (unlikely(ctx->singlestep_enabled)) { diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 58e9b8f93b..88098d7c23 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -302,7 +302,7 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) /* Use a direct jump if in same page and singlestep not enabled */ tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb((long) tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_i32(cpu_pc, dest); if (ctx->singlestep_enabled) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e26462eef5..883ecd2d2f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -241,7 +241,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, tcg_gen_goto_tb(tb_num); tcg_gen_movi_tl(cpu_pc, pc); tcg_gen_movi_tl(cpu_npc, npc); - tcg_gen_exit_tb((long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)tb + tb_num); } else { /* jump to another page: currently not optimized */ tcg_gen_movi_tl(cpu_pc, pc); From be5e7a76010bd14d09f74504ed6368782e701888 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Date: Mon, 4 Apr 2011 17:38:44 +0400 Subject: [PATCH 141/386] arm: basic support for ARMv4/ARMv4T emulation Currently target-arm/ assumes at least ARMv5 core. Add support for handling also ARMv4/ARMv4T. This changes the following instructions: BX(v4T and later) BKPT, BLX, CDP2, CLZ, LDC2, LDRD, MCRR, MCRR2, MRRC, MCRR, MRC2, MRRC, MRRC2, PLD QADD, QDADD, QDSUB, QSUB, STRD, SMLAxy, SMLALxy, SMLAWxy, SMULxy, SMULWxy, STC2 (v5 and later) All instructions that are "v5TE and later" are also bound to just v5, as that's how it was before. This patch doesn _not_ include disabling of cp15 access and base-updated data abort model (that will be required to emulate chips based on a ARM7TDMI), because: * no ARM7TDMI chips are currently emulated (or planned) * those features aren't strictly necessary for my purposes (SA-1 core emulation). All v5 models are handled as they are v5T. Internally we still have a check if the model is a v5(T) or v5TE, but as all emulated cores are v5TE, those two cases are simply aliased (for now). Patch is heavily based on patch by Filip Navara <filip.navara@gmail.com> which in turn is based on work by Ulrich Hecht <uli@suse.de> and Vincent Sanders <vince@kyllikki.org>. Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/cpu.h | 4 ++- target-arm/helper.c | 29 ++++++++++++++++++++- target-arm/translate.c | 59 +++++++++++++++++++++++++++++++++++------- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1ae7982c7f..e247a7ade0 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -360,7 +360,9 @@ enum arm_features { ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ ARM_FEATURE_THUMB2EE, - ARM_FEATURE_V7MP /* v7 Multiprocessing Extensions */ + ARM_FEATURE_V7MP, /* v7 Multiprocessing Extensions */ + ARM_FEATURE_V4T, + ARM_FEATURE_V5, }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/helper.c b/target-arm/helper.c index 6788a4c383..ce9a9d8fd2 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -48,17 +48,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cpuid = id; switch (id) { case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; case ARM_CPUID_ARM946: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_MPU); env->cp15.c0_cachetype = 0x0f004006; env->cp15.c1_sys = 0x00000078; break; case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; @@ -67,6 +73,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) break; case ARM_CPUID_ARM1136_R2: case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); @@ -79,6 +87,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00050078; break; case ARM_CPUID_ARM11MPCORE: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_VFP); @@ -91,6 +101,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_CORTEXA8: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -113,6 +125,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXA9: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -140,6 +154,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXM3: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_THUMB2); set_feature(env, ARM_FEATURE_V7); @@ -147,6 +163,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_DIV); break; case ARM_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_V6); set_feature(env, ARM_FEATURE_V6K); set_feature(env, ARM_FEATURE_V7); @@ -161,6 +179,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) break; case ARM_CPUID_TI915T: case ARM_CPUID_TI925T: + set_feature(env, ARM_FEATURE_V4T); set_feature(env, ARM_FEATURE_OMAPCP); env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */ env->cp15.c0_cachetype = 0x5109149; @@ -173,6 +192,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_PXA260: case ARM_CPUID_PXA261: case ARM_CPUID_PXA262: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ env->cp15.c0_cachetype = 0xd172172; @@ -184,6 +205,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_PXA270_B1: case ARM_CPUID_PXA270_C0: case ARM_CPUID_PXA270_C5: + set_feature(env, ARM_FEATURE_V4T); + set_feature(env, ARM_FEATURE_V5); set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ set_feature(env, ARM_FEATURE_IWMMXT); @@ -856,7 +879,11 @@ void do_interrupt(CPUARMState *env) /* Switch to the new mode, and to the correct instruction set. */ env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; env->uncached_cpsr |= mask; - env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0; + /* this is a lie, as the was no c1_sys on V4T/V5, but who cares + * and we should just guard the thumb mode on V4 */ + if (arm_feature(env, ARM_FEATURE_V4T)) { + env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0; + } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; env->interrupt_request |= CPU_INTERRUPT_EXITTB; diff --git a/target-arm/translate.c b/target-arm/translate.c index 55d524ba13..998cfd530c 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -34,6 +34,10 @@ #define GEN_HELPER 1 #include "helpers.h" +#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T) +#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5) +/* currently all emulated v5 cores are also v5TE, so don't bother */ +#define ENABLE_ARCH_5TE arm_feature(env, ARM_FEATURE_V5) #define ENABLE_ARCH_5J 0 #define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) #define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) @@ -750,6 +754,20 @@ static inline void store_reg_bx(CPUState *env, DisasContext *s, } } +/* Variant of store_reg which uses branch&exchange logic when storing + * to r15 in ARM architecture v5T and above. This is used for storing + * the results of a LDR/LDM/POP into r15, and corresponds to the cases + * in the ARM ARM which use the LoadWritePC() pseudocode function. */ +static inline void store_reg_from_load(CPUState *env, DisasContext *s, + int reg, TCGv var) +{ + if (reg == 15 && ENABLE_ARCH_5) { + gen_bx(s, var); + } else { + store_reg(s, reg, var); + } +} + static inline TCGv gen_ld8s(TCGv addr, int index) { TCGv tmp = tcg_temp_new_i32(); @@ -3436,6 +3454,10 @@ static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { /* Mask out undefined bits. */ mask &= ~CPSR_RESERVED; + if (!arm_feature(env, ARM_FEATURE_V4T)) + mask &= ~CPSR_T; + if (!arm_feature(env, ARM_FEATURE_V5)) + mask &= ~CPSR_Q; /* V5TE in reality*/ if (!arm_feature(env, ARM_FEATURE_V6)) mask &= ~(CPSR_E | CPSR_GE); if (!arm_feature(env, ARM_FEATURE_THUMB2)) @@ -6127,6 +6149,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; cond = insn >> 28; if (cond == 0xf){ + /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we + * choose to UNDEF. In ARMv5 and above the space is used + * for miscellaneous unconditional instructions. + */ + ARCH(5); + /* Unconditional instructions. */ if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ @@ -6155,6 +6183,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } /* Otherwise PLD; v5TE+ */ + ARCH(5TE); return; } if (((insn & 0x0f70f000) == 0x0450f000) || @@ -6291,6 +6320,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) val += (offset << 2) | ((insn >> 23) & 2) | 1; /* pipeline offset */ val += 4; + /* protected by ARCH(5); above, near the start of uncond block */ gen_bx_im(s, val); return; } else if ((insn & 0x0e000f00) == 0x0c000100) { @@ -6302,6 +6332,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } else if ((insn & 0x0fe00000) == 0x0c400000) { /* Coprocessor double register transfer. */ + ARCH(5TE); } else if ((insn & 0x0f000010) == 0x0e000010) { /* Additional coprocessor register transfer. */ } else if ((insn & 0x0ff10020) == 0x01000000) { @@ -6402,10 +6433,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x1: if (op1 == 1) { /* branch/exchange thumb (bx). */ + ARCH(4T); tmp = load_reg(s, rm); gen_bx(s, tmp); } else if (op1 == 3) { /* clz */ + ARCH(5); rd = (insn >> 12) & 0xf; tmp = load_reg(s, rm); gen_helper_clz(tmp, tmp); @@ -6428,6 +6461,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (op1 != 1) goto illegal_op; + ARCH(5); /* branch link/exchange thumb (blx) */ tmp = load_reg(s, rm); tmp2 = tcg_temp_new_i32(); @@ -6436,6 +6470,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_bx(s, tmp); break; case 0x5: /* saturating add/subtract */ + ARCH(5TE); rd = (insn >> 12) & 0xf; rn = (insn >> 16) & 0xf; tmp = load_reg(s, rm); @@ -6457,12 +6492,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; } /* bkpt */ + ARCH(5); gen_exception_insn(s, 4, EXCP_BKPT); break; case 0x8: /* signed multiply */ case 0xa: case 0xc: case 0xe: + ARCH(5TE); rs = (insn >> 8) & 0xf; rn = (insn >> 12) & 0xf; rd = (insn >> 16) & 0xf; @@ -6858,6 +6895,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } load = 1; } else if (sh & 2) { + ARCH(5TE); /* doubleword */ if (sh & 1) { /* store */ @@ -7198,10 +7236,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } if (insn & (1 << 20)) { /* Complete the load. */ - if (rd == 15) - gen_bx(s, tmp); - else - store_reg(s, rd, tmp); + store_reg_from_load(env, s, rd, tmp); } break; case 0x08: @@ -7254,9 +7289,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (insn & (1 << 20)) { /* load */ tmp = gen_ld32(addr, IS_USER(s)); - if (i == 15) { - gen_bx(s, tmp); - } else if (user) { + if (user) { tmp2 = tcg_const_i32(i); gen_helper_set_user_reg(tmp2, tmp); tcg_temp_free_i32(tmp2); @@ -7265,7 +7298,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) loaded_var = tmp; loaded_base = 1; } else { - store_reg(s, i, tmp); + store_reg_from_load(env, s, i, tmp); } } else { /* store */ @@ -7465,6 +7498,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) 16-bit instructions to get correct prefetch abort behavior. */ insn = insn_hw1; if ((insn & (1 << 12)) == 0) { + ARCH(5); /* Second half of blx. */ offset = ((insn & 0x7ff) << 1); tmp = load_reg(s, 14); @@ -8061,6 +8095,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } else { /* blx */ offset &= ~(uint32_t)2; + /* thumb2 bx, no need to check */ gen_bx_im(s, offset); } } else if (((insn >> 23) & 7) == 7) { @@ -8642,11 +8677,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) case 3:/* branch [and link] exchange thumb register */ tmp = load_reg(s, rm); if (insn & (1 << 7)) { + ARCH(5); val = (uint32_t)s->pc | 1; tmp2 = tcg_temp_new_i32(); tcg_gen_movi_i32(tmp2, val); store_reg(s, 14, tmp2); } + /* already thumb, no need to check */ gen_bx(s, tmp); break; } @@ -9006,8 +9043,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) /* write back the new stack pointer */ store_reg(s, 13, addr); /* set the new PC value */ - if ((insn & 0x0900) == 0x0900) - gen_bx(s, tmp); + if ((insn & 0x0900) == 0x0900) { + store_reg_from_load(env, s, 15, tmp); + } break; case 1: case 3: case 9: case 11: /* czb */ @@ -9038,6 +9076,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) break; case 0xe: /* bkpt */ + ARCH(5); gen_exception_insn(s, 2, EXCP_BKPT); break; From 23910d3f669d46073b403876e30a7314599633af Mon Sep 17 00:00:00 2001 From: Isaku Yamahata <yamahata@valinux.co.jp> Date: Fri, 25 Mar 2011 19:54:41 +0900 Subject: [PATCH 142/386] acpi, acpi_piix: factor out GPE logic factor out ACPI GPE logic. Later it will be used by ICH9 ACPI. Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi.c | 66 ++++++++++++++++++++++++++++++++++ hw/acpi.h | 17 +++++++++ hw/acpi_piix4.c | 95 +++++++++++++------------------------------------ 3 files changed, 108 insertions(+), 70 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 2879eea406..e372474399 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -328,3 +328,69 @@ void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt) qemu_irq_lower(pm1_cnt->cmos_s3); } } + +/* ACPI GPE */ +void acpi_gpe_init(ACPIGPE *gpe, uint8_t len) +{ + gpe->len = len; + gpe->sts = qemu_mallocz(len / 2); + gpe->en = qemu_mallocz(len / 2); +} + +void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk) +{ + gpe->blk = blk; +} + +void acpi_gpe_reset(ACPIGPE *gpe) +{ + memset(gpe->sts, 0, gpe->len / 2); + memset(gpe->en, 0, gpe->len / 2); +} + +static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr) +{ + uint8_t *cur = NULL; + + if (addr < gpe->len / 2) { + cur = gpe->sts + addr; + } else if (addr < gpe->len) { + cur = gpe->en + addr; + } else { + abort(); + } + + return cur; +} + +void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val) +{ + uint8_t *cur; + + addr -= gpe->blk; + cur = acpi_gpe_ioport_get_ptr(gpe, addr); + if (addr < gpe->len / 2) { + /* GPE_STS */ + *cur = (*cur) & ~val; + } else if (addr < gpe->len) { + /* GPE_EN */ + *cur = val; + } else { + abort(); + } +} + +uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr) +{ + uint8_t *cur; + uint32_t val; + + addr -= gpe->blk; + cur = acpi_gpe_ioport_get_ptr(gpe, addr); + val = 0; + if (cur != NULL) { + val = *cur; + } + + return val; +} diff --git a/hw/acpi.h b/hw/acpi.h index 836459e9c1..c141e65f4f 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -126,4 +126,21 @@ void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt, bool sci_enable, bool sci_disable); void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt); +/* GPE0 */ +struct ACPIGPE { + uint32_t blk; + uint8_t len; + + uint8_t *sts; + uint8_t *en; +}; +typedef struct ACPIGPE ACPIGPE; + +void acpi_gpe_init(ACPIGPE *gpe, uint8_t len); +void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk); +void acpi_gpe_reset(ACPIGPE *gpe); + +void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val); +uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr); + #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 412ace3849..96f522233a 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -35,17 +35,13 @@ #define ACPI_DBG_IO_ADDR 0xb044 #define GPE_BASE 0xafe0 +#define GPE_LEN 4 #define PCI_BASE 0xae00 #define PCI_EJ_BASE 0xae08 #define PCI_RMV_BASE 0xae0c #define PIIX4_PCI_HOTPLUG_STATUS 2 -struct gpe_regs { - uint16_t sts; /* status */ - uint16_t en; /* enabled */ -}; - struct pci_status { uint32_t up; uint32_t down; @@ -69,7 +65,7 @@ typedef struct PIIX4PMState { int kvm_enabled; /* for pci hotplug */ - struct gpe_regs gpe; + ACPIGPE gpe; struct pci_status pci0_status; uint32_t pci0_hotplug_enable; } PIIX4PMState; @@ -89,7 +85,7 @@ static void pm_update_sci(PIIX4PMState *s) ACPI_BITMASK_POWER_BUTTON_ENABLE | ACPI_BITMASK_GLOBAL_LOCK_ENABLE | ACPI_BITMASK_TIMER_ENABLE)) != 0) || - (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0); + (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0); qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ @@ -214,14 +210,25 @@ static int vmstate_acpi_post_load(void *opaque, int version_id) return 0; } +#define VMSTATE_GPE_ARRAY(_field, _state) \ + { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num = GPE_LEN, \ + .info = &vmstate_info_uint16, \ + .size = sizeof(uint16_t), \ + .flags = VMS_ARRAY | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ + } + static const VMStateDescription vmstate_gpe = { .name = "gpe", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT16(sts, struct gpe_regs), - VMSTATE_UINT16(en, struct gpe_regs), + VMSTATE_GPE_ARRAY(sts, ACPIGPE), + VMSTATE_GPE_ARRAY(en, ACPIGPE), VMSTATE_END_OF_LIST() } }; @@ -252,7 +259,7 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), VMSTATE_TIMER(tmr.timer, PIIX4PMState), VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), - VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs), + VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, struct pci_status), VMSTATE_END_OF_LIST() @@ -346,6 +353,7 @@ static int piix4_pm_initfn(PCIDevice *dev) register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); + acpi_gpe_init(&s->gpe, GPE_LEN); qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); @@ -399,74 +407,20 @@ static void piix4_pm_register(void) device_init(piix4_pm_register); -static uint32_t gpe_read_val(uint16_t val, uint32_t addr) -{ - if (addr & 1) - return (val >> 8) & 0xff; - return val & 0xff; -} - static uint32_t gpe_readb(void *opaque, uint32_t addr) { - uint32_t val = 0; PIIX4PMState *s = opaque; - struct gpe_regs *g = &s->gpe; - - switch (addr) { - case GPE_BASE: - case GPE_BASE + 1: - val = gpe_read_val(g->sts, addr); - break; - case GPE_BASE + 2: - case GPE_BASE + 3: - val = gpe_read_val(g->en, addr); - break; - default: - break; - } + uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr); PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); return val; } -static void gpe_write_val(uint16_t *cur, int addr, uint32_t val) -{ - if (addr & 1) - *cur = (*cur & 0xff) | (val << 8); - else - *cur = (*cur & 0xff00) | (val & 0xff); -} - -static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val) -{ - uint16_t x1, x0 = val & 0xff; - int shift = (addr & 1) ? 8 : 0; - - x1 = (*cur >> shift) & 0xff; - - x1 = x1 & ~x0; - - *cur = (*cur & (0xff << (8 - shift))) | (x1 << shift); -} - static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) { PIIX4PMState *s = opaque; - struct gpe_regs *g = &s->gpe; - - switch (addr) { - case GPE_BASE: - case GPE_BASE + 1: - gpe_reset_val(&g->sts, addr, val); - break; - case GPE_BASE + 2: - case GPE_BASE + 3: - gpe_write_val(&g->en, addr, val); - break; - default: - break; - } + acpi_gpe_ioport_writeb(&s->gpe, addr, val); pm_update_sci(s); PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); @@ -549,8 +503,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { struct pci_status *pci0_status = &s->pci0_status; - register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s); - register_ioport_read(GPE_BASE, 4, 1, gpe_readb, s); + register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); + register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); + acpi_gpe_blk(&s->gpe, GPE_BASE); register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); @@ -566,13 +521,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) static void enable_device(PIIX4PMState *s, int slot) { - s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS; + s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; s->pci0_status.up |= (1 << slot); } static void disable_device(PIIX4PMState *s, int slot) { - s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS; + s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; s->pci0_status.down |= (1 << slot); } From d04fba948fb945e467f263e820b1100d657c533d Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@web.de> Date: Sun, 10 Apr 2011 09:35:42 +0200 Subject: [PATCH 143/386] musicpal: Fix registration of MMIO-less sysbus devices The proper way to signal that a sysbus devices need no MMIO region is to pass -1 to sysbus_create_simple. Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/musicpal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/musicpal.c b/hw/musicpal.c index d98aa8d03c..52b2931d15 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1597,11 +1597,11 @@ static void musicpal_init(ram_addr_t ram_size, musicpal_misc_init(); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); - i2c_dev = sysbus_create_simple("gpio_i2c", 0, NULL); + i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c"); lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL); - key_dev = sysbus_create_simple("musicpal_key", 0, NULL); + key_dev = sysbus_create_simple("musicpal_key", -1, NULL); /* I2C read data */ qdev_connect_gpio_out(i2c_dev, 0, From 7b3da903041eae8e756d5dd29c492e5f043c9954 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Mon, 4 Apr 2011 16:32:11 +0200 Subject: [PATCH 144/386] s390x: set alignment for long to 8 The alignment for longs on s390x is 8. That's the only place where it differs from the default alignments found in configure already. The example alignment program from Laurent printed the following on a real s390x: alignof(short) 2 alignof(int) 4 alignof(long) 8 alignof(long long) 8 Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 2bb3faa07e..a4759ae817 100755 --- a/configure +++ b/configure @@ -3184,6 +3184,7 @@ case "$target_arch2" in s390x) target_nptl="yes" target_phys_bits=64 + target_long_alignment=8 ;; *) echo "Unsupported target CPU" From 8f16753fd6b584f34d47e102d290dbf4d5c94d46 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Mon, 4 Apr 2011 16:32:10 +0200 Subject: [PATCH 145/386] s390x: fix virtio feature bitmap The feature bitmap in the s390 virtio machine is little endian. To address for that, we need to bswap the values after reading them out. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/s390-virtio-bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 58af164880..60e0135ed8 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -223,7 +223,7 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) cur_offs += num_vq * VIRTIO_VQCONFIG_LEN; /* Sync feature bitmap */ - stl_phys(cur_offs, dev->host_features); + stl_phys(cur_offs, bswap32(dev->host_features)); dev->feat_offs = cur_offs + dev->feat_len; cur_offs += dev->feat_len * 2; @@ -246,7 +246,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev) /* Update guest supported feature bitmap */ - features = ldl_phys(dev->feat_offs); + features = bswap32(ldl_phys(dev->feat_offs)); if (vdev->set_features) { vdev->set_features(vdev, features); } From 8b2715a01e5dee434fbe070c3c855133203b2845 Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sat, 9 Apr 2011 14:25:25 +0000 Subject: [PATCH 146/386] ppc: remove a write-only variable Remove a write-only variable, spotted by GCC 4.6.0: /src/qemu/hw/ppc.c: In function 'power7_set_irq': /src/qemu/hw/ppc.c:255:9: error: variable 'cur_level' set but not used [-Werror=unused-but-set-variable] Acked-by: Alexander Graf <agraf@suse.de> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- hw/ppc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index dabb816510..18733289db 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -252,11 +252,9 @@ void ppc970_irq_init (CPUState *env) static void power7_set_irq (void *opaque, int pin, int level) { CPUState *env = opaque; - int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, env, pin, level); - cur_level = (env->irq_input_state >> pin) & 1; switch (pin) { case POWER7_INPUT_INT: From 7458a432f03bc9af031336af29fc6477de8c5e34 Mon Sep 17 00:00:00 2001 From: Alejandro Cabrera <aldaya@gmail.com> Date: Mon, 11 Apr 2011 23:07:58 +0200 Subject: [PATCH 147/386] microblaze: Correct MMU_ZONES mask Signed-off-by: Alejandro Cabrera <aldaya@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 14d4d42730..cc096474ff 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -194,7 +194,7 @@ struct CPUMBState; #define PVR11_MMU_ITLB_SIZE 0x38000000 #define PVR11_MMU_DTLB_SIZE 0x07000000 #define PVR11_MMU_TLB_ACCESS 0x00C00000 -#define PVR11_MMU_ZONES 0x003C0000 +#define PVR11_MMU_ZONES 0x003E0000 /* MSR Reset value PVR mask */ #define PVR11_MSR_RESET_VALUE_MASK 0x000007FF From 3b584046aae87df3ac195cc85b89ff86c1a8db01 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> Date: Mon, 11 Apr 2011 23:55:42 +0200 Subject: [PATCH 148/386] microblaze: Add constant for exception-code mask Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/cpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index cc096474ff..d0aee190ba 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -91,6 +91,7 @@ struct CPUMBState; #define ESR_EC_INSN_STORAGE 9 #define ESR_EC_DATA_TLB 10 #define ESR_EC_INSN_TLB 11 +#define ESR_EC_MASK 31 /* Floating Point Status Register (FSR) Bits */ #define FSR_IO (1<<4) /* Invalid operation */ From 2e42d52d95d613e38961727e6bac2028681340e3 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> Date: Mon, 11 Apr 2011 23:57:07 +0200 Subject: [PATCH 149/386] microblaze: Correct ec mask in debug print Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index e651bfdad8..91600877d2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2258,7 +2258,7 @@ void cpu_loop (CPUState *env) break; default: printf ("Unhandled hw-exception: 0x%x\n", - env->sregs[SR_ESR] & 5); + env->sregs[SR_ESR] & ESR_EC_MASK); cpu_dump_state(env, stderr, fprintf, 0); exit (1); break; From 8545364198da26f02f54343476947b8c11d17dfb Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> Date: Tue, 12 Apr 2011 00:42:28 +0200 Subject: [PATCH 150/386] microblaze: Add stream-insn related constants Based on a patch from: Alejandro Cabrera <aldaya@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/cpu.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index d0aee190ba..536222e4b8 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -79,6 +79,8 @@ struct CPUMBState; #define ESR_DIZ (1<<11) /* Zone Protection */ #define ESR_S (1<<10) /* Store instruction */ +#define ESR_ESS_FSL_OFFSET 5 + #define ESR_EC_FSL 0 #define ESR_EC_UNALIGNED_DATA 1 #define ESR_EC_ILLEGAL_OP 2 @@ -212,6 +214,13 @@ struct CPUMBState; #define CC_EQ 0 #define NB_MMU_MODES 3 + +#define STREAM_EXCEPTION (1 << 0) +#define STREAM_ATOMIC (1 << 1) +#define STREAM_TEST (1 << 2) +#define STREAM_CONTROL (1 << 3) +#define STREAM_NONBLOCK (1 << 4) + typedef struct CPUMBState { uint32_t debug; uint32_t btaken; From 6d76d23e82d0ce8a7874b13f5951aa763e059908 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com> Date: Tue, 12 Apr 2011 00:48:33 +0200 Subject: [PATCH 151/386] microblaze: Add partial decoding of stream insns Based on a patch from: Alejandro Cabrera <aldaya@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/helper.h | 3 +++ target-microblaze/microblaze-decode.h | 3 +++ target-microblaze/op_helper.c | 35 +++++++++++++++++++++++++ target-microblaze/translate.c | 37 +++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h index 1696b885b6..b92aa34d05 100644 --- a/target-microblaze/helper.h +++ b/target-microblaze/helper.h @@ -33,4 +33,7 @@ DEF_HELPER_2(mmu_write, void, i32, i32) DEF_HELPER_4(memalign, void, i32, i32, i32, i32) +DEF_HELPER_2(get, i32, i32, i32) +DEF_HELPER_3(put, void, i32, i32, i32) + #include "def-helper.h" diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h index 4a274768d3..401319ed46 100644 --- a/target-microblaze/microblaze-decode.h +++ b/target-microblaze/microblaze-decode.h @@ -50,3 +50,6 @@ #define DEC_BR {B8(00100110), B8(00110111)} #define DEC_BCC {B8(00100111), B8(00110111)} #define DEC_RTS {B8(00101101), B8(00111111)} + +#define DEC_STREAM {B8(00010011), B8(00110111)} + diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index d75a53cc54..39b8ec1e15 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -69,6 +69,41 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) } #endif +void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) +{ + int test = ctrl & STREAM_TEST; + int atomic = ctrl & STREAM_ATOMIC; + int control = ctrl & STREAM_CONTROL; + int nonblock = ctrl & STREAM_NONBLOCK; + int exception = ctrl & STREAM_EXCEPTION; + + qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", + id, data, + test ? "t" : "", + nonblock ? "n" : "", + exception ? "e" : "", + control ? "c" : "", + atomic ? "a" : ""); +} + +uint32_t helper_get(uint32_t id, uint32_t ctrl) +{ + int test = ctrl & STREAM_TEST; + int atomic = ctrl & STREAM_ATOMIC; + int control = ctrl & STREAM_CONTROL; + int nonblock = ctrl & STREAM_NONBLOCK; + int exception = ctrl & STREAM_EXCEPTION; + + qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n", + id, + test ? "t" : "", + nonblock ? "n" : "", + exception ? "e" : "", + control ? "c" : "", + atomic ? "a" : ""); + return 0xdead0000 | id; +} + void helper_raise_exception(uint32_t index) { env->exception_index = index; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 6f4eef1a69..bff3a11bc8 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1476,6 +1476,42 @@ static void dec_null(DisasContext *dc) dc->abort_at_next_insn = 1; } +/* Insns connected to FSL or AXI stream attached devices. */ +static void dec_stream(DisasContext *dc) +{ + int mem_index = cpu_mmu_index(dc->env); + TCGv_i32 t_id, t_ctrl; + int ctrl; + + LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put", + dc->type_b ? "" : "d", dc->imm); + + if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + + t_id = tcg_temp_new(); + if (dc->type_b) { + tcg_gen_movi_tl(t_id, dc->imm & 0xf); + ctrl = dc->imm >> 10; + } else { + tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf); + ctrl = dc->imm >> 5; + } + + t_ctrl = tcg_const_tl(ctrl); + + if (dc->rd == 0) { + gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); + } else { + gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); + } + tcg_temp_free(t_id); + tcg_temp_free(t_ctrl); +} + static struct decoder_info { struct { uint32_t bits; @@ -1500,6 +1536,7 @@ static struct decoder_info { {DEC_MUL, dec_mul}, {DEC_DIV, dec_div}, {DEC_MSR, dec_msr}, + {DEC_STREAM, dec_stream}, {{0, 0}, dec_null} }; From 6e64da3cd6890181fbeaaae7c08cfb779f138d82 Mon Sep 17 00:00:00 2001 From: Guan Xuetao <gxt@mprc.pku.edu.cn> Date: Tue, 12 Apr 2011 16:25:59 +0800 Subject: [PATCH 152/386] unicore32: add target-unicore32 directory for unicore32-linux-user support Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- target-unicore32/cpu.h | 182 +++ target-unicore32/exec.h | 50 + target-unicore32/helper.c | 487 ++++++++ target-unicore32/helper.h | 70 ++ target-unicore32/op_helper.c | 248 ++++ target-unicore32/translate.c | 2105 ++++++++++++++++++++++++++++++++++ 6 files changed, 3142 insertions(+) create mode 100644 target-unicore32/cpu.h create mode 100644 target-unicore32/exec.h create mode 100644 target-unicore32/helper.c create mode 100644 target-unicore32/helper.h create mode 100644 target-unicore32/op_helper.c create mode 100644 target-unicore32/translate.c diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h new file mode 100644 index 0000000000..1e10049f89 --- /dev/null +++ b/target-unicore32/cpu.h @@ -0,0 +1,182 @@ +/* + * UniCore32 virtual CPU header + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __CPU_UC32_H__ +#define __CPU_UC32_H__ + +#define TARGET_LONG_BITS 32 +#define TARGET_PAGE_BITS 12 + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 + +#define ELF_MACHINE EM_UNICORE32 + +#define CPUState struct CPUState_UniCore32 + +#include "cpu-defs.h" +#include "softfloat.h" + +#define NB_MMU_MODES 2 + +typedef struct CPUState_UniCore32 { + /* Regs for current mode. */ + uint32_t regs[32]; + /* Frequently accessed ASR bits are stored separately for efficiently. + This contains all the other bits. Use asr_{read,write} to access + the whole ASR. */ + uint32_t uncached_asr; + uint32_t bsr; + + /* Banked registers. */ + uint32_t banked_bsr[6]; + uint32_t banked_r29[6]; + uint32_t banked_r30[6]; + + /* asr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NF; /* N is bit 31. All other bits are undefined. */ + uint32_t ZF; /* Z set if zero. */ + + /* System control coprocessor (cp0) */ + struct { + uint32_t c0_cpuid; + uint32_t c0_cachetype; + uint32_t c1_sys; /* System control register. */ + uint32_t c2_base; /* MMU translation table base. */ + uint32_t c3_faultstatus; /* Fault status registers. */ + uint32_t c4_faultaddr; /* Fault address registers. */ + uint32_t c5_cacheop; /* Cache operation registers. */ + uint32_t c6_tlbop; /* TLB operation registers. */ + } cp0; + + /* UniCore-F64 coprocessor state. */ + struct { + float64 regs[16]; + uint32_t xregs[32]; + float_status fp_status; + } ucf64; + + CPU_COMMON + + /* Internal CPU feature flags. */ + uint32_t features; + +} CPUState_UniCore32; + +#define ASR_M (0x1f) +#define ASR_MODE_USER (0x10) +#define ASR_MODE_INTR (0x12) +#define ASR_MODE_PRIV (0x13) +#define ASR_MODE_TRAP (0x17) +#define ASR_MODE_EXTN (0x1b) +#define ASR_MODE_SUSR (0x1f) +#define ASR_I (1 << 7) +#define ASR_V (1 << 28) +#define ASR_C (1 << 29) +#define ASR_Z (1 << 30) +#define ASR_N (1 << 31) +#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V) +#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV)) + +#define UC32_EXCP_PRIV (ASR_MODE_PRIV) +#define UC32_EXCP_TRAP (ASR_MODE_TRAP) + +/* Return the current ASR value. */ +target_ulong cpu_asr_read(CPUState *env1); +/* Set the ASR. Note that some bits of mask must be all-set or all-clear. */ +void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask); + +/* UniCore-F64 system registers. */ +#define UC32_UCF64_FPSCR (31) +#define UCF64_FPSCR_MASK (0x27ffffff) +#define UCF64_FPSCR_RND_MASK (0x7) +#define UCF64_FPSCR_RND(r) (((r) >> 0) & UCF64_FPSCR_RND_MASK) +#define UCF64_FPSCR_TRAPEN_MASK (0x7f) +#define UCF64_FPSCR_TRAPEN(r) (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK) +#define UCF64_FPSCR_FLAG_MASK (0x3ff) +#define UCF64_FPSCR_FLAG(r) (((r) >> 17) & UCF64_FPSCR_FLAG_MASK) +#define UCF64_FPSCR_FLAG_ZERO (1 << 17) +#define UCF64_FPSCR_FLAG_INFINITY (1 << 18) +#define UCF64_FPSCR_FLAG_INVALID (1 << 19) +#define UCF64_FPSCR_FLAG_UNDERFLOW (1 << 20) +#define UCF64_FPSCR_FLAG_OVERFLOW (1 << 21) +#define UCF64_FPSCR_FLAG_INEXACT (1 << 22) +#define UCF64_FPSCR_FLAG_HUGEINT (1 << 23) +#define UCF64_FPSCR_FLAG_DENORMAL (1 << 24) +#define UCF64_FPSCR_FLAG_UNIMP (1 << 25) +#define UCF64_FPSCR_FLAG_DIVZERO (1 << 26) + +#define UC32_HWCAP_CMOV 4 /* 1 << 2 */ +#define UC32_HWCAP_UCF64 8 /* 1 << 3 */ + +#define UC32_CPUID(env) (env->cp0.c0_cpuid) +#define UC32_CPUID_UCV2 0x40010863 +#define UC32_CPUID_ANY 0xffffffff + +#define cpu_init uc32_cpu_init +#define cpu_exec uc32_cpu_exec +#define cpu_signal_handler uc32_cpu_signal_handler +#define cpu_handle_mmu_fault uc32_cpu_handle_mmu_fault + +CPUState *uc32_cpu_init(const char *cpu_model); +int uc32_cpu_exec(CPUState *s); +int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc); +int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmuu); + +#define CPU_SAVE_VERSION 2 + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index(CPUState *env) +{ + return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0; +} + +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) { + env->regs[29] = newsp; + } + env->regs[0] = 0; +} + +static inline void cpu_set_tls(CPUState *env, target_ulong newtls) +{ + env->regs[16] = newtls; +} + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->regs[31] = tb->pc; +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->regs[31]; + *cs_base = 0; + *flags = 0; + if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) { + *flags |= (1 << 6); + } +} + +void uc32_translate_init(void); +void do_interrupt(CPUState *); +void switch_mode(CPUState_UniCore32 *, int); + +#endif /* __CPU_UC32_H__ */ diff --git a/target-unicore32/exec.h b/target-unicore32/exec.h new file mode 100644 index 0000000000..4ab55f42cf --- /dev/null +++ b/target-unicore32/exec.h @@ -0,0 +1,50 @@ +/* + * UniCore32 execution defines + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __UC32_EXEC_H__ +#define __UC32_EXEC_H__ + +#include "config.h" +#include "dyngen-exec.h" + +register struct CPUState_UniCore32 *env asm(AREG0); + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +static inline int cpu_has_work(CPUState *env) +{ + return env->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); +} + +static inline int cpu_halted(CPUState *env) +{ + if (!env->halted) { + return 0; + } + /* An interrupt wakes the CPU even if the I and R ASR bits are + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (cpu_has_work(env)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + +#endif /* __UC32_EXEC_H__ */ diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c new file mode 100644 index 0000000000..483aeaeb14 --- /dev/null +++ b/target-unicore32/helper.c @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "helper.h" +#include "qemu-common.h" +#include "host-utils.h" + +static inline void set_feature(CPUState *env, int feature) +{ + env->features |= feature; +} + +struct uc32_cpu_t { + uint32_t id; + const char *name; +}; + +static const struct uc32_cpu_t uc32_cpu_names[] = { + { UC32_CPUID_UCV2, "UniCore-II"}, + { UC32_CPUID_ANY, "any"}, + { 0, NULL} +}; + +/* return 0 if not found */ +static uint32_t uc32_cpu_find_by_name(const char *name) +{ + int i; + uint32_t id; + + id = 0; + for (i = 0; uc32_cpu_names[i].name; i++) { + if (strcmp(name, uc32_cpu_names[i].name) == 0) { + id = uc32_cpu_names[i].id; + break; + } + } + return id; +} + +CPUState *uc32_cpu_init(const char *cpu_model) +{ + CPUState *env; + uint32_t id; + static int inited = 1; + + env = qemu_mallocz(sizeof(CPUState)); + cpu_exec_init(env); + + id = uc32_cpu_find_by_name(cpu_model); + switch (id) { + case UC32_CPUID_UCV2: + set_feature(env, UC32_HWCAP_CMOV); + set_feature(env, UC32_HWCAP_UCF64); + env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; + env->cp0.c0_cachetype = 0x1dd20d2; + env->cp0.c1_sys = 0x00090078; + break; + case UC32_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, UC32_HWCAP_CMOV); + set_feature(env, UC32_HWCAP_UCF64); + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + } + + env->cpu_model_str = cpu_model; + env->cp0.c0_cpuid = id; + env->uncached_asr = ASR_MODE_USER; + env->regs[31] = 0; + + if (inited) { + inited = 0; + uc32_translate_init(); + } + + tlb_flush(env, 1); + qemu_init_vcpu(env); + return env; +} + +uint32_t HELPER(clo)(uint32_t x) +{ + return clo32(x); +} + +uint32_t HELPER(clz)(uint32_t x) +{ + return clz32(x); +} + +void do_interrupt(CPUState *env) +{ + env->exception_index = -1; +} + +int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + env->exception_index = UC32_EXCP_TRAP; + env->cp0.c4_faultaddr = address; + return 1; +} + +/* These should probably raise undefined insn exceptions. */ +void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return; +} + +uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return 0; +} + +void HELPER(set_cp0)(CPUState *env, uint32_t insn, uint32_t val) +{ + cpu_abort(env, "cp0 insn %08x\n", insn); +} + +uint32_t HELPER(get_cp0)(CPUState *env, uint32_t insn) +{ + cpu_abort(env, "cp0 insn %08x\n", insn); + return 0; +} + +void switch_mode(CPUState *env, int mode) +{ + if (mode != ASR_MODE_USER) { + cpu_abort(env, "Tried to switch out of user mode\n"); + } +} + +void HELPER(set_r29_banked)(CPUState *env, uint32_t mode, uint32_t val) +{ + cpu_abort(env, "banked r29 write\n"); +} + +uint32_t HELPER(get_r29_banked)(CPUState *env, uint32_t mode) +{ + cpu_abort(env, "banked r29 read\n"); + return 0; +} + +/* UniCore-F64 support. We follow the convention used for F64 instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to f64 form. */ +static inline int ucf64_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) { + target_bits |= UCF64_FPSCR_FLAG_INVALID; + } + if (host_bits & float_flag_divbyzero) { + target_bits |= UCF64_FPSCR_FLAG_DIVZERO; + } + if (host_bits & float_flag_overflow) { + target_bits |= UCF64_FPSCR_FLAG_OVERFLOW; + } + if (host_bits & float_flag_underflow) { + target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW; + } + if (host_bits & float_flag_inexact) { + target_bits |= UCF64_FPSCR_FLAG_INEXACT; + } + return target_bits; +} + +uint32_t HELPER(ucf64_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK); + i = get_float_exception_flags(&env->ucf64.fp_status); + fpscr |= ucf64_exceptbits_from_host(i); + return fpscr; +} + +/* Convert ucf64 exception flags to target form. */ +static inline int ucf64_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & UCF64_FPSCR_FLAG_INVALID) { + host_bits |= float_flag_invalid; + } + if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) { + host_bits |= float_flag_divbyzero; + } + if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) { + host_bits |= float_flag_overflow; + } + if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) { + host_bits |= float_flag_underflow; + } + if (target_bits & UCF64_FPSCR_FLAG_INEXACT) { + host_bits |= float_flag_inexact; + } + return host_bits; +} + +void HELPER(ucf64_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->ucf64.xregs[UC32_UCF64_FPSCR]; + env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK); + + changed ^= val; + if (changed & (UCF64_FPSCR_RND_MASK)) { + i = UCF64_FPSCR_RND(val); + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_to_zero; + break; + case 2: + i = float_round_up; + break; + case 3: + i = float_round_down; + break; + default: /* 100 and 101 not implement */ + cpu_abort(env, "Unsupported UniCore-F64 round mode"); + } + set_float_rounding_mode(i, &env->ucf64.fp_status); + } + + i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val)); + set_float_exception_flags(i, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUState *env) +{ + return float32_add(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUState *env) +{ + return float64_add(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUState *env) +{ + return float32_sub(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUState *env) +{ + return float64_sub(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUState *env) +{ + return float32_mul(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUState *env) +{ + return float64_mul(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUState *env) +{ + return float32_div(a, b, &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUState *env) +{ + return float64_div(a, b, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_negs)(float32 a) +{ + return float32_chs(a); +} + +float64 HELPER(ucf64_negd)(float64 a) +{ + return float64_chs(a); +} + +float32 HELPER(ucf64_abss)(float32 a) +{ + return float32_abs(a); +} + +float64 HELPER(ucf64_absd)(float64 a) +{ + return float64_abs(a); +} + +/* XXX: check quiet/signaling case */ +void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUState *env) +{ + int flag; + flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); + env->CF = 0; + switch (c & 0x7) { + case 0: /* F */ + break; + case 1: /* UN */ + if (flag == 2) { + env->CF = 1; + } + break; + case 2: /* EQ */ + if (flag == 0) { + env->CF = 1; + } + break; + case 3: /* UEQ */ + if ((flag == 0) || (flag == 2)) { + env->CF = 1; + } + break; + case 4: /* OLT */ + if (flag == -1) { + env->CF = 1; + } + break; + case 5: /* ULT */ + if ((flag == -1) || (flag == 2)) { + env->CF = 1; + } + break; + case 6: /* OLE */ + if ((flag == -1) || (flag == 0)) { + env->CF = 1; + } + break; + case 7: /* ULE */ + if (flag != 1) { + env->CF = 1; + } + break; + } + env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) + | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); +} + +void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUState *env) +{ + int flag; + flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); + env->CF = 0; + switch (c & 0x7) { + case 0: /* F */ + break; + case 1: /* UN */ + if (flag == 2) { + env->CF = 1; + } + break; + case 2: /* EQ */ + if (flag == 0) { + env->CF = 1; + } + break; + case 3: /* UEQ */ + if ((flag == 0) || (flag == 2)) { + env->CF = 1; + } + break; + case 4: /* OLT */ + if (flag == -1) { + env->CF = 1; + } + break; + case 5: /* ULT */ + if ((flag == -1) || (flag == 2)) { + env->CF = 1; + } + break; + case 6: /* OLE */ + if ((flag == -1) || (flag == 0)) { + env->CF = 1; + } + break; + case 7: /* ULE */ + if (flag != 1) { + env->CF = 1; + } + break; + } + env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) + | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); +} + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 ucf64_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t ucf64_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 ucf64_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t ucf64_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 HELPER(ucf64_si2sf)(float32 x, CPUState *env) +{ + return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status); +} + +float64 HELPER(ucf64_si2df)(float32 x, CPUState *env) +{ + return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status); +} + +/* Float to integer conversion. */ +float32 HELPER(ucf64_sf2si)(float32 x, CPUState *env) +{ + return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status)); +} + +float32 HELPER(ucf64_df2si)(float64 x, CPUState *env) +{ + return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status)); +} + +/* floating point conversion */ +float64 HELPER(ucf64_sf2df)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->ucf64.fp_status); +} + +float32 HELPER(ucf64_df2sf)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->ucf64.fp_status); +} diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h new file mode 100644 index 0000000000..615de2add9 --- /dev/null +++ b/target-unicore32/helper.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "def-helper.h" + +DEF_HELPER_1(clz, i32, i32) +DEF_HELPER_1(clo, i32, i32) + +DEF_HELPER_1(exception, void, i32) + +DEF_HELPER_2(asr_write, void, i32, i32) +DEF_HELPER_0(asr_read, i32) + +DEF_HELPER_3(set_cp0, void, env, i32, i32) +DEF_HELPER_2(get_cp0, i32, env, i32) + +DEF_HELPER_3(set_cp, void, env, i32, i32) +DEF_HELPER_2(get_cp, i32, env, i32) + +DEF_HELPER_1(get_user_reg, i32, i32) +DEF_HELPER_2(set_user_reg, void, i32, i32) + +DEF_HELPER_2(add_cc, i32, i32, i32) +DEF_HELPER_2(adc_cc, i32, i32, i32) +DEF_HELPER_2(sub_cc, i32, i32, i32) +DEF_HELPER_2(sbc_cc, i32, i32, i32) + +DEF_HELPER_2(shl, i32, i32, i32) +DEF_HELPER_2(shr, i32, i32, i32) +DEF_HELPER_2(sar, i32, i32, i32) +DEF_HELPER_2(shl_cc, i32, i32, i32) +DEF_HELPER_2(shr_cc, i32, i32, i32) +DEF_HELPER_2(sar_cc, i32, i32, i32) +DEF_HELPER_2(ror_cc, i32, i32, i32) + +DEF_HELPER_2(get_r29_banked, i32, env, i32) +DEF_HELPER_3(set_r29_banked, void, env, i32, i32) + +DEF_HELPER_1(ucf64_get_fpscr, i32, env) +DEF_HELPER_2(ucf64_set_fpscr, void, env, i32) + +DEF_HELPER_3(ucf64_adds, f32, f32, f32, env) +DEF_HELPER_3(ucf64_addd, f64, f64, f64, env) +DEF_HELPER_3(ucf64_subs, f32, f32, f32, env) +DEF_HELPER_3(ucf64_subd, f64, f64, f64, env) +DEF_HELPER_3(ucf64_muls, f32, f32, f32, env) +DEF_HELPER_3(ucf64_muld, f64, f64, f64, env) +DEF_HELPER_3(ucf64_divs, f32, f32, f32, env) +DEF_HELPER_3(ucf64_divd, f64, f64, f64, env) +DEF_HELPER_1(ucf64_negs, f32, f32) +DEF_HELPER_1(ucf64_negd, f64, f64) +DEF_HELPER_1(ucf64_abss, f32, f32) +DEF_HELPER_1(ucf64_absd, f64, f64) +DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env) +DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env) + +DEF_HELPER_2(ucf64_sf2df, f64, f32, env) +DEF_HELPER_2(ucf64_df2sf, f32, f64, env) + +DEF_HELPER_2(ucf64_si2sf, f32, f32, env) +DEF_HELPER_2(ucf64_si2df, f64, f32, env) + +DEF_HELPER_2(ucf64_sf2si, f32, f32, env) +DEF_HELPER_2(ucf64_df2si, f32, f64, env) + +#include "def-helper.h" diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c new file mode 100644 index 0000000000..31e4b11e43 --- /dev/null +++ b/target-unicore32/op_helper.c @@ -0,0 +1,248 @@ +/* + * UniCore32 helper routines + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "exec.h" +#include "helper.h" + +#define SIGNBIT (uint32_t)0x80000000 +#define SIGNBIT64 ((uint64_t)1 << 63) + +void HELPER(exception)(uint32_t excp) +{ + env->exception_index = excp; + cpu_loop_exit(); +} + +static target_ulong asr_read(void) +{ + int ZF; + ZF = (env->ZF == 0); + return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} + +target_ulong cpu_asr_read(CPUState *env1) +{ + CPUState *saved_env; + target_ulong ret; + + saved_env = env; + env = env1; + ret = asr_read(); + env = saved_env; + return ret; +} + +target_ulong HELPER(asr_read)(void) +{ + return asr_read(); +} + +static void asr_write(target_ulong val, target_ulong mask) +{ + if (mask & ASR_NZCV) { + env->ZF = (~val) & ASR_Z; + env->NF = val; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + + if ((env->uncached_asr ^ val) & mask & ASR_M) { + switch_mode(env, val & ASR_M); + } + mask &= ~ASR_NZCV; + env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask); +} + +void cpu_asr_write(CPUState *env1, target_ulong val, target_ulong mask) +{ + CPUState *saved_env; + + saved_env = env; + env = env1; + asr_write(val, mask); + env = saved_env; +} + +void HELPER(asr_write)(target_ulong val, target_ulong mask) +{ + asr_write(val, mask); +} + +/* Access to user mode registers from privileged modes. */ +uint32_t HELPER(get_user_reg)(uint32_t regno) +{ + uint32_t val; + + if (regno == 29) { + val = env->banked_r29[0]; + } else if (regno == 30) { + val = env->banked_r30[0]; + } else { + val = env->regs[regno]; + } + return val; +} + +void HELPER(set_user_reg)(uint32_t regno, uint32_t val) +{ + if (regno == 29) { + env->banked_r29[0] = val; + } else if (regno == 30) { + env->banked_r30[0] = val; + } else { + env->regs[regno] = val; + } +} + +/* ??? Flag setting arithmetic is awkward because we need to do comparisons. + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +uint32_t HELPER(add_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a + b; + env->NF = env->ZF = result; + env->CF = result < a; + env->VF = (a ^ b ^ -1) & (a ^ result); + return result; +} + +uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a + b; + env->CF = result < a; + } else { + result = a + b + 1; + env->CF = result <= a; + } + env->VF = (a ^ b ^ -1) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + result = a - b; + env->NF = env->ZF = result; + env->CF = a >= b; + env->VF = (a ^ b) & (a ^ result); + return result; +} + +uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) +{ + uint32_t result; + if (!env->CF) { + result = a - b - 1; + env->CF = a > b; + } else { + result = a - b; + env->CF = a >= b; + } + env->VF = (a ^ b) & (a ^ result); + env->NF = env->ZF = result; + return result; +} + +/* Similarly for variable shift instructions. */ + +uint32_t HELPER(shl)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + return 0; + } + return x << shift; +} + +uint32_t HELPER(shr)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + return 0; + } + return (uint32_t)x >> shift; +} + +uint32_t HELPER(sar)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + shift = 31; + } + return (int32_t)x >> shift; +} + +uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) { + env->CF = x & 1; + } else { + env->CF = 0; + } + return 0; + } else if (shift != 0) { + env->CF = (x >> (32 - shift)) & 1; + return x << shift; + } + return x; +} + +uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + if (shift == 32) { + env->CF = (x >> 31) & 1; + } else { + env->CF = 0; + } + return 0; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return x >> shift; + } + return x; +} + +uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) +{ + int shift = i & 0xff; + if (shift >= 32) { + env->CF = (x >> 31) & 1; + return (int32_t)x >> 31; + } else if (shift != 0) { + env->CF = (x >> (shift - 1)) & 1; + return (int32_t)x >> shift; + } + return x; +} + +uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) +{ + int shift1, shift; + shift1 = i & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) { + env->CF = (x >> 31) & 1; + } + return x; + } else { + env->CF = (x >> (shift - 1)) & 1; + return ((uint32_t)x >> shift) | (x << (32 - shift)); + } +} diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c new file mode 100644 index 0000000000..a6ba991e92 --- /dev/null +++ b/target-unicore32/translate.c @@ -0,0 +1,2105 @@ +/* + * UniCore32 translation + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +#include "helper.h" +#define GEN_HELPER 1 +#include "helper.h" + +/* internal defines */ +typedef struct DisasContext { + target_ulong pc; + int is_jmp; + /* Nonzero if this instruction has been conditionally skipped. */ + int condjmp; + /* The label that will be jumped to when the instruction is skipped. */ + int condlabel; + struct TranslationBlock *tb; + int singlestep_enabled; +} DisasContext; + +#define IS_USER(s) 1 + +/* These instructions trap after executing, so defer them until after the + conditional executions state has been updated. */ +#define DISAS_SYSCALL 5 + +static TCGv_ptr cpu_env; +static TCGv_i32 cpu_R[32]; + +/* FIXME: These should be removed. */ +static TCGv cpu_F0s, cpu_F1s; +static TCGv_i64 cpu_F0d, cpu_F1d; + +#include "gen-icount.h" + +static const char *regnames[] = { + "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", + "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" }; + +/* initialize TCG globals. */ +void uc32_translate_init(void) +{ + int i; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + for (i = 0; i < 32; i++) { + cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, regs[i]), regnames[i]); + } + +#define GEN_HELPER 2 +#include "helper.h" +} + +static int num_temps; + +/* Allocate a temporary variable. */ +static TCGv_i32 new_tmp(void) +{ + num_temps++; + return tcg_temp_new_i32(); +} + +/* Release a temporary variable. */ +static void dead_tmp(TCGv tmp) +{ + tcg_temp_free(tmp); + num_temps--; +} + +static inline TCGv load_cpu_offset(int offset) +{ + TCGv tmp = new_tmp(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name)) + +static inline void store_cpu_offset(TCGv var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + dead_tmp(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUState, name)) + +/* Set a variable to the value of a CPU register. */ +static void load_reg_var(DisasContext *s, TCGv var, int reg) +{ + if (reg == 31) { + uint32_t addr; + /* normaly, since we updated PC */ + addr = (long)s->pc; + tcg_gen_movi_i32(var, addr); + } else { + tcg_gen_mov_i32(var, cpu_R[reg]); + } +} + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv load_reg(DisasContext *s, int reg) +{ + TCGv tmp = new_tmp(); + load_reg_var(s, tmp, reg); + return tmp; +} + +/* Set a CPU register. The source must be a temporary and will be + marked as dead. */ +static void store_reg(DisasContext *s, int reg, TCGv var) +{ + if (reg == 31) { + tcg_gen_andi_i32(var, var, ~3); + s->is_jmp = DISAS_JUMP; + } + tcg_gen_mov_i32(cpu_R[reg], var); + dead_tmp(var); +} + +/* Value extensions. */ +#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) +#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) +#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) +#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) + +#define UCOP_REG_M (((insn) >> 0) & 0x1f) +#define UCOP_REG_N (((insn) >> 19) & 0x1f) +#define UCOP_REG_D (((insn) >> 14) & 0x1f) +#define UCOP_REG_S (((insn) >> 9) & 0x1f) +#define UCOP_REG_LO (((insn) >> 14) & 0x1f) +#define UCOP_REG_HI (((insn) >> 9) & 0x1f) +#define UCOP_SH_OP (((insn) >> 6) & 0x03) +#define UCOP_SH_IM (((insn) >> 9) & 0x1f) +#define UCOP_OPCODES (((insn) >> 25) & 0x0f) +#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff) +#define UCOP_IMM10 (((insn) >> 0) & 0x3ff) +#define UCOP_IMM14 (((insn) >> 0) & 0x3fff) +#define UCOP_COND (((insn) >> 25) & 0x0f) +#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f) +#define UCOP_CPNUM (((insn) >> 10) & 0x0f) +#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03) +#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f) +#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f) + +#define UCOP_SET(i) ((insn) & (1 << (i))) +#define UCOP_SET_P UCOP_SET(28) +#define UCOP_SET_U UCOP_SET(27) +#define UCOP_SET_B UCOP_SET(26) +#define UCOP_SET_W UCOP_SET(25) +#define UCOP_SET_L UCOP_SET(24) +#define UCOP_SET_S UCOP_SET(24) + +#define ILLEGAL cpu_abort(env, \ + "Illegal UniCore32 instruction %x at line %d!", \ + insn, __LINE__) + +static inline void gen_set_asr(TCGv var, uint32_t mask) +{ + TCGv tmp_mask = tcg_const_i32(mask); + gen_helper_asr_write(var, tmp_mask); + tcg_temp_free_i32(tmp_mask); +} +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV) + +static void gen_exception(int excp) +{ + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); + gen_helper_exception(tmp); + dead_tmp(tmp); +} + +/* FIXME: Most targets have native widening multiplication. + It would be good to use that instead of a full wide multiply. */ +/* 32x32->64 multiply. Marks inputs as dead. */ +static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_extu_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) +{ + TCGv_i64 tmp1 = tcg_temp_new_i64(); + TCGv_i64 tmp2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(tmp1, a); + dead_tmp(a); + tcg_gen_ext_i32_i64(tmp2, b); + dead_tmp(b); + tcg_gen_mul_i64(tmp1, tmp1, tmp2); + tcg_temp_free_i64(tmp2); + return tmp1; +} + +#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF)) + +/* Set CF to the top bit of var. */ +static void gen_set_CF_bit31(TCGv var) +{ + TCGv tmp = new_tmp(); + tcg_gen_shri_i32(tmp, var, 31); + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Set N and Z flags from var. */ +static inline void gen_logic_CC(TCGv var) +{ + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF)); + tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF)); +} + +/* dest = T0 + T1 + CF. */ +static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + dead_tmp(tmp); +} + +/* dest = T0 - T1 + CF - 1. */ +static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(dest, t0, t1); + tmp = load_cpu_field(CF); + tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_subi_i32(dest, dest, 1); + dead_tmp(tmp); +} + +static void shifter_out_im(TCGv var, int shift) +{ + TCGv tmp = new_tmp(); + if (shift == 0) { + tcg_gen_andi_i32(tmp, var, 1); + } else { + tcg_gen_shri_i32(tmp, var, shift); + if (shift != 31) { + tcg_gen_andi_i32(tmp, tmp, 1); + } + } + gen_set_CF(tmp); + dead_tmp(tmp); +} + +/* Shift by immediate. Includes special handling for shift == 0. */ +static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift, + int flags) +{ + switch (shiftop) { + case 0: /* LSL */ + if (shift != 0) { + if (flags) { + shifter_out_im(var, 32 - shift); + } + tcg_gen_shli_i32(var, var, shift); + } + break; + case 1: /* LSR */ + if (shift == 0) { + if (flags) { + tcg_gen_shri_i32(var, var, 31); + gen_set_CF(var); + } + tcg_gen_movi_i32(var, 0); + } else { + if (flags) { + shifter_out_im(var, shift - 1); + } + tcg_gen_shri_i32(var, var, shift); + } + break; + case 2: /* ASR */ + if (shift == 0) { + shift = 32; + } + if (flags) { + shifter_out_im(var, shift - 1); + } + if (shift == 32) { + shift = 31; + } + tcg_gen_sari_i32(var, var, shift); + break; + case 3: /* ROR/RRX */ + if (shift != 0) { + if (flags) { + shifter_out_im(var, shift - 1); + } + tcg_gen_rotri_i32(var, var, shift); break; + } else { + TCGv tmp = load_cpu_field(CF); + if (flags) { + shifter_out_im(var, 0); + } + tcg_gen_shri_i32(var, var, 1); + tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_or_i32(var, var, tmp); + dead_tmp(tmp); + } + } +}; + +static inline void gen_uc32_shift_reg(TCGv var, int shiftop, + TCGv shift, int flags) +{ + if (flags) { + switch (shiftop) { + case 0: + gen_helper_shl_cc(var, var, shift); + break; + case 1: + gen_helper_shr_cc(var, var, shift); + break; + case 2: + gen_helper_sar_cc(var, var, shift); + break; + case 3: + gen_helper_ror_cc(var, var, shift); + break; + } + } else { + switch (shiftop) { + case 0: + gen_helper_shl(var, var, shift); + break; + case 1: + gen_helper_shr(var, var, shift); + break; + case 2: + gen_helper_sar(var, var, shift); + break; + case 3: + tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_rotr_i32(var, var, shift); + break; + } + } + dead_tmp(shift); +} + +static void gen_test_cc(int cc, int label) +{ + TCGv tmp; + TCGv tmp2; + int inv; + + switch (cc) { + case 0: /* eq: Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 1: /* ne: !Z */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 2: /* cs: C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + break; + case 3: /* cc: !C */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 4: /* mi: N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 5: /* pl: !N */ + tmp = load_cpu_field(NF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 6: /* vs: V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 7: /* vc: !V */ + tmp = load_cpu_field(VF); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 8: /* hi: C && !Z */ + inv = gen_new_label(); + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + gen_set_label(inv); + break; + case 9: /* ls: !C || Z */ + tmp = load_cpu_field(CF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + break; + case 10: /* ge: N == V -> N ^ V == 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + break; + case 11: /* lt: N != V -> N ^ V != 0 */ + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + case 12: /* gt: !Z && N == V */ + inv = gen_new_label(); + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + gen_set_label(inv); + break; + case 13: /* le: Z || N != V */ + tmp = load_cpu_field(ZF); + tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + dead_tmp(tmp); + tmp = load_cpu_field(VF); + tmp2 = load_cpu_field(NF); + tcg_gen_xor_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + break; + default: + fprintf(stderr, "Bad condition code 0x%x\n", cc); + abort(); + } + dead_tmp(tmp); +} + +static const uint8_t table_logic_cc[16] = { + 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */ + 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */ + 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */ + 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */ +}; + +/* Set PC state from an immediate address. */ +static inline void gen_bx_im(DisasContext *s, uint32_t addr) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_movi_i32(cpu_R[31], addr & ~3); +} + +/* Set PC state from var. var is marked as dead. */ +static inline void gen_bx(DisasContext *s, TCGv var) +{ + s->is_jmp = DISAS_UPDATE; + tcg_gen_andi_i32(cpu_R[31], var, ~3); + dead_tmp(var); +} + +static inline void store_reg_bx(DisasContext *s, int reg, TCGv var) +{ + store_reg(s, reg, var); +} + +static inline TCGv gen_ld8s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8s(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld8u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld8u(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld16s(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16s(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld16u(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld16u(tmp, addr, index); + return tmp; +} + +static inline TCGv gen_ld32(TCGv addr, int index) +{ + TCGv tmp = new_tmp(); + tcg_gen_qemu_ld32u(tmp, addr, index); + return tmp; +} + +static inline TCGv_i64 gen_ld64(TCGv addr, int index) +{ + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp, addr, index); + return tmp; +} + +static inline void gen_st8(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st8(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st16(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st16(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st32(TCGv val, TCGv addr, int index) +{ + tcg_gen_qemu_st32(val, addr, index); + dead_tmp(val); +} + +static inline void gen_st64(TCGv_i64 val, TCGv addr, int index) +{ + tcg_gen_qemu_st64(val, addr, index); + tcg_temp_free_i64(val); +} + +static inline void gen_set_pc_im(uint32_t val) +{ + tcg_gen_movi_i32(cpu_R[31], val); +} + +/* Force a TB lookup after an instruction that changes the CPU state. */ +static inline void gen_lookup_tb(DisasContext *s) +{ + tcg_gen_movi_i32(cpu_R[31], s->pc & ~1); + s->is_jmp = DISAS_UPDATE; +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val; + TCGv offset; + + if (UCOP_SET(29)) { + /* immediate */ + val = UCOP_IMM14; + if (!UCOP_SET_U) { + val = -val; + } + if (val != 0) { + tcg_gen_addi_i32(var, var, val); + } + } else { + /* shift/register */ + offset = load_reg(s, UCOP_REG_M); + gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0); + if (!UCOP_SET_U) { + tcg_gen_sub_i32(var, var, offset); + } else { + tcg_gen_add_i32(var, var, offset); + } + dead_tmp(offset); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, + TCGv var) +{ + int val; + TCGv offset; + + if (UCOP_SET(26)) { + /* immediate */ + val = (insn & 0x1f) | ((insn >> 4) & 0x3e0); + if (!UCOP_SET_U) { + val = -val; + } + if (val != 0) { + tcg_gen_addi_i32(var, var, val); + } + } else { + /* register */ + offset = load_reg(s, UCOP_REG_M); + if (!UCOP_SET_U) { + tcg_gen_sub_i32(var, var, offset); + } else { + tcg_gen_add_i32(var, var, offset); + } + dead_tmp(offset); + } +} + +static inline long ucf64_reg_offset(int reg) +{ + if (reg & 1) { + return offsetof(CPUState, ucf64.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUState, ucf64.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} + +#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg)) +#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg)) + +/* UniCore-F64 single load/store I_offset */ +static void do_ucf64_ldst_i(CPUState *env, DisasContext *s, uint32_t insn) +{ + int offset; + TCGv tmp; + TCGv addr; + + addr = load_reg(s, UCOP_REG_N); + if (!UCOP_SET_P && !UCOP_SET_W) { + ILLEGAL; + } + + if (UCOP_SET_P) { + offset = UCOP_IMM10 << 2; + if (!UCOP_SET_U) { + offset = -offset; + } + if (offset != 0) { + tcg_gen_addi_i32(addr, addr, offset); + } + } + + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + ucf64_gen_st32(tmp, UCOP_REG_D); + } else { /* store */ + tmp = ucf64_gen_ld32(UCOP_REG_D); + gen_st32(tmp, addr, IS_USER(s)); + } + + if (!UCOP_SET_P) { + offset = UCOP_IMM10 << 2; + if (!UCOP_SET_U) { + offset = -offset; + } + if (offset != 0) { + tcg_gen_addi_i32(addr, addr, offset); + } + } + if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } +} + +/* UniCore-F64 load/store multiple words */ +static void do_ucf64_ldst_m(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int i; + int j, n, freg; + TCGv tmp; + TCGv addr; + + if (UCOP_REG_D != 0) { + ILLEGAL; + } + if (UCOP_REG_N == 31) { + ILLEGAL; + } + if ((insn << 24) == 0) { + ILLEGAL; + } + + addr = load_reg(s, UCOP_REG_N); + + n = 0; + for (i = 0; i < 8; i++) { + if (UCOP_SET(i)) { + n++; + } + } + + if (UCOP_SET_U) { + if (UCOP_SET_P) { /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } /* unnecessary to do anything when post increment */ + } else { + if (UCOP_SET_P) { /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { /* post decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + } + + freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */ + + for (i = 0, j = 0; i < 8; i++, freg++) { + if (!UCOP_SET(i)) { + continue; + } + + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + ucf64_gen_st32(tmp, freg); + } else { /* store */ + tmp = ucf64_gen_ld32(freg); + gen_st32(tmp, addr, IS_USER(s)); + } + + j++; + /* unnecessary to add after the last transfer */ + if (j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + + if (UCOP_SET_W) { /* write back */ + if (UCOP_SET_U) { + if (!UCOP_SET_P) { /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } /* unnecessary to do anything when pre increment */ + } else { + if (UCOP_SET_P) { + /* pre decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } +} + +/* UniCore-F64 mrc/mcr */ +static void do_ucf64_trans(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + + if ((insn & 0xfe0003ff) == 0xe2000000) { + /* control register */ + if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) { + ILLEGAL; + } + if (UCOP_SET(24)) { + /* CFF */ + tmp = new_tmp(); + gen_helper_ucf64_get_fpscr(tmp, cpu_env); + store_reg(s, UCOP_REG_D, tmp); + } else { + /* CTF */ + tmp = load_reg(s, UCOP_REG_D); + gen_helper_ucf64_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); + gen_lookup_tb(s); + } + return; + } + if ((insn & 0xfe0003ff) == 0xe0000000) { + /* general register */ + if (UCOP_REG_D == 31) { + ILLEGAL; + } + if (UCOP_SET(24)) { /* MFF */ + tmp = ucf64_gen_ld32(UCOP_REG_N); + store_reg(s, UCOP_REG_D, tmp); + } else { /* MTF */ + tmp = load_reg(s, UCOP_REG_D); + ucf64_gen_st32(tmp, UCOP_REG_N); + } + return; + } + if ((insn & 0xfb000000) == 0xe9000000) { + /* MFFC */ + if (UCOP_REG_D != 31) { + ILLEGAL; + } + if (UCOP_UCF64_COND & 0x8) { + ILLEGAL; + } + + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, UCOP_UCF64_COND); + if (UCOP_SET(26)) { + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env); + } else { + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env); + } + dead_tmp(tmp); + return; + } + ILLEGAL; +} + +/* UniCore-F64 convert instructions */ +static void do_ucf64_fcvt(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_UCF64_FMT == 3) { + ILLEGAL; + } + if (UCOP_REG_N != 0) { + ILLEGAL; + } + switch (UCOP_UCF64_FUNC) { + case 0: /* cvt.s */ + switch (UCOP_UCF64_FMT) { + case 1 /* d */: + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 2 /* w */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* s */: + ILLEGAL; + break; + } + break; + case 1: /* cvt.d */ + switch (UCOP_UCF64_FMT) { + case 0 /* s */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env); + tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 2 /* w */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env); + tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* d */: + ILLEGAL; + break; + } + break; + case 4: /* cvt.w */ + switch (UCOP_UCF64_FMT) { + case 0 /* s */: + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + case 1 /* d */: + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env); + tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); + break; + default /* w */: + ILLEGAL; + break; + } + break; + default: + ILLEGAL; + } +} + +/* UniCore-F64 compare instructions */ +static void do_ucf64_fcmp(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_SET(25)) { + ILLEGAL; + } + if (UCOP_REG_D != 0) { + ILLEGAL; + } + + ILLEGAL; /* TODO */ + if (UCOP_SET(24)) { + tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */ + } else { + tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); + tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); + /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */ + } +} + +#define gen_helper_ucf64_movs(x, y) do { } while (0) +#define gen_helper_ucf64_movd(x, y) do { } while (0) + +#define UCF64_OP1(name) do { \ + if (UCOP_REG_N != 0) { \ + ILLEGAL; \ + } \ + switch (UCOP_UCF64_FMT) { \ + case 0 /* s */: \ + tcg_gen_ld_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \ + tcg_gen_st_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 1 /* d */: \ + tcg_gen_ld_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \ + tcg_gen_st_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 2 /* w */: \ + ILLEGAL; \ + break; \ + } \ + } while (0) + +#define UCF64_OP2(name) do { \ + switch (UCOP_UCF64_FMT) { \ + case 0 /* s */: \ + tcg_gen_ld_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_N)); \ + tcg_gen_ld_i32(cpu_F1s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##s(cpu_F0s, \ + cpu_F0s, cpu_F1s, cpu_env); \ + tcg_gen_st_i32(cpu_F0s, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 1 /* d */: \ + tcg_gen_ld_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_N)); \ + tcg_gen_ld_i64(cpu_F1d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_M)); \ + gen_helper_ucf64_##name##d(cpu_F0d, \ + cpu_F0d, cpu_F1d, cpu_env); \ + tcg_gen_st_i64(cpu_F0d, cpu_env, \ + ucf64_reg_offset(UCOP_REG_D)); \ + break; \ + case 2 /* w */: \ + ILLEGAL; \ + break; \ + } \ + } while (0) + +/* UniCore-F64 data processing */ +static void do_ucf64_datap(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (UCOP_UCF64_FMT == 3) { + ILLEGAL; + } + switch (UCOP_UCF64_FUNC) { + case 0: /* add */ + UCF64_OP2(add); + break; + case 1: /* sub */ + UCF64_OP2(sub); + break; + case 2: /* mul */ + UCF64_OP2(mul); + break; + case 4: /* div */ + UCF64_OP2(div); + break; + case 5: /* abs */ + UCF64_OP1(abs); + break; + case 6: /* mov */ + UCF64_OP1(mov); + break; + case 7: /* neg */ + UCF64_OP1(neg); + break; + default: + ILLEGAL; + } +} + +/* Disassemble an F64 instruction */ +static void disas_ucf64_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + if (!UCOP_SET(29)) { + if (UCOP_SET(26)) { + do_ucf64_ldst_m(env, s, insn); + } else { + do_ucf64_ldst_i(env, s, insn); + } + } else { + if (UCOP_SET(5)) { + switch ((insn >> 26) & 0x3) { + case 0: + do_ucf64_datap(env, s, insn); + break; + case 1: + ILLEGAL; + break; + case 2: + do_ucf64_fcvt(env, s, insn); + break; + case 3: + do_ucf64_fcmp(env, s, insn); + break; + } + } else { + do_ucf64_trans(env, s, insn); + } + } +} + +static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + gen_set_pc_im(dest); + tcg_gen_exit_tb((long)tb + n); + } else { + gen_set_pc_im(dest); + tcg_gen_exit_tb(0); + } +} + +static inline void gen_jmp(DisasContext *s, uint32_t dest) +{ + if (unlikely(s->singlestep_enabled)) { + /* An indirect jump so that we still trigger the debug exception. */ + gen_bx_im(s, dest); + } else { + gen_goto_tb(s, 0, dest); + s->is_jmp = DISAS_TB_JUMP; + } +} + +static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y) +{ + if (x) { + tcg_gen_sari_i32(t0, t0, 16); + } else { + gen_sxth(t0); + } + if (y) { + tcg_gen_sari_i32(t1, t1, 16); + } else { + gen_sxth(t1); + } + tcg_gen_mul_i32(t0, t0, t1); +} + +/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ +static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0) +{ + TCGv tmp; + if (bsr) { + /* ??? This is also undefined in system mode. */ + if (IS_USER(s)) { + return 1; + } + + tmp = load_cpu_field(bsr); + tcg_gen_andi_i32(tmp, tmp, ~mask); + tcg_gen_andi_i32(t0, t0, mask); + tcg_gen_or_i32(tmp, tmp, t0); + store_cpu_field(tmp, bsr); + } else { + gen_set_asr(t0, mask); + } + dead_tmp(t0); + gen_lookup_tb(s); + return 0; +} + +/* Generate an old-style exception return. Marks pc as dead. */ +static void gen_exception_return(DisasContext *s, TCGv pc) +{ + TCGv tmp; + store_reg(s, 31, pc); + tmp = load_cpu_field(bsr); + gen_set_asr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; +} + +static void disas_coproc_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + switch (UCOP_CPNUM) { + case 2: + disas_ucf64_insn(env, s, insn); + break; + default: + /* Unknown coprocessor. */ + cpu_abort(env, "Unknown coprocessor!"); + } +} + + +/* Store a 64-bit value to a register pair. Clobbers val. */ +static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) +{ + TCGv tmp; + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rlow, tmp); + tmp = new_tmp(); + tcg_gen_shri_i64(val, val, 32); + tcg_gen_trunc_i64_i32(tmp, val); + store_reg(s, rhigh, tmp); +} + +/* load and add a 64-bit value from a register pair. */ +static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) +{ + TCGv_i64 tmp; + TCGv tmpl; + TCGv tmph; + + /* Load 64-bit value rd:rn. */ + tmpl = load_reg(s, rlow); + tmph = load_reg(s, rhigh); + tmp = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(tmp, tmpl, tmph); + dead_tmp(tmpl); + dead_tmp(tmph); + tcg_gen_add_i64(val, val, tmp); + tcg_temp_free_i64(tmp); +} + +/* data processing instructions */ +static void do_datap(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + TCGv tmp2; + int logic_cc; + + if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) { + if (UCOP_SET(23)) { /* CMOV instructions */ + if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) { + ILLEGAL; + } + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel); + s->condjmp = 1; + } + } + + logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24); + + if (UCOP_SET(29)) { + unsigned int val; + /* immediate operand */ + val = UCOP_IMM_9; + if (UCOP_SH_IM) { + val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); + } + tmp2 = new_tmp(); + tcg_gen_movi_i32(tmp2, val); + if (logic_cc && UCOP_SH_IM) { + gen_set_CF_bit31(tmp2); + } + } else { + /* register */ + tmp2 = load_reg(s, UCOP_REG_M); + if (UCOP_SET(5)) { + tmp = load_reg(s, UCOP_REG_S); + gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc); + } else { + gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc); + } + } + + if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { + tmp = load_reg(s, UCOP_REG_N); + } else { + TCGV_UNUSED(tmp); + } + + switch (UCOP_OPCODES) { + case 0x00: + tcg_gen_and_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x01: + tcg_gen_xor_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x02: + if (UCOP_SET_S && UCOP_REG_D == 31) { + /* SUBS r31, ... is used for exception return. */ + if (IS_USER(s)) { + ILLEGAL; + } + gen_helper_sub_cc(tmp, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + } + break; + case 0x03: + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x04: + if (UCOP_SET_S) { + gen_helper_add_cc(tmp, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x05: + if (UCOP_SET_S) { + gen_helper_adc_cc(tmp, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x06: + if (UCOP_SET_S) { + gen_helper_sbc_cc(tmp, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x07: + if (UCOP_SET_S) { + gen_helper_sbc_cc(tmp, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x08: + if (UCOP_SET_S) { + tcg_gen_and_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x09: + if (UCOP_SET_S) { + tcg_gen_xor_i32(tmp, tmp, tmp2); + gen_logic_CC(tmp); + } + dead_tmp(tmp); + break; + case 0x0a: + if (UCOP_SET_S) { + gen_helper_sub_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0b: + if (UCOP_SET_S) { + gen_helper_add_cc(tmp, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0c: + tcg_gen_or_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + case 0x0d: + if (logic_cc && UCOP_REG_D == 31) { + /* MOVS r31, ... is used for exception return. */ + if (IS_USER(s)) { + ILLEGAL; + } + gen_exception_return(s, tmp2); + } else { + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp2); + } + break; + case 0x0e: + tcg_gen_andc_i32(tmp, tmp, tmp2); + if (logic_cc) { + gen_logic_CC(tmp); + } + store_reg_bx(s, UCOP_REG_D, tmp); + break; + default: + case 0x0f: + tcg_gen_not_i32(tmp2, tmp2); + if (logic_cc) { + gen_logic_CC(tmp2); + } + store_reg_bx(s, UCOP_REG_D, tmp2); + break; + } + if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { + dead_tmp(tmp2); + } +} + +/* multiply */ +static void do_mult(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv tmp; + TCGv tmp2; + TCGv_i64 tmp64; + + if (UCOP_SET(27)) { + /* 64 bit mul */ + tmp = load_reg(s, UCOP_REG_M); + tmp2 = load_reg(s, UCOP_REG_N); + if (UCOP_SET(26)) { + tmp64 = gen_muls_i64_i32(tmp, tmp2); + } else { + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + } + if (UCOP_SET(25)) { /* mult accumulate */ + gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI); + } + gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64); + tcg_temp_free_i64(tmp64); + } else { + /* 32 bit mul */ + tmp = load_reg(s, UCOP_REG_M); + tmp2 = load_reg(s, UCOP_REG_N); + tcg_gen_mul_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + if (UCOP_SET(25)) { + /* Add */ + tmp2 = load_reg(s, UCOP_REG_S); + tcg_gen_add_i32(tmp, tmp, tmp2); + dead_tmp(tmp2); + } + if (UCOP_SET_S) { + gen_logic_CC(tmp); + } + store_reg(s, UCOP_REG_D, tmp); + } +} + +/* miscellaneous instructions */ +static void do_misc(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val; + TCGv tmp; + + if ((insn & 0xffffffe0) == 0x10ffc120) { + /* Trivial implementation equivalent to bx. */ + tmp = load_reg(s, UCOP_REG_M); + gen_bx(s, tmp); + return; + } + + if ((insn & 0xfbffc000) == 0x30ffc000) { + /* PSR = immediate */ + val = UCOP_IMM_9; + if (UCOP_SH_IM) { + val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); + } + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbffffe0) == 0x12ffc020) { + /* PSR.flag = reg */ + tmp = load_reg(s, UCOP_REG_M); + if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbffffe0) == 0x10ffc020) { + /* PSR = reg */ + tmp = load_reg(s, UCOP_REG_M); + if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { + ILLEGAL; + } + return; + } + + if ((insn & 0xfbf83fff) == 0x10f80000) { + /* reg = PSR */ + if (UCOP_SET_B) { + if (IS_USER(s)) { + ILLEGAL; + } + tmp = load_cpu_field(bsr); + } else { + tmp = new_tmp(); + gen_helper_asr_read(tmp); + } + store_reg(s, UCOP_REG_D, tmp); + return; + } + + if ((insn & 0xfbf83fe0) == 0x12f80120) { + /* clz */ + tmp = load_reg(s, UCOP_REG_M); + if (UCOP_SET(26)) { + gen_helper_clo(tmp, tmp); + } else { + gen_helper_clz(tmp, tmp); + } + store_reg(s, UCOP_REG_D, tmp); + return; + } + + /* otherwise */ + ILLEGAL; +} + +/* load/store I_offset and R_offset */ +static void do_ldst_ir(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int i; + TCGv tmp; + TCGv tmp2; + + tmp2 = load_reg(s, UCOP_REG_N); + i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); + + /* immediate */ + if (UCOP_SET_P) { + gen_add_data_offset(s, insn, tmp2); + } + + if (UCOP_SET_L) { + /* load */ + if (UCOP_SET_B) { + tmp = gen_ld8u(tmp2, i); + } else { + tmp = gen_ld32(tmp2, i); + } + } else { + /* store */ + tmp = load_reg(s, UCOP_REG_D); + if (UCOP_SET_B) { + gen_st8(tmp, tmp2, i); + } else { + gen_st32(tmp, tmp2, i); + } + } + if (!UCOP_SET_P) { + gen_add_data_offset(s, insn, tmp2); + store_reg(s, UCOP_REG_N, tmp2); + } else if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, tmp2); + } else { + dead_tmp(tmp2); + } + if (UCOP_SET_L) { + /* Complete the load. */ + if (UCOP_REG_D == 31) { + gen_bx(s, tmp); + } else { + store_reg(s, UCOP_REG_D, tmp); + } + } +} + +/* SWP instruction */ +static void do_swap(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv addr; + TCGv tmp; + TCGv tmp2; + + if ((insn & 0xff003fe0) != 0x40000120) { + ILLEGAL; + } + + /* ??? This is not really atomic. However we know + we never have multiple CPUs running in parallel, + so it is good enough. */ + addr = load_reg(s, UCOP_REG_N); + tmp = load_reg(s, UCOP_REG_M); + if (UCOP_SET_B) { + tmp2 = gen_ld8u(addr, IS_USER(s)); + gen_st8(tmp, addr, IS_USER(s)); + } else { + tmp2 = gen_ld32(addr, IS_USER(s)); + gen_st32(tmp, addr, IS_USER(s)); + } + dead_tmp(addr); + store_reg(s, UCOP_REG_D, tmp2); +} + +/* load/store hw/sb */ +static void do_ldst_hwsb(CPUState *env, DisasContext *s, uint32_t insn) +{ + TCGv addr; + TCGv tmp; + + if (UCOP_SH_OP == 0) { + do_swap(env, s, insn); + return; + } + + addr = load_reg(s, UCOP_REG_N); + if (UCOP_SET_P) { + gen_add_datah_offset(s, insn, addr); + } + + if (UCOP_SET_L) { /* load */ + switch (UCOP_SH_OP) { + case 1: + tmp = gen_ld16u(addr, IS_USER(s)); + break; + case 2: + tmp = gen_ld8s(addr, IS_USER(s)); + break; + default: /* see do_swap */ + case 3: + tmp = gen_ld16s(addr, IS_USER(s)); + break; + } + } else { /* store */ + if (UCOP_SH_OP != 1) { + ILLEGAL; + } + tmp = load_reg(s, UCOP_REG_D); + gen_st16(tmp, addr, IS_USER(s)); + } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. */ + if (!UCOP_SET_P) { + gen_add_datah_offset(s, insn, addr); + store_reg(s, UCOP_REG_N, addr); + } else if (UCOP_SET_W) { + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } + if (UCOP_SET_L) { + /* Complete the load. */ + store_reg(s, UCOP_REG_D, tmp); + } +} + +/* load/store multiple words */ +static void do_ldst_m(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val, i; + int j, n, reg, user, loaded_base; + TCGv tmp; + TCGv tmp2; + TCGv addr; + TCGv loaded_var; + + if (UCOP_SET(7)) { + ILLEGAL; + } + /* XXX: store correct base if write back */ + user = 0; + if (UCOP_SET_B) { /* S bit in instruction table */ + if (IS_USER(s)) { + ILLEGAL; /* only usable in supervisor mode */ + } + if (UCOP_SET(18) == 0) { /* pc reg */ + user = 1; + } + } + + addr = load_reg(s, UCOP_REG_N); + + /* compute total size */ + loaded_base = 0; + TCGV_UNUSED(loaded_var); + n = 0; + for (i = 0; i < 6; i++) { + if (UCOP_SET(i)) { + n++; + } + } + for (i = 9; i < 19; i++) { + if (UCOP_SET(i)) { + n++; + } + } + /* XXX: test invalid n == 0 case ? */ + if (UCOP_SET_U) { + if (UCOP_SET_P) { + /* pre increment */ + tcg_gen_addi_i32(addr, addr, 4); + } else { + /* post increment */ + } + } else { + if (UCOP_SET_P) { + /* pre decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } else { + /* post decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } + } + + j = 0; + reg = UCOP_SET(6) ? 16 : 0; + for (i = 0; i < 19; i++, reg++) { + if (i == 6) { + i = i + 3; + } + if (UCOP_SET(i)) { + if (UCOP_SET_L) { /* load */ + tmp = gen_ld32(addr, IS_USER(s)); + if (reg == 31) { + gen_bx(s, tmp); + } else if (user) { + tmp2 = tcg_const_i32(reg); + gen_helper_set_user_reg(tmp2, tmp); + tcg_temp_free_i32(tmp2); + dead_tmp(tmp); + } else if (reg == UCOP_REG_N) { + loaded_var = tmp; + loaded_base = 1; + } else { + store_reg(s, reg, tmp); + } + } else { /* store */ + if (reg == 31) { + /* special case: r31 = PC + 4 */ + val = (long)s->pc; + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + } else if (user) { + tmp = new_tmp(); + tmp2 = tcg_const_i32(reg); + gen_helper_get_user_reg(tmp, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, reg); + } + gen_st32(tmp, addr, IS_USER(s)); + } + j++; + /* no need to add after the last transfer */ + if (j != n) { + tcg_gen_addi_i32(addr, addr, 4); + } + } + } + if (UCOP_SET_W) { /* write back */ + if (UCOP_SET_U) { + if (UCOP_SET_P) { + /* pre increment */ + } else { + /* post increment */ + tcg_gen_addi_i32(addr, addr, 4); + } + } else { + if (UCOP_SET_P) { + /* pre decrement */ + if (n != 1) { + tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); + } + } else { + /* post decrement */ + tcg_gen_addi_i32(addr, addr, -(n * 4)); + } + } + store_reg(s, UCOP_REG_N, addr); + } else { + dead_tmp(addr); + } + if (loaded_base) { + store_reg(s, UCOP_REG_N, loaded_var); + } + if (UCOP_SET_B && !user) { + /* Restore ASR from BSR. */ + tmp = load_cpu_field(bsr); + gen_set_asr(tmp, 0xffffffff); + dead_tmp(tmp); + s->is_jmp = DISAS_UPDATE; + } +} + +/* branch (and link) */ +static void do_branch(CPUState *env, DisasContext *s, uint32_t insn) +{ + unsigned int val; + int32_t offset; + TCGv tmp; + + if (UCOP_COND == 0xf) { + ILLEGAL; + } + + if (UCOP_COND != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc(UCOP_COND ^ 1, s->condlabel); + s->condjmp = 1; + } + + val = (int32_t)s->pc; + if (UCOP_SET_L) { + tmp = new_tmp(); + tcg_gen_movi_i32(tmp, val); + store_reg(s, 30, tmp); + } + offset = (((int32_t)insn << 8) >> 8); + val += (offset << 2); /* unicore is pc+4 */ + gen_jmp(s, val); +} + +static void disas_uc32_insn(CPUState *env, DisasContext *s) +{ + unsigned int insn; + + insn = ldl_code(s->pc); + s->pc += 4; + + /* UniCore instructions class: + * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx + * AAA : see switch case + * BBBB : opcodes or cond or PUBW + * C : S OR L + * D : 8 + * E : 5 + */ + switch (insn >> 29) { + case 0b000: + if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) { + do_mult(env, s, insn); + break; + } + + if (UCOP_SET(8)) { + do_misc(env, s, insn); + break; + } + case 0b001: + if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) { + do_misc(env, s, insn); + break; + } + do_datap(env, s, insn); + break; + + case 0b010: + if (UCOP_SET(8) && UCOP_SET(5)) { + do_ldst_hwsb(env, s, insn); + break; + } + if (UCOP_SET(8) || UCOP_SET(5)) { + ILLEGAL; + } + case 0b011: + do_ldst_ir(env, s, insn); + break; + + case 0b100: + if (UCOP_SET(8)) { + ILLEGAL; /* extended instructions */ + } + do_ldst_m(env, s, insn); + break; + case 0b101: + do_branch(env, s, insn); + break; + case 0b110: + /* Coprocessor. */ + disas_coproc_insn(env, s, insn); + break; + case 0b111: + if (!UCOP_SET(28)) { + disas_coproc_insn(env, s, insn); + break; + } + if ((insn & 0xff000000) == 0xff000000) { /* syscall */ + gen_set_pc_im(s->pc); + s->is_jmp = DISAS_SYSCALL; + break; + } + ILLEGAL; + } + + return; +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline void gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, int search_pc) +{ + DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; + uint16_t *gen_opc_end; + int j, lj; + target_ulong pc_start; + uint32_t next_page_start; + int num_insns; + int max_insns; + + /* generate intermediate code */ + num_temps = 0; + + pc_start = tb->pc; + + dc->tb = tb; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->condjmp = 0; + cpu_F0s = tcg_temp_new_i32(); + cpu_F1s = tcg_temp_new_i32(); + cpu_F0d = tcg_temp_new_i64(); + cpu_F1d = tcg_temp_new_i64(); + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + + gen_icount_start(); + do { + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + gen_set_pc_im(dc->pc); + gen_exception(EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; /* FIXME */ + goto done_generating; + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) { + gen_opc_instr_start[lj++] = 0; + } + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + + disas_uc32_insn(env, dc); + + if (num_temps) { + fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); + num_temps = 0; + } + + if (dc->condjmp && !dc->is_jmp) { + gen_set_label(dc->condlabel); + dc->condjmp = 0; + } + /* Translation stops when a conditional branch is encountered. + * Otherwise the subsequent code could get translated several times. + * Also stop translation when a page boundary is reached. This + * ensures prefetch aborts occur at the right place. */ + num_insns++; + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && + !singlestep && + dc->pc < next_page_start && + num_insns < max_insns); + + if (tb->cflags & CF_LAST_IO) { + if (dc->condjmp) { + /* FIXME: This can theoretically happen with self-modifying + code. */ + cpu_abort(env, "IO on conditional branch instruction"); + } + gen_io_end(); + } + + /* At this stage dc->condjmp will only be set when the skipped + instruction was a conditional branch or trap, and the PC has + already been written. */ + if (unlikely(env->singlestep_enabled)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (dc->condjmp) { + if (dc->is_jmp == DISAS_SYSCALL) { + gen_exception(UC32_EXCP_PRIV); + } else { + gen_exception(EXCP_DEBUG); + } + gen_set_label(dc->condlabel); + } + if (dc->condjmp || !dc->is_jmp) { + gen_set_pc_im(dc->pc); + dc->condjmp = 0; + } + if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) { + gen_exception(UC32_EXCP_PRIV); + } else { + gen_exception(EXCP_DEBUG); + } + } else { + /* While branches must always occur at the end of an IT block, + there are a few other things that can cause us to terminate + the TB in the middel of an IT block: + - Exception generating instructions (bkpt, swi, undefined). + - Page boundaries. + - Hardware watchpoints. + Hardware breakpoints have already been handled and skip this code. + */ + switch (dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + case DISAS_SYSCALL: + gen_exception(UC32_EXCP_PRIV); + break; + } + if (dc->condjmp) { + gen_set_label(dc->condlabel); + gen_goto_tb(dc, 1, dc->pc); + dc->condjmp = 0; + } + } + +done_generating: + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("----------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, dc->pc - pc_start, 0); + qemu_log("\n"); + } +#endif + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) { + gen_opc_instr_start[lj++] = 0; + } + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } +} + +void gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +static const char *cpu_mode_names[16] = { + "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP", + "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR" +}; + +#define UCF64_DUMP_STATE +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + int i; +#ifdef UCF64_DUMP_STATE + union { + uint32_t i; + float s; + } s0, s1; + CPU_DoubleU d; + /* ??? This assumes float64 and double have the same layout. + Oh well, it's only debug dumps. */ + union { + float64 f64; + double d; + } d0; +#endif + uint32_t psr; + + for (i = 0; i < 32; i++) { + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) { + cpu_fprintf(f, "\n"); + } else { + cpu_fprintf(f, " "); + } + } + psr = cpu_asr_read(env); + cpu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + cpu_mode_names[psr & 0xf]); + +#ifdef UCF64_DUMP_STATE + for (i = 0; i < 16; i++) { + d.d = env->ucf64.regs[i]; + s0.i = d.l.lower; + s1.i = d.l.upper; + d0.f64 = d.d; + cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s, + i, (uint64_t)d0.f64, d0.d); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); +#endif +} + +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->regs[31] = gen_opc_pc[pc_pos]; +} From 8b5d487d4d35a1a18c3ac48f3dd367fb769592b2 Mon Sep 17 00:00:00 2001 From: Guan Xuetao <gxt@mprc.pku.edu.cn> Date: Tue, 12 Apr 2011 16:26:27 +0800 Subject: [PATCH 153/386] unicore32: add necessry headers in linux-user/unicore32 for unicore32 support Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- linux-user/unicore32/syscall.h | 55 ++++ linux-user/unicore32/syscall_nr.h | 371 +++++++++++++++++++++++++++ linux-user/unicore32/target_signal.h | 26 ++ linux-user/unicore32/termbits.h | 2 + 4 files changed, 454 insertions(+) create mode 100644 linux-user/unicore32/syscall.h create mode 100644 linux-user/unicore32/syscall_nr.h create mode 100644 linux-user/unicore32/target_signal.h create mode 100644 linux-user/unicore32/termbits.h diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h new file mode 100644 index 0000000000..010cdd896e --- /dev/null +++ b/linux-user/unicore32/syscall.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __UC32_SYSCALL_H__ +#define __UC32_SYSCALL_H__ +struct target_pt_regs { + abi_ulong uregs[34]; +}; + +#define UC32_REG_pc uregs[31] +#define UC32_REG_lr uregs[30] +#define UC32_REG_sp uregs[29] +#define UC32_REG_ip uregs[28] +#define UC32_REG_fp uregs[27] +#define UC32_REG_26 uregs[26] +#define UC32_REG_25 uregs[25] +#define UC32_REG_24 uregs[24] +#define UC32_REG_23 uregs[23] +#define UC32_REG_22 uregs[22] +#define UC32_REG_21 uregs[21] +#define UC32_REG_20 uregs[20] +#define UC32_REG_19 uregs[19] +#define UC32_REG_18 uregs[18] +#define UC32_REG_17 uregs[17] +#define UC32_REG_16 uregs[16] +#define UC32_REG_15 uregs[15] +#define UC32_REG_14 uregs[14] +#define UC32_REG_13 uregs[13] +#define UC32_REG_12 uregs[12] +#define UC32_REG_11 uregs[11] +#define UC32_REG_10 uregs[10] +#define UC32_REG_09 uregs[9] +#define UC32_REG_08 uregs[8] +#define UC32_REG_07 uregs[7] +#define UC32_REG_06 uregs[6] +#define UC32_REG_05 uregs[5] +#define UC32_REG_04 uregs[4] +#define UC32_REG_03 uregs[3] +#define UC32_REG_02 uregs[2] +#define UC32_REG_01 uregs[1] +#define UC32_REG_00 uregs[0] +#define UC32_REG_asr uregs[32] +#define UC32_REG_ORIG_00 uregs[33] + +#define UC32_SYSCALL_BASE 0x900000 +#define UC32_SYSCALL_ARCH_BASE 0xf0000 +#define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5) + +#define UNAME_MACHINE "UniCore-II" + +#endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/unicore32/syscall_nr.h b/linux-user/unicore32/syscall_nr.h new file mode 100644 index 0000000000..9c72d84d80 --- /dev/null +++ b/linux-user/unicore32/syscall_nr.h @@ -0,0 +1,371 @@ +/* + * This file contains the system call numbers for UniCore32 oldabi. + * + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 + /* 18 */ +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 + /* 28 */ +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 + /* 59 */ +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 + /* 84 */ +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 + /* 109 */ + /* 110 */ +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_syscall 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 + /* 188 */ + /* 189 */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_getdents64 217 +#define TARGET_NR_pivot_root 218 +#define TARGET_NR_mincore 219 +#define TARGET_NR_madvise 220 +#define TARGET_NR_fcntl64 221 + /* 222 */ + /* 223 */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_io_setup 243 +#define TARGET_NR_io_destroy 244 +#define TARGET_NR_io_getevents 245 +#define TARGET_NR_io_submit 246 +#define TARGET_NR_io_cancel 247 +#define TARGET_NR_exit_group 248 +#define TARGET_NR_lookup_dcookie 249 +#define TARGET_NR_epoll_create 250 +#define TARGET_NR_epoll_ctl 251 +#define TARGET_NR_epoll_wait 252 +#define TARGET_NR_remap_file_pages 253 + /* 254 */ + /* 255 */ + /* 256 */ +#define TARGET_NR_set_tid_address 256 +#define TARGET_NR_timer_create 257 +#define TARGET_NR_timer_settime 258 +#define TARGET_NR_timer_gettime 259 +#define TARGET_NR_timer_getoverrun 260 +#define TARGET_NR_timer_delete 261 +#define TARGET_NR_clock_settime 262 +#define TARGET_NR_clock_gettime 263 +#define TARGET_NR_clock_getres 264 +#define TARGET_NR_clock_nanosleep 265 +#define TARGET_NR_statfs64 266 +#define TARGET_NR_fstatfs64 267 +#define TARGET_NR_tgkill 268 +#define TARGET_NR_utimes 269 +#define TARGET_NR_fadvise64_64 270 +#define TARGET_NR_pciconfig_iobase 271 +#define TARGET_NR_pciconfig_read 272 +#define TARGET_NR_pciconfig_write 273 +#define TARGET_NR_mq_open 274 +#define TARGET_NR_mq_unlink 275 +#define TARGET_NR_mq_timedsend 276 +#define TARGET_NR_mq_timedreceive 277 +#define TARGET_NR_mq_notify 278 +#define TARGET_NR_mq_getsetattr 279 +#define TARGET_NR_waitid 280 +#define TARGET_NR_socket 281 +#define TARGET_NR_bind 282 +#define TARGET_NR_connect 283 +#define TARGET_NR_listen 284 +#define TARGET_NR_accept 285 +#define TARGET_NR_getsockname 286 +#define TARGET_NR_getpeername 287 +#define TARGET_NR_socketpair 288 +#define TARGET_NR_send 289 +#define TARGET_NR_sendto 290 +#define TARGET_NR_recv 291 +#define TARGET_NR_recvfrom 292 +#define TARGET_NR_shutdown 293 +#define TARGET_NR_setsockopt 294 +#define TARGET_NR_getsockopt 295 +#define TARGET_NR_sendmsg 296 +#define TARGET_NR_recvmsg 297 +#define TARGET_NR_semop 298 +#define TARGET_NR_semget 299 +#define TARGET_NR_semctl 300 +#define TARGET_NR_msgsnd 301 +#define TARGET_NR_msgrcv 302 +#define TARGET_NR_msgget 303 +#define TARGET_NR_msgctl 304 +#define TARGET_NR_shmat 305 +#define TARGET_NR_shmdt 306 +#define TARGET_NR_shmget 307 +#define TARGET_NR_shmctl 308 +#define TARGET_NR_add_key 309 +#define TARGET_NR_request_key 310 +#define TARGET_NR_keyctl 311 +#define TARGET_NR_semtimedop 312 +#define TARGET_NR_vserver 313 +#define TARGET_NR_ioprio_set 314 +#define TARGET_NR_ioprio_get 315 +#define TARGET_NR_inotify_init 316 +#define TARGET_NR_inotify_add_watch 317 +#define TARGET_NR_inotify_rm_watch 318 +#define TARGET_NR_mbind 319 +#define TARGET_NR_get_mempolicy 320 +#define TARGET_NR_set_mempolicy 321 +#define TARGET_NR_openat 322 +#define TARGET_NR_mkdirat 323 +#define TARGET_NR_mknodat 324 +#define TARGET_NR_fchownat 325 +#define TARGET_NR_futimesat 326 +#define TARGET_NR_fstatat64 327 +#define TARGET_NR_unlinkat 328 +#define TARGET_NR_renameat 329 +#define TARGET_NR_linkat 330 +#define TARGET_NR_symlinkat 331 +#define TARGET_NR_readlinkat 332 +#define TARGET_NR_fchmodat 333 +#define TARGET_NR_faccessat 334 + /* 335 */ + /* 336 */ +#define TARGET_NR_unshare 337 +#define TARGET_NR_set_robust_list 338 +#define TARGET_NR_get_robust_list 339 +#define TARGET_NR_splice 340 +#define TARGET_NR_sync_file_range2 341 +#define TARGET_NR_tee 342 +#define TARGET_NR_vmsplice 343 +#define TARGET_NR_move_pages 344 +#define TARGET_NR_getcpu 345 + /* 346 */ +#define TARGET_NR_kexec_load 347 +#define TARGET_NR_utimensat 348 +#define TARGET_NR_signalfd 349 +#define TARGET_NR_timerfd 350 +#define TARGET_NR_eventfd 351 +#define TARGET_NR_fallocate 352 +#define TARGET_NR_timerfd_settime 353 +#define TARGET_NR_timerfd_gettime 354 +#define TARGET_NR_signalfd4 355 +#define TARGET_NR_eventfd2 356 +#define TARGET_NR_epoll_create1 357 +#define TARGET_NR_dup3 358 +#define TARGET_NR_pipe2 359 +#define TARGET_NR_inotify_init1 360 diff --git a/linux-user/unicore32/target_signal.h b/linux-user/unicore32/target_signal.h new file mode 100644 index 0000000000..8b255c4550 --- /dev/null +++ b/linux-user/unicore32/target_signal.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010-2011 GUAN Xue-tao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_ulong ss_flags; + abi_ulong ss_size; +} target_stack_t; + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define get_sp_from_cpustate(cpustate) (cpustate->regs[29]) + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/unicore32/termbits.h b/linux-user/unicore32/termbits.h new file mode 100644 index 0000000000..a5fcd64abf --- /dev/null +++ b/linux-user/unicore32/termbits.h @@ -0,0 +1,2 @@ +/* NOTE: exactly the same as i386 */ +#include "../i386/termbits.h" From d2fbca94223ef573a67d4eb2f27509a9bbb85ca1 Mon Sep 17 00:00:00 2001 From: Guan Xuetao <gxt@mprc.pku.edu.cn> Date: Tue, 12 Apr 2011 16:27:03 +0800 Subject: [PATCH 154/386] unicore32: necessary modifications for other files to support unicore32 Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- configure | 11 ++- cpu-exec.c | 12 +++- default-configs/unicore32-linux-user.mak | 1 + elf.h | 2 + fpu/softfloat-specialize.h | 10 +-- fpu/softfloat.h | 2 +- linux-user/elfload.c | 74 ++++++++++++++++++++ linux-user/main.c | 89 +++++++++++++++++++++++- linux-user/qemu.h | 5 +- linux-user/syscall_defs.h | 10 ++- 10 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 default-configs/unicore32-linux-user.mak diff --git a/configure b/configure index a4759ae817..ed4d951ce9 100755 --- a/configure +++ b/configure @@ -283,7 +283,7 @@ else fi case "$cpu" in - alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64) + alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64|unicore32) cpu="$cpu" ;; i386|i486|i586|i686|i86pc|BePC) @@ -814,6 +814,9 @@ case "$cpu" in hppa*) host_guest_base="yes" ;; + unicore32*) + host_guest_base="yes" + ;; esac [ -z "$guest_base" ] && guest_base="$host_guest_base" @@ -1048,6 +1051,7 @@ sh4eb-linux-user \ sparc-linux-user \ sparc64-linux-user \ sparc32plus-linux-user \ +unicore32-linux-user \ " fi # the following are Darwin specific @@ -2633,7 +2637,7 @@ echo "docdir=$docdir" >> $config_host_mak echo "confdir=$confdir" >> $config_host_mak case "$cpu" in - i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64) + i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64|unicore32) ARCH=$cpu ;; armv4b|armv4l) @@ -3186,6 +3190,9 @@ case "$target_arch2" in target_phys_bits=64 target_long_alignment=8 ;; + unicore32) + target_phys_bits=32 + ;; *) echo "Unsupported target CPU" exit 1 diff --git a/cpu-exec.c b/cpu-exec.c index 5cc937904a..5d6c9a8a1c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -267,6 +267,7 @@ int cpu_exec(CPUState *env1) env->cc_x = (env->sr >> 4) & 1; #elif defined(TARGET_ALPHA) #elif defined(TARGET_ARM) +#elif defined(TARGET_UNICORE32) #elif defined(TARGET_PPC) #elif defined(TARGET_LM32) #elif defined(TARGET_MICROBLAZE) @@ -335,6 +336,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_ARM) do_interrupt(env); +#elif defined(TARGET_UNICORE32) + do_interrupt(env); #elif defined(TARGET_SH4) do_interrupt(env); #elif defined(TARGET_ALPHA) @@ -367,7 +370,7 @@ int cpu_exec(CPUState *env1) } #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ - defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) + defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32) if (interrupt_request & CPU_INTERRUPT_HALT) { env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; @@ -514,6 +517,12 @@ int cpu_exec(CPUState *env1) do_interrupt(env); next_tb = 0; } +#elif defined(TARGET_UNICORE32) + if (interrupt_request & CPU_INTERRUPT_HARD + && !(env->uncached_asr & ASR_I)) { + do_interrupt(env); + next_tb = 0; + } #elif defined(TARGET_SH4) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); @@ -664,6 +673,7 @@ int cpu_exec(CPUState *env1) env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK); #elif defined(TARGET_ARM) /* XXX: Save/restore host fpu exception state?. */ +#elif defined(TARGET_UNICORE32) #elif defined(TARGET_SPARC) #elif defined(TARGET_PPC) #elif defined(TARGET_LM32) diff --git a/default-configs/unicore32-linux-user.mak b/default-configs/unicore32-linux-user.mak new file mode 100644 index 0000000000..6aafd21494 --- /dev/null +++ b/default-configs/unicore32-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for unicore32-linux-user diff --git a/elf.h b/elf.h index 523c972a6b..ffcac7e0b0 100644 --- a/elf.h +++ b/elf.h @@ -106,6 +106,8 @@ typedef int64_t Elf64_Sxword; #define EM_H8S 48 /* Hitachi H8S */ #define EM_LATTICEMICO32 138 /* LatticeMico32 */ +#define EM_UNICORE32 110 /* UniCore32 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 4b65de64a8..b1101872af 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -93,7 +93,7 @@ float16 float16_maybe_silence_nan(float16 a_) { if (float16_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float16_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -184,7 +184,7 @@ float32 float32_maybe_silence_nan( float32 a_ ) { if (float32_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float32_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -430,7 +430,7 @@ float64 float64_maybe_silence_nan( float64 a_ ) { if (float64_is_signaling_nan(a_)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) return float64_default_nan; # else # error Rules for silencing a signaling NaN are target-specific @@ -578,7 +578,7 @@ floatx80 floatx80_maybe_silence_nan( floatx80 a ) { if (floatx80_is_signaling_nan(a)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) a.low = floatx80_default_nan_low; a.high = floatx80_default_nan_high; # else @@ -721,7 +721,7 @@ float128 float128_maybe_silence_nan( float128 a ) { if (float128_is_signaling_nan(a)) { #if SNAN_BIT_IS_ONE -# if defined(TARGET_MIPS) || defined(TARGET_SH4) +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) a.low = float128_default_nan_low; a.high = float128_default_nan_high; # else diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 90f4250173..7abcbe899e 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -68,7 +68,7 @@ typedef int64_t int64; #define LIT64( a ) a##LL #define INLINE static inline -#if defined(TARGET_MIPS) || defined(TARGET_SH4) +#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) #define SNAN_BIT_IS_ONE 1 #else #define SNAN_BIT_IS_ONE 0 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fe5410e6f9..4c399f8e33 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -339,6 +339,80 @@ enum #endif +#ifdef TARGET_UNICORE32 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == EM_UNICORE32) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_UNICORE32 + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->UC32_REG_asr = 0x10; + regs->UC32_REG_pc = infop->entry & 0xfffffffe; + regs->UC32_REG_sp = infop->start_stack; + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->UC32_REG_02, stack + 8); /* envp */ + get_user_ual(regs->UC32_REG_01, stack + 4); /* envp */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->UC32_REG_00 = 0; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUState *env) +{ + (*regs)[0] = env->regs[0]; + (*regs)[1] = env->regs[1]; + (*regs)[2] = env->regs[2]; + (*regs)[3] = env->regs[3]; + (*regs)[4] = env->regs[4]; + (*regs)[5] = env->regs[5]; + (*regs)[6] = env->regs[6]; + (*regs)[7] = env->regs[7]; + (*regs)[8] = env->regs[8]; + (*regs)[9] = env->regs[9]; + (*regs)[10] = env->regs[10]; + (*regs)[11] = env->regs[11]; + (*regs)[12] = env->regs[12]; + (*regs)[13] = env->regs[13]; + (*regs)[14] = env->regs[14]; + (*regs)[15] = env->regs[15]; + (*regs)[16] = env->regs[16]; + (*regs)[17] = env->regs[17]; + (*regs)[18] = env->regs[18]; + (*regs)[19] = env->regs[19]; + (*regs)[20] = env->regs[20]; + (*regs)[21] = env->regs[21]; + (*regs)[22] = env->regs[22]; + (*regs)[23] = env->regs[23]; + (*regs)[24] = env->regs[24]; + (*regs)[25] = env->regs[25]; + (*regs)[26] = env->regs[26]; + (*regs)[27] = env->regs[27]; + (*regs)[28] = env->regs[28]; + (*regs)[29] = env->regs[29]; + (*regs)[30] = env->regs[30]; + (*regs)[31] = env->regs[31]; + + (*regs)[32] = cpu_asr_read((CPUState *)env); + (*regs)[33] = env->regs[0]; /* XXX */ +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_HWCAP (UC32_HWCAP_CMOV | UC32_HWCAP_UCF64) + +#endif + #ifdef TARGET_SPARC #ifdef TARGET_SPARC64 diff --git a/linux-user/main.c b/linux-user/main.c index 91600877d2..a1e37e4948 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -816,6 +816,83 @@ void cpu_loop(CPUARMState *env) #endif +#ifdef TARGET_UNICORE32 + +void cpu_loop(CPUState *env) +{ + int trapnr; + unsigned int n, insn; + target_siginfo_t info; + + for (;;) { + cpu_exec_start(env); + trapnr = uc32_cpu_exec(env); + cpu_exec_end(env); + switch (trapnr) { + case UC32_EXCP_PRIV: + { + /* system call */ + get_user_u32(insn, env->regs[31] - 4); + n = insn & 0xffffff; + + if (n >= UC32_SYSCALL_BASE) { + /* linux syscall */ + n -= UC32_SYSCALL_BASE; + if (n == UC32_SYSCALL_NR_set_tls) { + cpu_set_tls(env, env->regs[0]); + env->regs[0] = 0; + } else { + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5]); + } + } else { + goto error; + } + } + break; + case UC32_EXCP_TRAP: + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->cp0.c4_faultaddr; + queue_signal(env, 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, TARGET_SIGTRAP); + if (sig) { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); + } + } + break; + default: + goto error; + } + process_pending_signals(env); + } + +error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); +} +#endif + #ifdef TARGET_SPARC #define SPARC64_STACK_BIAS 2047 @@ -2925,6 +3002,8 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_ARM) cpu_model = "any"; +#elif defined(TARGET_UNICORE32) + cpu_model = "any"; #elif defined(TARGET_M68K) cpu_model = "any"; #elif defined(TARGET_SPARC) @@ -3227,6 +3306,14 @@ int main(int argc, char **argv, char **envp) env->regs[i] = regs->uregs[i]; } } +#elif defined(TARGET_UNICORE32) + { + int i; + cpu_asr_write(env, regs->uregs[32], 0xffffffff); + for (i = 0; i < 32; i++) { + env->regs[i] = regs->uregs[i]; + } + } #elif defined(TARGET_SPARC) { int i; @@ -3367,7 +3454,7 @@ int main(int argc, char **argv, char **envp) #error unsupported target CPU #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) ts->stack_base = info->start_stack; ts->heap_base = info->brk; /* This will be filled in on the first SYS_HEAPINFO call. */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 250814d9f7..f522f5e64a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -105,6 +105,9 @@ typedef struct TaskState { FPA11 fpa; int swi_errno; #endif +#ifdef TARGET_UNICORE32 + int swi_errno; +#endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) abi_ulong target_v86; struct vm86_saved_state vm86_saved_regs; @@ -118,7 +121,7 @@ typedef struct TaskState { #ifdef TARGET_M68K int sim_syscalls; #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) /* Extra fields for semihosted binaries. */ uint32_t stack_base; uint32_t heap_base; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 702652cb9e..bde89213de 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -55,7 +55,7 @@ #endif #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ - || defined(TARGET_M68K) || defined(TARGET_CRIS) + || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -315,7 +315,10 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ + || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined(TARGET_SH4) \ + || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \ + || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -1002,7 +1005,8 @@ struct target_winsize { #define TARGET_MAP_UNINITIALIZED 0x4000000 /* for anonymous mmap, memory could be uninitialized */ #endif -#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS) +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) \ + || defined(TARGET_CRIS) || defined(TARGET_UNICORE32) struct target_stat { unsigned short st_dev; unsigned short __pad1; From d6c424c56e0e9064448d04c271625c8ac696ae50 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Sun, 10 Apr 2011 21:09:12 +0200 Subject: [PATCH 155/386] target-sh4: get rid of CPU_{Float,Double}U SH4 is always using softfloat, so it's possible to have helpers directly taking float32 or float64 value. This allow to get rid of conversions through CPU_{Float,Double}U. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-sh4/helper.h | 48 +++--- target-sh4/op_helper.c | 342 +++++++++++++++++------------------------ 2 files changed, 162 insertions(+), 228 deletions(-) diff --git a/target-sh4/helper.h b/target-sh4/helper.h index 2e52768414..95e3c7c8f7 100644 --- a/target-sh4/helper.h +++ b/target-sh4/helper.h @@ -23,31 +23,31 @@ DEF_HELPER_2(macw, void, i32, i32) DEF_HELPER_1(ld_fpscr, void, i32) -DEF_HELPER_1(fabs_FT, i32, i32) -DEF_HELPER_1(fabs_DT, i64, i64) -DEF_HELPER_2(fadd_FT, i32, i32, i32) -DEF_HELPER_2(fadd_DT, i64, i64, i64) -DEF_HELPER_1(fcnvsd_FT_DT, i64, i32) -DEF_HELPER_1(fcnvds_DT_FT, i32, i64) +DEF_HELPER_1(fabs_FT, f32, f32) +DEF_HELPER_1(fabs_DT, f64, f64) +DEF_HELPER_2(fadd_FT, f32, f32, f32) +DEF_HELPER_2(fadd_DT, f64, f64, f64) +DEF_HELPER_1(fcnvsd_FT_DT, f64, f32) +DEF_HELPER_1(fcnvds_DT_FT, f32, f64) -DEF_HELPER_2(fcmp_eq_FT, void, i32, i32) -DEF_HELPER_2(fcmp_eq_DT, void, i64, i64) -DEF_HELPER_2(fcmp_gt_FT, void, i32, i32) -DEF_HELPER_2(fcmp_gt_DT, void, i64, i64) -DEF_HELPER_2(fdiv_FT, i32, i32, i32) -DEF_HELPER_2(fdiv_DT, i64, i64, i64) -DEF_HELPER_1(float_FT, i32, i32) -DEF_HELPER_1(float_DT, i64, i32) -DEF_HELPER_3(fmac_FT, i32, i32, i32, i32) -DEF_HELPER_2(fmul_FT, i32, i32, i32) -DEF_HELPER_2(fmul_DT, i64, i64, i64) -DEF_HELPER_1(fneg_T, i32, i32) -DEF_HELPER_2(fsub_FT, i32, i32, i32) -DEF_HELPER_2(fsub_DT, i64, i64, i64) -DEF_HELPER_1(fsqrt_FT, i32, i32) -DEF_HELPER_1(fsqrt_DT, i64, i64) -DEF_HELPER_1(ftrc_FT, i32, i32) -DEF_HELPER_1(ftrc_DT, i32, i64) +DEF_HELPER_2(fcmp_eq_FT, void, f32, f32) +DEF_HELPER_2(fcmp_eq_DT, void, f64, f64) +DEF_HELPER_2(fcmp_gt_FT, void, f32, f32) +DEF_HELPER_2(fcmp_gt_DT, void, f64, f64) +DEF_HELPER_2(fdiv_FT, f32, f32, f32) +DEF_HELPER_2(fdiv_DT, f64, f64, f64) +DEF_HELPER_1(float_FT, f32, i32) +DEF_HELPER_1(float_DT, f64, i32) +DEF_HELPER_3(fmac_FT, f32, f32, f32, f32) +DEF_HELPER_2(fmul_FT, f32, f32, f32) +DEF_HELPER_2(fmul_DT, f64, f64, f64) +DEF_HELPER_1(fneg_T, f32, f32) +DEF_HELPER_2(fsub_FT, f32, f32, f32) +DEF_HELPER_2(fsub_DT, f64, f64, f64) +DEF_HELPER_1(fsqrt_FT, f32, f32) +DEF_HELPER_1(fsqrt_DT, f64, f64) +DEF_HELPER_1(ftrc_FT, i32, f32) +DEF_HELPER_1(ftrc_DT, i32, f64) DEF_HELPER_2(fipr, void, i32, i32) DEF_HELPER_1(ftrv, void, i32) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index b8f4ca28ed..c127860cd9 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -487,53 +487,38 @@ static void update_fpscr(void *retaddr) } } -uint32_t helper_fabs_FT(uint32_t t0) +float32 helper_fabs_FT(float32 t0) { - CPU_FloatU f; - f.l = t0; - f.f = float32_abs(f.f); - return f.l; + return float32_abs(t0); } -uint64_t helper_fabs_DT(uint64_t t0) +float64 helper_fabs_DT(float64 t0) { - CPU_DoubleU d; - d.ll = t0; - d.d = float64_abs(d.d); - return d.ll; + return float64_abs(t0); } -uint32_t helper_fadd_FT(uint32_t t0, uint32_t t1) +float32 helper_fadd_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - f0.f = float32_add(f0.f, f1.f, &env->fp_status); + t0 = float32_add(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return f0.l; + return t0; } -uint64_t helper_fadd_DT(uint64_t t0, uint64_t t1) +float64 helper_fadd_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - d0.d = float64_add(d0.d, d1.d, &env->fp_status); + t0 = float64_add(t0, t1, &env->fp_status); update_fpscr(GETPC()); - return d0.ll; + return t0; } -void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1) +void helper_fcmp_eq_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; int relation; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(f0.f, f1.f, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_equal) { @@ -543,15 +528,12 @@ void helper_fcmp_eq_FT(uint32_t t0, uint32_t t1) } } -void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1) +void helper_fcmp_eq_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; int relation; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(d0.d, d1.d, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_equal) { @@ -561,15 +543,12 @@ void helper_fcmp_eq_DT(uint64_t t0, uint64_t t1) } } -void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1) +void helper_fcmp_gt_FT(float32 t0, float32 t1) { - CPU_FloatU f0, f1; int relation; - f0.l = t0; - f1.l = t1; set_float_exception_flags(0, &env->fp_status); - relation = float32_compare(f0.f, f1.f, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_greater) { @@ -579,15 +558,12 @@ void helper_fcmp_gt_FT(uint32_t t0, uint32_t t1) } } -void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1) +void helper_fcmp_gt_DT(float64 t0, float64 t1) { - CPU_DoubleU d0, d1; int relation; - d0.ll = t0; - d1.ll = t1; set_float_exception_flags(0, &env->fp_status); - relation = float64_compare(d0.d, d1.d, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); if (unlikely(relation == float_relation_unordered)) { update_fpscr(GETPC()); } else if (relation == float_relation_greater) { @@ -597,176 +573,134 @@ void helper_fcmp_gt_DT(uint64_t t0, uint64_t t1) } } -uint64_t helper_fcnvsd_FT_DT(uint32_t t0) +float64 helper_fcnvsd_FT_DT(float32 t0) { - CPU_DoubleU d; - CPU_FloatU f; - f.l = t0; + float64 ret; set_float_exception_flags(0, &env->fp_status); - d.d = float32_to_float64(f.f, &env->fp_status); - update_fpscr(GETPC()); - return d.ll; -} - -uint32_t helper_fcnvds_DT_FT(uint64_t t0) -{ - CPU_DoubleU d; - CPU_FloatU f; - d.ll = t0; - set_float_exception_flags(0, &env->fp_status); - f.f = float64_to_float32(d.d, &env->fp_status); - update_fpscr(GETPC()); - return f.l; -} - -uint32_t helper_fdiv_FT(uint32_t t0, uint32_t t1) -{ - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; - set_float_exception_flags(0, &env->fp_status); - f0.f = float32_div(f0.f, f1.f, &env->fp_status); - update_fpscr(GETPC()); - return f0.l; -} - -uint64_t helper_fdiv_DT(uint64_t t0, uint64_t t1) -{ - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; - set_float_exception_flags(0, &env->fp_status); - d0.d = float64_div(d0.d, d1.d, &env->fp_status); - update_fpscr(GETPC()); - return d0.ll; -} - -uint32_t helper_float_FT(uint32_t t0) -{ - CPU_FloatU f; - - set_float_exception_flags(0, &env->fp_status); - f.f = int32_to_float32(t0, &env->fp_status); - update_fpscr(GETPC()); - - return f.l; -} - -uint64_t helper_float_DT(uint32_t t0) -{ - CPU_DoubleU d; - set_float_exception_flags(0, &env->fp_status); - d.d = int32_to_float64(t0, &env->fp_status); - update_fpscr(GETPC()); - return d.ll; -} - -uint32_t helper_fmac_FT(uint32_t t0, uint32_t t1, uint32_t t2) -{ - CPU_FloatU f0, f1, f2; - f0.l = t0; - f1.l = t1; - f2.l = t2; - set_float_exception_flags(0, &env->fp_status); - f0.f = float32_mul(f0.f, f1.f, &env->fp_status); - f0.f = float32_add(f0.f, f2.f, &env->fp_status); - update_fpscr(GETPC()); - - return f0.l; -} - -uint32_t helper_fmul_FT(uint32_t t0, uint32_t t1) -{ - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; - set_float_exception_flags(0, &env->fp_status); - f0.f = float32_mul(f0.f, f1.f, &env->fp_status); - update_fpscr(GETPC()); - return f0.l; -} - -uint64_t helper_fmul_DT(uint64_t t0, uint64_t t1) -{ - CPU_DoubleU d0, d1; - d0.ll = t0; - d1.ll = t1; - set_float_exception_flags(0, &env->fp_status); - d0.d = float64_mul(d0.d, d1.d, &env->fp_status); - update_fpscr(GETPC()); - - return d0.ll; -} - -uint32_t helper_fneg_T(uint32_t t0) -{ - CPU_FloatU f; - f.l = t0; - f.f = float32_chs(f.f); - return f.l; -} - -uint32_t helper_fsqrt_FT(uint32_t t0) -{ - CPU_FloatU f; - f.l = t0; - set_float_exception_flags(0, &env->fp_status); - f.f = float32_sqrt(f.f, &env->fp_status); - update_fpscr(GETPC()); - return f.l; -} - -uint64_t helper_fsqrt_DT(uint64_t t0) -{ - CPU_DoubleU d; - d.ll = t0; - set_float_exception_flags(0, &env->fp_status); - d.d = float64_sqrt(d.d, &env->fp_status); - update_fpscr(GETPC()); - return d.ll; -} - -uint32_t helper_fsub_FT(uint32_t t0, uint32_t t1) -{ - CPU_FloatU f0, f1; - f0.l = t0; - f1.l = t1; - set_float_exception_flags(0, &env->fp_status); - f0.f = float32_sub(f0.f, f1.f, &env->fp_status); - update_fpscr(GETPC()); - return f0.l; -} - -uint64_t helper_fsub_DT(uint64_t t0, uint64_t t1) -{ - CPU_DoubleU d0, d1; - - d0.ll = t0; - d1.ll = t1; - set_float_exception_flags(0, &env->fp_status); - d0.d = float64_sub(d0.d, d1.d, &env->fp_status); - update_fpscr(GETPC()); - return d0.ll; -} - -uint32_t helper_ftrc_FT(uint32_t t0) -{ - CPU_FloatU f; - uint32_t ret; - f.l = t0; - set_float_exception_flags(0, &env->fp_status); - ret = float32_to_int32_round_to_zero(f.f, &env->fp_status); + ret = float32_to_float64(t0, &env->fp_status); update_fpscr(GETPC()); return ret; } -uint32_t helper_ftrc_DT(uint64_t t0) +float32 helper_fcnvds_DT_FT(float64 t0) { - CPU_DoubleU d; - uint32_t ret; - d.ll = t0; + float32 ret; set_float_exception_flags(0, &env->fp_status); - ret = float64_to_int32_round_to_zero(d.d, &env->fp_status); + ret = float64_to_float32(t0, &env->fp_status); + update_fpscr(GETPC()); + return ret; +} + +float32 helper_fdiv_FT(float32 t0, float32 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float32_div(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float64 helper_fdiv_DT(float64 t0, float64 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float64_div(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float32 helper_float_FT(uint32_t t0) +{ + float32 ret; + set_float_exception_flags(0, &env->fp_status); + ret = int32_to_float32(t0, &env->fp_status); + update_fpscr(GETPC()); + return ret; +} + +float64 helper_float_DT(uint32_t t0) +{ + float64 ret; + set_float_exception_flags(0, &env->fp_status); + ret = int32_to_float64(t0, &env->fp_status); + update_fpscr(GETPC()); + return ret; +} + +float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); + t0 = float32_add(t0, t2, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float32 helper_fmul_FT(float32 t0, float32 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float64 helper_fmul_DT(float64 t0, float64 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float64_mul(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float32 helper_fneg_T(float32 t0) +{ + return float32_chs(t0); +} + +float32 helper_fsqrt_FT(float32 t0) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float32_sqrt(t0, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float64 helper_fsqrt_DT(float64 t0) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float64_sqrt(t0, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float32 helper_fsub_FT(float32 t0, float32 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float32_sub(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +float64 helper_fsub_DT(float64 t0, float64 t1) +{ + set_float_exception_flags(0, &env->fp_status); + t0 = float64_sub(t0, t1, &env->fp_status); + update_fpscr(GETPC()); + return t0; +} + +uint32_t helper_ftrc_FT(float32 t0) +{ + uint32_t ret; + set_float_exception_flags(0, &env->fp_status); + ret = float32_to_int32_round_to_zero(t0, &env->fp_status); + update_fpscr(GETPC()); + return ret; +} + +uint32_t helper_ftrc_DT(float64 t0) +{ + uint32_t ret; + set_float_exception_flags(0, &env->fp_status); + ret = float64_to_int32_round_to_zero(t0, &env->fp_status); update_fpscr(GETPC()); return ret; } From 7dae117a58dc89af15e3832fe435a4037c83d3d2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Sun, 10 Apr 2011 21:09:12 +0200 Subject: [PATCH 156/386] target-ppc: remove #ifdef FLOAT128 Now that PPC defaults to softfloat which always provides float128 support, there is no need to keep two version of the code, depending if float128 support is available or not. Suggested by Peter Maydell. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-ppc/op_helper.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5882becbc9..8c993a1cf5 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1287,7 +1287,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1303,10 +1302,6 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) + farg3.d; -#endif } return farg1.ll; @@ -1332,7 +1327,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1348,10 +1342,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) - farg3.d; -#endif } return farg1.ll; } @@ -1376,7 +1366,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1392,10 +1381,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) + farg3.d; -#endif if (likely(!float64_is_any_nan(farg1.d))) { farg1.d = float64_chs(farg1.d); } @@ -1423,7 +1408,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* sNaN operation */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); } -#ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1439,10 +1423,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); farg1.d = float128_to_float64(ft0_128, &env->fp_status); } -#else - /* This is OK on x86 hosts */ - farg1.d = (farg1.d * farg2.d) - farg3.d; -#endif if (likely(!float64_is_any_nan(farg1.d))) { farg1.d = float64_chs(farg1.d); } From f50ee4e0749604373bfd3bf3bb1d94c28787a378 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Sat, 9 Apr 2011 23:13:20 +0200 Subject: [PATCH 157/386] configure: disable opengl per default There is a bug in nvidia's binary GPU driver, which causes a segmentation fault if linked to libGL. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index ed4d951ce9..da2da04059 100755 --- a/configure +++ b/configure @@ -177,6 +177,7 @@ spice="" rbd="" smartcard="" smartcard_nss="" +opengl="no" # parse CC options first for opt do From 3bad98147f84f2606afe2afb9d80ea15d3e1c39f Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 10 Apr 2011 17:28:56 +0200 Subject: [PATCH 158/386] cpu-common: Modify cpu_physical_memory_read and cpu_physical_memory_write A lot of calls don't operate on bytes but on words or on structured data. So instead of a pointer to uint8_t, a void pointer is the better choice. This allows removing many type casts. (Some very early implementations of memcpy used char pointers which were replaced by void pointers for the same reason). Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- cpu-common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index ef4e8dab7a..96c02aeb64 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -68,14 +68,14 @@ void cpu_unregister_io_memory(int table_address); void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write); static inline void cpu_physical_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) + void *buf, int len) { cpu_physical_memory_rw(addr, buf, len, 0); } static inline void cpu_physical_memory_write(target_phys_addr_t addr, - const uint8_t *buf, int len) + const void *buf, int len) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); + cpu_physical_memory_rw(addr, (void *)buf, len, 1); } void *cpu_physical_memory_map(target_phys_addr_t addr, target_phys_addr_t *plen, From 71d2b725e1f38162872b198992a61fa460978d77 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sat, 26 Mar 2011 21:06:56 +0100 Subject: [PATCH 159/386] exec: Remove a type cast which is no longer needed All other type casts in calls of cpu_physical_memory_write are used by hardware emulations and will be fixed by separate patches. Cc: Blue Swirl <blauwirbel@gmail.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 983c0db3f7..e8f1eeb750 100644 --- a/exec.c +++ b/exec.c @@ -4253,7 +4253,7 @@ void stw_phys(target_phys_addr_t addr, uint32_t val) void stq_phys(target_phys_addr_t addr, uint64_t val) { val = tswap64(val); - cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); + cpu_physical_memory_write(addr, &val, 8); } /* virtual memory access for debug (includes writing to ROM) */ From b8b79323d0f26959237fdb80053cd48a750e3482 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sat, 26 Mar 2011 21:11:05 +0100 Subject: [PATCH 160/386] monitor: Remove some type casts which are no longer needed All other type casts in calls of cpu_physical_memory_read are used by hardware emulations and will be fixed by separate patches. Cc: Blue Swirl <blauwirbel@gmail.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- monitor.c | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/monitor.c b/monitor.c index f1a08dc486..07186ca028 100644 --- a/monitor.c +++ b/monitor.c @@ -2026,7 +2026,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env) pgd = env->cr[3] & ~0xfff; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { @@ -2034,8 +2034,7 @@ static void tlb_info_32(Monitor *mon, CPUState *env) print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 22) + (l2 << 12), @@ -2056,13 +2055,12 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env) pdp_addr = env->cr[3] & ~0x1f; for (l1 = 0; l1 < 4; l1++) { - cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8); + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); if (pdpe & PG_PRESENT_MASK) { pd_addr = pdpe & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pd_addr + l2 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); pde = le64_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if (pde & PG_PSE_MASK) { @@ -2072,8 +2070,7 @@ static void tlb_info_pae32(Monitor *mon, CPUState *env) } else { pt_addr = pde & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pt_addr + l3 * 8, - (uint8_t *)&pte, 8); + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); pte = le64_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 30 ) + (l2 << 21) @@ -2098,13 +2095,12 @@ static void tlb_info_64(Monitor *mon, CPUState *env) pml4_addr = env->cr[3] & 0x3fffffffff000ULL; for (l1 = 0; l1 < 512; l1++) { - cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8); + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); pml4e = le64_to_cpu(pml4e); if (pml4e & PG_PRESENT_MASK) { pdp_addr = pml4e & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe, - 8); + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); if (pdpe & PG_PRESENT_MASK) { if (pdpe & PG_PSE_MASK) { @@ -2114,8 +2110,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env) } else { pd_addr = pdpe & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pd_addr + l3 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); pde = le64_to_cpu(pde); if (pde & PG_PRESENT_MASK) { if (pde & PG_PSE_MASK) { @@ -2128,8 +2123,7 @@ static void tlb_info_64(Monitor *mon, CPUState *env) for (l4 = 0; l4 < 512; l4++) { cpu_physical_memory_read(pt_addr + l4 * 8, - (uint8_t *)&pte, - 8); + &pte, 8); pte = le64_to_cpu(pte); if (pte & PG_PRESENT_MASK) { print_pte(mon, (l1 << 39) + @@ -2207,7 +2201,7 @@ static void mem_info_32(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for(l1 = 0; l1 < 1024; l1++) { - cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + cpu_physical_memory_read(pgd + l1 * 4, &pde, 4); pde = le32_to_cpu(pde); end = l1 << 22; if (pde & PG_PRESENT_MASK) { @@ -2216,8 +2210,7 @@ static void mem_info_32(Monitor *mon, CPUState *env) mem_print(mon, &start, &last_prot, end, prot); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, - (uint8_t *)&pte, 4); + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); end = (l1 << 22) + (l2 << 12); if (pte & PG_PRESENT_MASK) { @@ -2246,14 +2239,13 @@ static void mem_info_pae32(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for (l1 = 0; l1 < 4; l1++) { - cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8); + cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); end = l1 << 30; if (pdpe & PG_PRESENT_MASK) { pd_addr = pdpe & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pd_addr + l2 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8); pde = le64_to_cpu(pde); end = (l1 << 30) + (l2 << 21); if (pde & PG_PRESENT_MASK) { @@ -2264,8 +2256,7 @@ static void mem_info_pae32(Monitor *mon, CPUState *env) } else { pt_addr = pde & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pt_addr + l3 * 8, - (uint8_t *)&pte, 8); + cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); pte = le64_to_cpu(pte); end = (l1 << 30) + (l2 << 21) + (l3 << 12); if (pte & PG_PRESENT_MASK) { @@ -2302,14 +2293,13 @@ static void mem_info_64(Monitor *mon, CPUState *env) last_prot = 0; start = -1; for (l1 = 0; l1 < 512; l1++) { - cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8); + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); pml4e = le64_to_cpu(pml4e); end = l1 << 39; if (pml4e & PG_PRESENT_MASK) { pdp_addr = pml4e & 0x3fffffffff000ULL; for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe, - 8); + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); pdpe = le64_to_cpu(pdpe); end = (l1 << 39) + (l2 << 30); if (pdpe & PG_PRESENT_MASK) { @@ -2320,8 +2310,7 @@ static void mem_info_64(Monitor *mon, CPUState *env) } else { pd_addr = pdpe & 0x3fffffffff000ULL; for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pd_addr + l3 * 8, - (uint8_t *)&pde, 8); + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); pde = le64_to_cpu(pde); end = (l1 << 39) + (l2 << 30) + (l3 << 21); if (pde & PG_PRESENT_MASK) { @@ -2334,8 +2323,7 @@ static void mem_info_64(Monitor *mon, CPUState *env) for (l4 = 0; l4 < 512; l4++) { cpu_physical_memory_read(pt_addr + l4 * 8, - (uint8_t *)&pte, - 8); + &pte, 8); pte = le64_to_cpu(pte); end = (l1 << 39) + (l2 << 30) + (l3 << 21) + (l4 << 12); From 54f7b4a396d00522d99c685562a54725a1b52e40 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 10 Apr 2011 18:23:39 +0200 Subject: [PATCH 161/386] Replace cpu_physical_memory_rw were possible Using cpu_physical_memory_read, cpu_physical_memory_write and ldub_phys improves readability and allows removing some type casts. lduw_phys and ldl_phys were not used because both require aligned addresses. Therefore it is not possible to simply replace existing calls by one of these functions. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- disas.c | 2 +- exec.c | 2 +- hw/rc4030.c | 4 ++-- hw/s390-virtio-bus.c | 3 ++- hw/s390-virtio.c | 4 ++-- hw/sm501_template.h | 2 +- hw/usb-ohci.c | 14 ++++++-------- monitor.c | 9 ++++----- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/disas.c b/disas.c index 17b4ce47b2..223606cc50 100644 --- a/disas.c +++ b/disas.c @@ -345,7 +345,7 @@ monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, struct disassemble_info *info) { if (monitor_disas_is_physical) { - cpu_physical_memory_rw(memaddr, myaddr, length, 0); + cpu_physical_memory_read(memaddr, myaddr, length); } else { cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); } diff --git a/exec.c b/exec.c index e8f1eeb750..b1ee52a4d0 100644 --- a/exec.c +++ b/exec.c @@ -3932,7 +3932,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, bounce.addr = addr; bounce.len = l; if (!is_write) { - cpu_physical_memory_rw(addr, bounce.buffer, l, 0); + cpu_physical_memory_read(addr, bounce.buffer, l); } ptr = bounce.buffer; } else { diff --git a/hw/rc4030.c b/hw/rc4030.c index d30230a859..6563336dd0 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -307,7 +307,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { target_phys_addr_t dest = s->cache_ptag & ~0x1; dest += (s->cache_maint & 0x3) << 3; - cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1); + cpu_physical_memory_write(dest, &val, 4); } break; /* Remote Speed Registers */ @@ -704,7 +704,7 @@ void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, i entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); /* XXX: not sure. should we really use only lowest bits? */ entry_addr &= 0x7fffffff; - cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0); + cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); /* Read/write data at right place */ phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 60e0135ed8..175e5cb3a0 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -233,7 +233,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev) dev->vdev->get_config(dev->vdev, dev->vdev->config); } - cpu_physical_memory_rw(cur_offs, dev->vdev->config, dev->vdev->config_len, 1); + cpu_physical_memory_write(cur_offs, + dev->vdev->config, dev->vdev->config_len); cur_offs += dev->vdev->config_len; } diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 850422fee0..d429f10d56 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -230,8 +230,8 @@ static void s390_init(ram_addr_t ram_size, } if (kernel_cmdline) { - cpu_physical_memory_rw(KERN_PARM_AREA, (uint8_t *)kernel_cmdline, - strlen(kernel_cmdline), 1); + cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline, + strlen(kernel_cmdline)); } /* Create VirtIO network adapters */ diff --git a/hw/sm501_template.h b/hw/sm501_template.h index d1ceef9cb6..2d4a3d8b48 100644 --- a/hw/sm501_template.h +++ b/hw/sm501_template.h @@ -120,7 +120,7 @@ static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt, /* get pixel value */ if (i % 4 == 0) { - cpu_physical_memory_rw(cursor_addr, &bitset, 1, 0); + bitset = ldub_phys(cursor_addr); cursor_addr++; } v = bitset & 3; diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index d2b14f7b4f..0ad4f555d0 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -427,7 +427,7 @@ static inline int get_dwords(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + cpu_physical_memory_read(addr, buf, sizeof(*buf)); *buf = le32_to_cpu(*buf); } @@ -444,7 +444,7 @@ static inline int put_dwords(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); - cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + cpu_physical_memory_write(addr, &tmp, sizeof(tmp)); } return 1; @@ -459,7 +459,7 @@ static inline int get_words(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + cpu_physical_memory_read(addr, buf, sizeof(*buf)); *buf = le16_to_cpu(*buf); } @@ -476,7 +476,7 @@ static inline int put_words(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint16_t tmp = cpu_to_le16(*buf); - cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + cpu_physical_memory_write(addr, &tmp, sizeof(tmp)); } return 1; @@ -504,8 +504,7 @@ static inline int ohci_read_iso_td(OHCIState *ohci, static inline int ohci_read_hcca(OHCIState *ohci, uint32_t addr, struct ohci_hcca *hcca) { - cpu_physical_memory_rw(addr + ohci->localmem_base, - (uint8_t *)hcca, sizeof(*hcca), 0); + cpu_physical_memory_read(addr + ohci->localmem_base, hcca, sizeof(*hcca)); return 1; } @@ -531,8 +530,7 @@ static inline int ohci_put_iso_td(OHCIState *ohci, static inline int ohci_put_hcca(OHCIState *ohci, uint32_t addr, struct ohci_hcca *hcca) { - cpu_physical_memory_rw(addr + ohci->localmem_base, - (uint8_t *)hcca, sizeof(*hcca), 1); + cpu_physical_memory_write(addr + ohci->localmem_base, hcca, sizeof(*hcca)); return 1; } diff --git a/monitor.c b/monitor.c index 07186ca028..5f3bc726bd 100644 --- a/monitor.c +++ b/monitor.c @@ -1429,7 +1429,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize, if (l > line_size) l = line_size; if (is_physical) { - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); } else { env = mon_get_cpu(); if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) { @@ -1605,7 +1605,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict, l = sizeof(buf); if (l > size) l = size; - cpu_physical_memory_rw(addr, buf, l, 0); + cpu_physical_memory_read(addr, buf, l); if (fwrite(buf, 1, l, f) != l) { monitor_printf(mon, "fwrite() error in do_physical_memory_save\n"); goto exit; @@ -1625,17 +1625,16 @@ exit: static void do_sum(Monitor *mon, const QDict *qdict) { uint32_t addr; - uint8_t buf[1]; uint16_t sum; uint32_t start = qdict_get_int(qdict, "start"); uint32_t size = qdict_get_int(qdict, "size"); sum = 0; for(addr = start; addr < (start + size); addr++) { - cpu_physical_memory_rw(addr, buf, 1, 0); + uint8_t val = ldub_phys(addr); /* BSD sum algorithm ('sum' Unix command) */ sum = (sum >> 1) | (sum << 15); - sum += buf[0]; + sum += val; } monitor_printf(mon, "%05d\n", sum); } From 54f8e61d5bf8c80c407d8d6ea46ead816c029512 Mon Sep 17 00:00:00 2001 From: Wen Congyang <wency@cn.fujitsu.com> Date: Tue, 12 Apr 2011 17:27:44 +0800 Subject: [PATCH 162/386] fix acpi regression This bug is introduced by commit 23910d3f. Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index e372474399..ad40fb4c3c 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -355,7 +355,7 @@ static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr) if (addr < gpe->len / 2) { cur = gpe->sts + addr; } else if (addr < gpe->len) { - cur = gpe->en + addr; + cur = gpe->en + addr - gpe->len / 2; } else { abort(); } From 62698be3bac2e4c969205f3849c48922e0e76e88 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:11 +0100 Subject: [PATCH 163/386] target-arm: Use lookup table for size check on Neon 3-reg-same insns Simplify the checks for invalid size values for the Neon "three registers of the same size" instruction forms (and add them where they were missing) by using a lookup table. This includes adding symbolic constants for the op values in this space, since we now use them in multiple places. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 197 ++++++++++++++++++++++++++++------------- 1 file changed, 133 insertions(+), 64 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 998cfd530c..3fa27e145b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3558,15 +3558,14 @@ static void gen_nop_hint(DisasContext *s, int val) #define CPU_V001 cpu_V0, cpu_V0, cpu_V1 -static inline int gen_neon_add(int size, TCGv t0, TCGv t1) +static inline void gen_neon_add(int size, TCGv t0, TCGv t1) { switch (size) { case 0: gen_helper_neon_add_u8(t0, t0, t1); break; case 1: gen_helper_neon_add_u16(t0, t0, t1); break; case 2: tcg_gen_add_i32(t0, t0, t1); break; - default: return 1; + default: abort(); } - return 0; } static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1) @@ -4245,6 +4244,74 @@ static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src) } } +/* Symbolic constants for op fields for Neon 3-register same-length. + * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B + * table A7-9. + */ +#define NEON_3R_VHADD 0 +#define NEON_3R_VQADD 1 +#define NEON_3R_VRHADD 2 +#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */ +#define NEON_3R_VHSUB 4 +#define NEON_3R_VQSUB 5 +#define NEON_3R_VCGT 6 +#define NEON_3R_VCGE 7 +#define NEON_3R_VSHL 8 +#define NEON_3R_VQSHL 9 +#define NEON_3R_VRSHL 10 +#define NEON_3R_VQRSHL 11 +#define NEON_3R_VMAX 12 +#define NEON_3R_VMIN 13 +#define NEON_3R_VABD 14 +#define NEON_3R_VABA 15 +#define NEON_3R_VADD_VSUB 16 +#define NEON_3R_VTST_VCEQ 17 +#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */ +#define NEON_3R_VMUL 19 +#define NEON_3R_VPMAX 20 +#define NEON_3R_VPMIN 21 +#define NEON_3R_VQDMULH_VQRDMULH 22 +#define NEON_3R_VPADD 23 +#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */ +#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */ +#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */ +#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */ +#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */ +#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */ + +static const uint8_t neon_3r_sizes[] = { + [NEON_3R_VHADD] = 0x7, + [NEON_3R_VQADD] = 0xf, + [NEON_3R_VRHADD] = 0x7, + [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */ + [NEON_3R_VHSUB] = 0x7, + [NEON_3R_VQSUB] = 0xf, + [NEON_3R_VCGT] = 0x7, + [NEON_3R_VCGE] = 0x7, + [NEON_3R_VSHL] = 0xf, + [NEON_3R_VQSHL] = 0xf, + [NEON_3R_VRSHL] = 0xf, + [NEON_3R_VQRSHL] = 0xf, + [NEON_3R_VMAX] = 0x7, + [NEON_3R_VMIN] = 0x7, + [NEON_3R_VABD] = 0x7, + [NEON_3R_VABA] = 0x7, + [NEON_3R_VADD_VSUB] = 0xf, + [NEON_3R_VTST_VCEQ] = 0x7, + [NEON_3R_VML] = 0x7, + [NEON_3R_VMUL] = 0x7, + [NEON_3R_VPMAX] = 0x7, + [NEON_3R_VPMIN] = 0x7, + [NEON_3R_VQDMULH_VQRDMULH] = 0x6, + [NEON_3R_VPADD] = 0x7, + [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */ + [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */ +}; + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. We process data in a mixture of 32-bit and 64-bit chunks. @@ -4277,56 +4344,59 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if ((insn & (1 << 23)) == 0) { /* Three register same length. */ op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); - if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9 - || op == 10 || op == 11 || op == 16)) { - /* 64-bit element instructions. */ + /* Catch invalid op and bad size combinations: UNDEF */ + if ((neon_3r_sizes[op] & (1 << size)) == 0) { + return 1; + } + if (size == 3 && op != NEON_3R_LOGIC) { + /* 64-bit element instructions. */ for (pass = 0; pass < (q ? 2 : 1); pass++) { neon_load_reg64(cpu_V0, rn + pass); neon_load_reg64(cpu_V1, rm + pass); switch (op) { - case 1: /* VQADD */ + case NEON_3R_VQADD: if (u) { gen_helper_neon_qadd_u64(cpu_V0, cpu_V0, cpu_V1); } else { gen_helper_neon_qadd_s64(cpu_V0, cpu_V0, cpu_V1); } break; - case 5: /* VQSUB */ + case NEON_3R_VQSUB: if (u) { gen_helper_neon_qsub_u64(cpu_V0, cpu_V0, cpu_V1); } else { gen_helper_neon_qsub_s64(cpu_V0, cpu_V0, cpu_V1); } break; - case 8: /* VSHL */ + case NEON_3R_VSHL: if (u) { gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 9: /* VQSHL */ + case NEON_3R_VQSHL: if (u) { gen_helper_neon_qshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_qshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 10: /* VRSHL */ + case NEON_3R_VRSHL: if (u) { gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 11: /* VQRSHL */ + case NEON_3R_VQRSHL: if (u) { gen_helper_neon_qrshl_u64(cpu_V0, cpu_V1, cpu_V0); } else { gen_helper_neon_qrshl_s64(cpu_V0, cpu_V1, cpu_V0); } break; - case 16: + case NEON_3R_VADD_VSUB: if (u) { tcg_gen_sub_i64(CPU_V001); } else { @@ -4341,10 +4411,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) return 0; } switch (op) { - case 8: /* VSHL */ - case 9: /* VQSHL */ - case 10: /* VRSHL */ - case 11: /* VQRSHL */ + case NEON_3R_VSHL: + case NEON_3R_VQSHL: + case NEON_3R_VRSHL: + case NEON_3R_VQRSHL: { int rtmp; /* Shift instruction operands are reversed. */ @@ -4354,15 +4424,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) pairwise = 0; } break; - case 20: /* VPMAX */ - case 21: /* VPMIN */ - case 23: /* VPADD */ + case NEON_3R_VPMAX: + case NEON_3R_VPMIN: + case NEON_3R_VPADD: pairwise = 1; break; - case 26: /* VPADD (float) */ + case NEON_3R_FLOAT_ARITH: /* VADD, VSUB, VPADD, VABD (float) */ pairwise = (u && size < 2); break; - case 30: /* VPMIN/VPMAX (float) */ + case NEON_3R_FLOAT_MINMAX: /* VPMIN/VPMAX (float) */ pairwise = u; break; default: @@ -4391,16 +4461,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(rm, pass); } switch (op) { - case 0: /* VHADD */ + case NEON_3R_VHADD: GEN_NEON_INTEGER_OP(hadd); break; - case 1: /* VQADD */ + case NEON_3R_VQADD: GEN_NEON_INTEGER_OP(qadd); break; - case 2: /* VRHADD */ + case NEON_3R_VRHADD: GEN_NEON_INTEGER_OP(rhadd); break; - case 3: /* Logic ops. */ + case NEON_3R_LOGIC: /* Logic ops. */ switch ((u << 2) | size) { case 0: /* VAND */ tcg_gen_and_i32(tmp, tmp, tmp2); @@ -4434,81 +4504,80 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; } break; - case 4: /* VHSUB */ + case NEON_3R_VHSUB: GEN_NEON_INTEGER_OP(hsub); break; - case 5: /* VQSUB */ + case NEON_3R_VQSUB: GEN_NEON_INTEGER_OP(qsub); break; - case 6: /* VCGT */ + case NEON_3R_VCGT: GEN_NEON_INTEGER_OP(cgt); break; - case 7: /* VCGE */ + case NEON_3R_VCGE: GEN_NEON_INTEGER_OP(cge); break; - case 8: /* VSHL */ + case NEON_3R_VSHL: GEN_NEON_INTEGER_OP(shl); break; - case 9: /* VQSHL */ + case NEON_3R_VQSHL: GEN_NEON_INTEGER_OP(qshl); break; - case 10: /* VRSHL */ + case NEON_3R_VRSHL: GEN_NEON_INTEGER_OP(rshl); break; - case 11: /* VQRSHL */ + case NEON_3R_VQRSHL: GEN_NEON_INTEGER_OP(qrshl); break; - case 12: /* VMAX */ + case NEON_3R_VMAX: GEN_NEON_INTEGER_OP(max); break; - case 13: /* VMIN */ + case NEON_3R_VMIN: GEN_NEON_INTEGER_OP(min); break; - case 14: /* VABD */ + case NEON_3R_VABD: GEN_NEON_INTEGER_OP(abd); break; - case 15: /* VABA */ + case NEON_3R_VABA: GEN_NEON_INTEGER_OP(abd); tcg_temp_free_i32(tmp2); tmp2 = neon_load_reg(rd, pass); gen_neon_add(size, tmp, tmp2); break; - case 16: + case NEON_3R_VADD_VSUB: if (!u) { /* VADD */ - if (gen_neon_add(size, tmp, tmp2)) - return 1; + gen_neon_add(size, tmp, tmp2); } else { /* VSUB */ switch (size) { case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 17: + case NEON_3R_VTST_VCEQ: if (!u) { /* VTST */ switch (size) { case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } else { /* VCEQ */ switch (size) { case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 18: /* Multiply. */ + case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */ switch (size) { case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free_i32(tmp2); tmp2 = neon_load_reg(rd, pass); @@ -4518,7 +4587,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_neon_add(size, tmp, tmp2); } break; - case 19: /* VMUL */ + case NEON_3R_VMUL: if (u) { /* polynomial */ gen_helper_neon_mul_p8(tmp, tmp, tmp2); } else { /* Integer */ @@ -4526,42 +4595,42 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 20: /* VPMAX */ + case NEON_3R_VPMAX: GEN_NEON_INTEGER_OP(pmax); break; - case 21: /* VPMIN */ + case NEON_3R_VPMIN: GEN_NEON_INTEGER_OP(pmin); break; - case 22: /* Hultiply high. */ + case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */ if (!u) { /* VQDMULH */ switch (size) { case 1: gen_helper_neon_qdmulh_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_qdmulh_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } - } else { /* VQRDHMUL */ + } else { /* VQRDMULH */ switch (size) { case 1: gen_helper_neon_qrdmulh_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_qrdmulh_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } break; - case 23: /* VPADD */ + case NEON_3R_VPADD: if (u) return 1; switch (size) { case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } break; - case 26: /* Floating point arithnetic. */ + case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */ switch ((u << 2) | size) { case 0: /* VADD */ gen_helper_neon_add_f32(tmp, tmp, tmp2); @@ -4576,10 +4645,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_abd_f32(tmp, tmp, tmp2); break; default: - return 1; + abort(); } break; - case 27: /* Float multiply. */ + case NEON_3R_FLOAT_MULTIPLY: gen_helper_neon_mul_f32(tmp, tmp, tmp2); if (!u) { tcg_temp_free_i32(tmp2); @@ -4591,7 +4660,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 28: /* Float compare. */ + case NEON_3R_FLOAT_CMP: if (!u) { gen_helper_neon_ceq_f32(tmp, tmp, tmp2); } else { @@ -4601,7 +4670,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_cgt_f32(tmp, tmp, tmp2); } break; - case 29: /* Float compare absolute. */ + case NEON_3R_FLOAT_ACMP: if (!u) return 1; if (size == 0) @@ -4609,13 +4678,13 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) else gen_helper_neon_acgt_f32(tmp, tmp, tmp2); break; - case 30: /* Float min/max. */ + case NEON_3R_FLOAT_MINMAX: if (size == 0) gen_helper_neon_max_f32(tmp, tmp, tmp2); else gen_helper_neon_min_f32(tmp, tmp, tmp2); break; - case 31: + case NEON_3R_VRECPS_VRSQRTS: if (size == 0) gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env); else From 25f84f79481db5363c638dd95d5c2a0a0e430cee Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:12 +0100 Subject: [PATCH 164/386] target-arm: Handle UNDEF cases for Neon 3-regs-same insns Correct the handling of UNDEF cases for the NEON "3 registers same size" forms, by adding missing checks and rationalising some others so they are done early enough to avoid leaking TCG temporaries. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 54 +++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 3fa27e145b..5ffbace5ae 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4348,6 +4348,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if ((neon_3r_sizes[op] & (1 << size)) == 0) { return 1; } + /* All insns of this form UNDEF for either this condition or the + * superset of cases "Q==1"; we catch the latter later. + */ + if (q && ((rd | rn | rm) & 1)) { + return 1; + } if (size == 3 && op != NEON_3R_LOGIC) { /* 64-bit element instructions. */ for (pass = 0; pass < (q ? 2 : 1); pass++) { @@ -4410,6 +4416,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } return 0; } + pairwise = 0; switch (op) { case NEON_3R_VSHL: case NEON_3R_VQSHL: @@ -4421,25 +4428,54 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) rtmp = rn; rn = rm; rm = rtmp; - pairwise = 0; } break; + case NEON_3R_VPADD: + if (u) { + return 1; + } + /* Fall through */ case NEON_3R_VPMAX: case NEON_3R_VPMIN: - case NEON_3R_VPADD: pairwise = 1; break; - case NEON_3R_FLOAT_ARITH: /* VADD, VSUB, VPADD, VABD (float) */ - pairwise = (u && size < 2); + case NEON_3R_FLOAT_ARITH: + pairwise = (u && size < 2); /* if VPADD (float) */ break; - case NEON_3R_FLOAT_MINMAX: /* VPMIN/VPMAX (float) */ - pairwise = u; + case NEON_3R_FLOAT_MINMAX: + pairwise = u; /* if VPMIN/VPMAX (float) */ + break; + case NEON_3R_FLOAT_CMP: + if (!u && size) { + /* no encoding for U=0 C=1x */ + return 1; + } + break; + case NEON_3R_FLOAT_ACMP: + if (!u) { + return 1; + } + break; + case NEON_3R_VRECPS_VRSQRTS: + if (u) { + return 1; + } + break; + case NEON_3R_VMUL: + if (u && (size != 0)) { + /* UNDEF on invalid size for polynomial subcase */ + return 1; + } break; default: - pairwise = 0; break; } + if (pairwise && q) { + /* All the pairwise insns UNDEF if Q is set */ + return 1; + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { if (pairwise) { @@ -4621,8 +4657,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } break; case NEON_3R_VPADD: - if (u) - return 1; switch (size) { case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break; @@ -4671,8 +4705,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } break; case NEON_3R_FLOAT_ACMP: - if (!u) - return 1; if (size == 0) gen_helper_neon_acge_f32(tmp, tmp, tmp2); else From a5a14945da2c9ea8903c69af22274c33ad9488f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= <juha.riihimaki@nokia.com> Date: Mon, 11 Apr 2011 16:26:13 +0100 Subject: [PATCH 165/386] target-arm: Simplify three-register pairwise code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we know that the case of (pairwise && q) has been caught earlier, we can simplify the register setup code for each pass in the three-register-same-size Neon loop. Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 5ffbace5ae..0cf933d021 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4328,7 +4328,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) int count; int pairwise; int u; - int n; uint32_t imm, mask; TCGv tmp, tmp2, tmp3, tmp4, tmp5; TCGv_i64 tmp64; @@ -4480,16 +4479,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (pairwise) { /* Pairwise. */ - if (q) - n = (pass & 1) * 2; - else - n = 0; - if (pass < q + 1) { - tmp = neon_load_reg(rn, n); - tmp2 = neon_load_reg(rn, n + 1); + if (pass < 1) { + tmp = neon_load_reg(rn, 0); + tmp2 = neon_load_reg(rn, 1); } else { - tmp = neon_load_reg(rm, n); - tmp2 = neon_load_reg(rm, n + 1); + tmp = neon_load_reg(rm, 0); + tmp2 = neon_load_reg(rm, 1); } } else { /* Elementwise. */ @@ -5147,6 +5142,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* VMOV, VMVN. */ tmp = tcg_temp_new_i32(); if (op == 14 && invert) { + int n; uint32_t val; val = 0; for (n = 0; n < 4; n++) { @@ -5575,6 +5571,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 33: /* VTRN */ if (size == 2) { + int n; for (n = 0; n < (q ? 4 : 2); n += 2) { tmp = neon_load_reg(rm, n); tmp2 = neon_load_reg(rd, n + 1); @@ -5866,7 +5863,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else if ((insn & (1 << 10)) == 0) { /* VTBL, VTBX. */ - n = ((insn >> 5) & 0x18) + 8; + int n = ((insn >> 5) & 0x18) + 8; if (insn & (1 << 6)) { tmp = neon_load_reg(rd, 0); } else { From cc13115bdecb4596fd4201f16455220a7d1a85f8 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:14 +0100 Subject: [PATCH 166/386] target-arm: Handle UNDEF cases for Neon "2 regs and shift" insns Correctly handle all the UNDEF cases for Neon instructions of the "2 registers and shift" form, and make sure that we check for these cases early enough not to leak TCG temporaries. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 0cf933d021..c0ffa9fca8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4744,7 +4744,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Two registers and shift. */ op = (insn >> 8) & 0xf; if (insn & (1 << 7)) { - /* 64-bit shift. */ + /* 64-bit shift. */ + if (op > 7) { + return 1; + } size = 3; } else { size = 2; @@ -4757,6 +4760,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (op < 8) { /* Shift by immediate: VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ + if (q && ((rd | rm) & 1)) { + return 1; + } + if (!u && (op == 4 || op == 6)) { + return 1; + } /* Right shifts are encoded as N - shift, where N is the element size in bits. */ if (op <= 4) @@ -4804,20 +4813,13 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); break; case 4: /* VSRI */ - if (!u) - return 1; gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); break; case 5: /* VSHL, VSLI */ gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); break; case 6: /* VQSHLU */ - if (u) { - gen_helper_neon_qshlu_s64(cpu_V0, - cpu_V0, cpu_V1); - } else { - return 1; - } + gen_helper_neon_qshlu_s64(cpu_V0, cpu_V0, cpu_V1); break; case 7: /* VQSHL */ if (u) { @@ -4865,8 +4867,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(rshl); break; case 4: /* VSRI */ - if (!u) - return 1; GEN_NEON_INTEGER_OP(shl); break; case 5: /* VSHL, VSLI */ @@ -4874,13 +4874,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } break; case 6: /* VQSHLU */ - if (!u) { - return 1; - } switch (size) { case 0: gen_helper_neon_qshlu_s8(tmp, tmp, tmp2); @@ -4892,7 +4889,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_qshlu_s32(tmp, tmp, tmp2); break; default: - return 1; + abort(); } break; case 7: /* VQSHL */ @@ -4950,7 +4947,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Shift by immediate and narrow: VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ int input_unsigned = (op == 8) ? !u : u; - + if (rm & 1) { + return 1; + } shift = shift - (1 << (size + 3)); size++; if (size == 3) { @@ -5018,9 +5017,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp2); } } else if (op == 10) { - /* VSHLL */ - if (q || size == 3) + /* VSHLL, VMOVL */ + if (q || (rd & 1)) { return 1; + } tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { @@ -5061,6 +5061,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else if (op >= 14) { /* VCVT fixed-point. */ + if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) { + return 1; + } /* We have already masked out the must-be-1 top bit of imm6, * hence this 32-shift where the ARM ARM has 64-imm6. */ From 2bc70834e867e7a0c4f30d374405acf8d81bba03 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:15 +0100 Subject: [PATCH 167/386] target-arm: Collapse VSRI case into VSHL, VSLI Collapse some switch cases for VSRI into those for VSHL, VSLI, since the bodies are the same. (This is not completely obvious for the size < 3 case, but since for VSRI we know U=1 the GEN_NEON_INTEGER_OP() expansion is equivalent to the open-coded VSHL/VSLI case.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index c0ffa9fca8..a86c54c564 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4813,8 +4813,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1); break; case 4: /* VSRI */ - gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); - break; case 5: /* VSHL, VSLI */ gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1); break; @@ -4867,8 +4865,6 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) GEN_NEON_INTEGER_OP(rshl); break; case 4: /* VSRI */ - GEN_NEON_INTEGER_OP(shl); - break; case 5: /* VSHL, VSLI */ switch (size) { case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break; From 7d80fee5b9e663148ddee714e3b755a0af20508d Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:16 +0100 Subject: [PATCH 168/386] target-arm: Handle UNDEF cases for Neon invalid modified-immediates For Neon "one register and a modified immediate value" forms, the combination op=1 cmode=1111 is unallocated and should UNDEF. All instructions of this form also UNDEF if Q == 1 and Vd<0> == 1. We also add a comment on the only UNPREDICTABLE in this space. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index a86c54c564..0a9b3cf354 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5084,11 +5084,18 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else { /* (insn & 0x00380080) == 0 */ int invert; + if (q && (rd & 1)) { + return 1; + } op = (insn >> 8) & 0xf; /* One register and immediate. */ imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); invert = (insn & (1 << 5)) != 0; + /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. + * We choose to not special-case this and will behave as if a + * valid constant encoding of 0 had been given. + */ switch (op) { case 0: case 1: /* no-op */ @@ -5120,6 +5127,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) imm = ~imm; break; case 15: + if (invert) { + return 1; + } imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); break; From 695272dcb976897639c034b8fe3d32699ada6482 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:17 +0100 Subject: [PATCH 169/386] target-arm: Handle UNDEF cases for Neon 3-regs-different-widths Add missing UNDEF checks for instructions in the Neon "3 registers of different widths" data processing space. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 56 +++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 0a9b3cf354..9ff5af0475 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5174,31 +5174,47 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) int src1_wide; int src2_wide; int prewiden; - /* prewiden, src1_wide, src2_wide */ - static const int neon_3reg_wide[16][3] = { - {1, 0, 0}, /* VADDL */ - {1, 1, 0}, /* VADDW */ - {1, 0, 0}, /* VSUBL */ - {1, 1, 0}, /* VSUBW */ - {0, 1, 1}, /* VADDHN */ - {0, 0, 0}, /* VABAL */ - {0, 1, 1}, /* VSUBHN */ - {0, 0, 0}, /* VABDL */ - {0, 0, 0}, /* VMLAL */ - {0, 0, 0}, /* VQDMLAL */ - {0, 0, 0}, /* VMLSL */ - {0, 0, 0}, /* VQDMLSL */ - {0, 0, 0}, /* Integer VMULL */ - {0, 0, 0}, /* VQDMULL */ - {0, 0, 0} /* Polynomial VMULL */ + /* undefreq: bit 0 : UNDEF if size != 0 + * bit 1 : UNDEF if size == 0 + * bit 2 : UNDEF if U == 1 + * Note that [1:0] set implies 'always UNDEF' + */ + int undefreq; + /* prewiden, src1_wide, src2_wide, undefreq */ + static const int neon_3reg_wide[16][4] = { + {1, 0, 0, 0}, /* VADDL */ + {1, 1, 0, 0}, /* VADDW */ + {1, 0, 0, 0}, /* VSUBL */ + {1, 1, 0, 0}, /* VSUBW */ + {0, 1, 1, 0}, /* VADDHN */ + {0, 0, 0, 0}, /* VABAL */ + {0, 1, 1, 0}, /* VSUBHN */ + {0, 0, 0, 0}, /* VABDL */ + {0, 0, 0, 0}, /* VMLAL */ + {0, 0, 0, 6}, /* VQDMLAL */ + {0, 0, 0, 0}, /* VMLSL */ + {0, 0, 0, 6}, /* VQDMLSL */ + {0, 0, 0, 0}, /* Integer VMULL */ + {0, 0, 0, 2}, /* VQDMULL */ + {0, 0, 0, 5}, /* Polynomial VMULL */ + {0, 0, 0, 3}, /* Reserved: always UNDEF */ }; prewiden = neon_3reg_wide[op][0]; src1_wide = neon_3reg_wide[op][1]; src2_wide = neon_3reg_wide[op][2]; + undefreq = neon_3reg_wide[op][3]; - if (size == 0 && (op == 9 || op == 11 || op == 13)) + if (((undefreq & 1) && (size != 0)) || + ((undefreq & 2) && (size == 0)) || + ((undefreq & 4) && u)) { return 1; + } + if ((src1_wide && (rn & 1)) || + (src2_wide && (rm & 1)) || + (!src2_wide && (rd & 1))) { + return 1; + } /* Avoid overlapping operands. Wide source operands are always aligned so will never overlap with wide @@ -5279,8 +5295,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp); break; - default: /* 15 is RESERVED. */ - return 1; + default: /* 15 is RESERVED: caught earlier */ + abort(); } if (op == 13) { /* VQDMULL */ From 3e3326dfb003df0f2f9209c78c25b965aa6022f1 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:18 +0100 Subject: [PATCH 170/386] target-arm: Handle UNDEF cases for Neon 2 regs + scalar forms Add missing checks for cases which must UNDEF in the Neon "2 registers and a scalar" data processing instruction space. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 9ff5af0475..15c2015d90 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5368,16 +5368,29 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } } else { - /* Two registers and a scalar. */ + /* Two registers and a scalar. NB that for ops of this form + * the ARM ARM labels bit 24 as Q, but it is in our variable + * 'u', not 'q'. + */ + if (size == 0) { + return 1; + } switch (op) { - case 0: /* Integer VMLA scalar */ case 1: /* Float VMLA scalar */ - case 4: /* Integer VMLS scalar */ case 5: /* Floating point VMLS scalar */ - case 8: /* Integer VMUL scalar */ case 9: /* Floating point VMUL scalar */ + if (size == 1) { + return 1; + } + /* fall through */ + case 0: /* Integer VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 8: /* Integer VMUL scalar */ case 12: /* VQDMULH scalar */ case 13: /* VQRDMULH scalar */ + if (u && ((rd | rn) & 1)) { + return 1; + } tmp = neon_get_scalar(size, rm); neon_store_scratch(0, tmp); for (pass = 0; pass < (u ? 4 : 2); pass++) { @@ -5402,7 +5415,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break; case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } } tcg_temp_free_i32(tmp2); @@ -5430,15 +5443,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg(rd, pass, tmp); } break; - case 2: /* VMLAL sclar */ case 3: /* VQDMLAL scalar */ - case 6: /* VMLSL scalar */ case 7: /* VQDMLSL scalar */ - case 10: /* VMULL scalar */ case 11: /* VQDMULL scalar */ - if (size == 0 && (op == 3 || op == 7 || op == 11)) + if (u == 1) { return 1; - + } + /* fall through */ + case 2: /* VMLAL sclar */ + case 6: /* VMLSL scalar */ + case 10: /* VMULL scalar */ + if (rd & 1) { + return 1; + } tmp2 = neon_get_scalar(size, rm); /* We need a copy of tmp2 because gen_neon_mull * deletes it during pass 0. */ From 52579ea1c201ce10a5fe6f5734373543e462e345 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:19 +0100 Subject: [PATCH 171/386] target-arm: Handle UNDEF cases for VEXT VEXT must UNDEF if Q == 1 && (Vd<0> == 1 || Vr<0> == 1 || Vm<0> == 1) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index 15c2015d90..f47e5ea487 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5514,6 +5514,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (imm > 7 && !q) return 1; + if (q && ((rd | rn | rm) & 1)) { + return 1; + } + if (imm == 0) { neon_load_reg64(cpu_V0, rn); if (q) { From 600b828c448f108b89e1f864f0420a49ccb70d43 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:20 +0100 Subject: [PATCH 172/386] target-arm: Simplify checking of size field in Neon 2reg-misc forms Many of the Neon "2 register misc" instruction forms require invalid size fields to cause the instruction to UNDEF. Pull this information out into an array; this simplifies the code and also means we can do the check early and avoid the problem of leaking TCG temporaries in the illegal_op case. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 255 +++++++++++++++++++++++++++++------------ 1 file changed, 179 insertions(+), 76 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index f47e5ea487..472824889d 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3662,7 +3662,7 @@ static inline TCGv neon_get_scalar(int size, int reg) static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv tmp, tmp2; - if (size == 3 || (!q && size == 2)) { + if (!q && size == 2) { return 1; } tmp = tcg_const_i32(rd); @@ -3701,7 +3701,7 @@ static int gen_neon_unzip(int rd, int rm, int size, int q) static int gen_neon_zip(int rd, int rm, int size, int q) { TCGv tmp, tmp2; - if (size == 3 || (!q && size == 2)) { + if (!q && size == 2) { return 1; } tmp = tcg_const_i32(rd); @@ -4312,6 +4312,113 @@ static const uint8_t neon_3r_sizes[] = { [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */ }; +/* Symbolic constants for op fields for Neon 2-register miscellaneous. + * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B + * table A7-13. + */ +#define NEON_2RM_VREV64 0 +#define NEON_2RM_VREV32 1 +#define NEON_2RM_VREV16 2 +#define NEON_2RM_VPADDL 4 +#define NEON_2RM_VPADDL_U 5 +#define NEON_2RM_VCLS 8 +#define NEON_2RM_VCLZ 9 +#define NEON_2RM_VCNT 10 +#define NEON_2RM_VMVN 11 +#define NEON_2RM_VPADAL 12 +#define NEON_2RM_VPADAL_U 13 +#define NEON_2RM_VQABS 14 +#define NEON_2RM_VQNEG 15 +#define NEON_2RM_VCGT0 16 +#define NEON_2RM_VCGE0 17 +#define NEON_2RM_VCEQ0 18 +#define NEON_2RM_VCLE0 19 +#define NEON_2RM_VCLT0 20 +#define NEON_2RM_VABS 22 +#define NEON_2RM_VNEG 23 +#define NEON_2RM_VCGT0_F 24 +#define NEON_2RM_VCGE0_F 25 +#define NEON_2RM_VCEQ0_F 26 +#define NEON_2RM_VCLE0_F 27 +#define NEON_2RM_VCLT0_F 28 +#define NEON_2RM_VABS_F 30 +#define NEON_2RM_VNEG_F 31 +#define NEON_2RM_VSWP 32 +#define NEON_2RM_VTRN 33 +#define NEON_2RM_VUZP 34 +#define NEON_2RM_VZIP 35 +#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */ +#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */ +#define NEON_2RM_VSHLL 38 +#define NEON_2RM_VCVT_F16_F32 44 +#define NEON_2RM_VCVT_F32_F16 46 +#define NEON_2RM_VRECPE 56 +#define NEON_2RM_VRSQRTE 57 +#define NEON_2RM_VRECPE_F 58 +#define NEON_2RM_VRSQRTE_F 59 +#define NEON_2RM_VCVT_FS 60 +#define NEON_2RM_VCVT_FU 61 +#define NEON_2RM_VCVT_SF 62 +#define NEON_2RM_VCVT_UF 63 + +static int neon_2rm_is_float_op(int op) +{ + /* Return true if this neon 2reg-misc op is float-to-float */ + return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F || + op >= NEON_2RM_VRECPE_F); +} + +/* Each entry in this array has bit n set if the insn allows + * size value n (otherwise it will UNDEF). Since unallocated + * op values will have no bits set they always UNDEF. + */ +static const uint8_t neon_2rm_sizes[] = { + [NEON_2RM_VREV64] = 0x7, + [NEON_2RM_VREV32] = 0x3, + [NEON_2RM_VREV16] = 0x1, + [NEON_2RM_VPADDL] = 0x7, + [NEON_2RM_VPADDL_U] = 0x7, + [NEON_2RM_VCLS] = 0x7, + [NEON_2RM_VCLZ] = 0x7, + [NEON_2RM_VCNT] = 0x1, + [NEON_2RM_VMVN] = 0x1, + [NEON_2RM_VPADAL] = 0x7, + [NEON_2RM_VPADAL_U] = 0x7, + [NEON_2RM_VQABS] = 0x7, + [NEON_2RM_VQNEG] = 0x7, + [NEON_2RM_VCGT0] = 0x7, + [NEON_2RM_VCGE0] = 0x7, + [NEON_2RM_VCEQ0] = 0x7, + [NEON_2RM_VCLE0] = 0x7, + [NEON_2RM_VCLT0] = 0x7, + [NEON_2RM_VABS] = 0x7, + [NEON_2RM_VNEG] = 0x7, + [NEON_2RM_VCGT0_F] = 0x4, + [NEON_2RM_VCGE0_F] = 0x4, + [NEON_2RM_VCEQ0_F] = 0x4, + [NEON_2RM_VCLE0_F] = 0x4, + [NEON_2RM_VCLT0_F] = 0x4, + [NEON_2RM_VABS_F] = 0x4, + [NEON_2RM_VNEG_F] = 0x4, + [NEON_2RM_VSWP] = 0x1, + [NEON_2RM_VTRN] = 0x7, + [NEON_2RM_VUZP] = 0x7, + [NEON_2RM_VZIP] = 0x7, + [NEON_2RM_VMOVN] = 0x7, + [NEON_2RM_VQMOVN] = 0x7, + [NEON_2RM_VSHLL] = 0x7, + [NEON_2RM_VCVT_F16_F32] = 0x2, + [NEON_2RM_VCVT_F32_F16] = 0x2, + [NEON_2RM_VRECPE] = 0x4, + [NEON_2RM_VRSQRTE] = 0x4, + [NEON_2RM_VRECPE_F] = 0x4, + [NEON_2RM_VRSQRTE_F] = 0x4, + [NEON_2RM_VCVT_FS] = 0x4, + [NEON_2RM_VCVT_FU] = 0x4, + [NEON_2RM_VCVT_SF] = 0x4, + [NEON_2RM_VCVT_UF] = 0x4, +}; + /* Translate a NEON data processing instruction. Return nonzero if the instruction is invalid. We process data in a mixture of 32-bit and 64-bit chunks. @@ -5566,10 +5673,12 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Two register misc. */ op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); size = (insn >> 18) & 3; + /* UNDEF for unknown op values and bad op-size combinations */ + if ((neon_2rm_sizes[op] & (1 << size)) == 0) { + return 1; + } switch (op) { - case 0: /* VREV64 */ - if (size == 3) - return 1; + case NEON_2RM_VREV64: for (pass = 0; pass < (q ? 2 : 1); pass++) { tmp = neon_load_reg(rm, pass * 2); tmp2 = neon_load_reg(rm, pass * 2 + 1); @@ -5592,10 +5701,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 4: case 5: /* VPADDL */ - case 12: case 13: /* VPADAL */ - if (size == 3) - return 1; + case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: + case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: for (pass = 0; pass < q + 1; pass++) { tmp = neon_load_reg(rm, pass * 2); gen_neon_widen(cpu_V0, tmp, size, op & 1); @@ -5607,7 +5714,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 2: tcg_gen_add_i64(CPU_V001); break; default: abort(); } - if (op >= 12) { + if (op >= NEON_2RM_VPADAL) { /* Accumulate. */ neon_load_reg64(cpu_V1, rd + pass); gen_neon_addl(size); @@ -5615,7 +5722,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg64(cpu_V0, rd + pass); } break; - case 33: /* VTRN */ + case NEON_2RM_VTRN: if (size == 2) { int n; for (n = 0; n < (q ? 4 : 2); n += 2) { @@ -5628,24 +5735,24 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) goto elementwise; } break; - case 34: /* VUZP */ + case NEON_2RM_VUZP: if (gen_neon_unzip(rd, rm, size, q)) { return 1; } break; - case 35: /* VZIP */ + case NEON_2RM_VZIP: if (gen_neon_zip(rd, rm, size, q)) { return 1; } break; - case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ - if (size == 3) - return 1; + case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: + /* also VQMOVUN; op field and mnemonics don't line up */ TCGV_UNUSED(tmp2); for (pass = 0; pass < 2; pass++) { neon_load_reg64(cpu_V0, rm + pass); tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == 36, q, size, tmp, cpu_V0); + gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size, + tmp, cpu_V0); if (pass == 0) { tmp2 = tmp; } else { @@ -5654,9 +5761,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } break; - case 38: /* VSHLL */ - if (q || size == 3) + case NEON_2RM_VSHLL: + if (q) { return 1; + } tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); for (pass = 0; pass < 2; pass++) { @@ -5667,7 +5775,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg64(cpu_V0, rd + pass); } break; - case 44: /* VCVT.F16.F32 */ + case NEON_2RM_VCVT_F16_F32: if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) return 1; tmp = tcg_temp_new_i32(); @@ -5689,7 +5797,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) neon_store_reg(rd, 1, tmp2); tcg_temp_free_i32(tmp); break; - case 46: /* VCVT.F32.F16 */ + case NEON_2RM_VCVT_F32_F16: if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) return 1; tmp3 = tcg_temp_new_i32(); @@ -5714,7 +5822,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) default: elementwise: for (pass = 0; pass < (q ? 4 : 2); pass++) { - if (op == 30 || op == 31 || op >= 58) { + if (neon_2rm_is_float_op(op)) { tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); TCGV_UNUSED(tmp); @@ -5722,183 +5830,178 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp = neon_load_reg(rm, pass); } switch (op) { - case 1: /* VREV32 */ + case NEON_2RM_VREV32: switch (size) { case 0: tcg_gen_bswap32_i32(tmp, tmp); break; case 1: gen_swap_half(tmp); break; - default: return 1; + default: abort(); } break; - case 2: /* VREV16 */ - if (size != 0) - return 1; + case NEON_2RM_VREV16: gen_rev16(tmp); break; - case 8: /* CLS */ + case NEON_2RM_VCLS: switch (size) { case 0: gen_helper_neon_cls_s8(tmp, tmp); break; case 1: gen_helper_neon_cls_s16(tmp, tmp); break; case 2: gen_helper_neon_cls_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 9: /* CLZ */ + case NEON_2RM_VCLZ: switch (size) { case 0: gen_helper_neon_clz_u8(tmp, tmp); break; case 1: gen_helper_neon_clz_u16(tmp, tmp); break; case 2: gen_helper_clz(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 10: /* CNT */ - if (size != 0) - return 1; + case NEON_2RM_VCNT: gen_helper_neon_cnt_u8(tmp, tmp); break; - case 11: /* VNOT */ - if (size != 0) - return 1; + case NEON_2RM_VMVN: tcg_gen_not_i32(tmp, tmp); break; - case 14: /* VQABS */ + case NEON_2RM_VQABS: switch (size) { case 0: gen_helper_neon_qabs_s8(tmp, tmp); break; case 1: gen_helper_neon_qabs_s16(tmp, tmp); break; case 2: gen_helper_neon_qabs_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 15: /* VQNEG */ + case NEON_2RM_VQNEG: switch (size) { case 0: gen_helper_neon_qneg_s8(tmp, tmp); break; case 1: gen_helper_neon_qneg_s16(tmp, tmp); break; case 2: gen_helper_neon_qneg_s32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 16: case 19: /* VCGT #0, VCLE #0 */ + case NEON_2RM_VCGT0: case NEON_2RM_VCLE0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); - if (op == 19) + if (op == NEON_2RM_VCLE0) { tcg_gen_not_i32(tmp, tmp); + } break; - case 17: case 20: /* VCGE #0, VCLT #0 */ + case NEON_2RM_VCGE0: case NEON_2RM_VCLT0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); - if (op == 20) + if (op == NEON_2RM_VCLT0) { tcg_gen_not_i32(tmp, tmp); + } break; - case 18: /* VCEQ #0 */ + case NEON_2RM_VCEQ0: tmp2 = tcg_const_i32(0); switch(size) { case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break; case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break; case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break; - default: return 1; + default: abort(); } tcg_temp_free(tmp2); break; - case 22: /* VABS */ + case NEON_2RM_VABS: switch(size) { case 0: gen_helper_neon_abs_s8(tmp, tmp); break; case 1: gen_helper_neon_abs_s16(tmp, tmp); break; case 2: tcg_gen_abs_i32(tmp, tmp); break; - default: return 1; + default: abort(); } break; - case 23: /* VNEG */ - if (size == 3) - return 1; + case NEON_2RM_VNEG: tmp2 = tcg_const_i32(0); gen_neon_rsb(size, tmp, tmp2); tcg_temp_free(tmp2); break; - case 24: /* Float VCGT #0 */ + case NEON_2RM_VCGT0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cgt_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 25: /* Float VCGE #0 */ + case NEON_2RM_VCGE0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cge_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 26: /* Float VCEQ #0 */ + case NEON_2RM_VCEQ0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_ceq_f32(tmp, tmp, tmp2); tcg_temp_free(tmp2); break; - case 27: /* Float VCLE #0 */ + case NEON_2RM_VCLE0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cge_f32(tmp, tmp2, tmp); tcg_temp_free(tmp2); break; - case 28: /* Float VCLT #0 */ + case NEON_2RM_VCLT0_F: tmp2 = tcg_const_i32(0); gen_helper_neon_cgt_f32(tmp, tmp2, tmp); tcg_temp_free(tmp2); break; - case 30: /* Float VABS */ + case NEON_2RM_VABS_F: gen_vfp_abs(0); break; - case 31: /* Float VNEG */ + case NEON_2RM_VNEG_F: gen_vfp_neg(0); break; - case 32: /* VSWP */ + case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); break; - case 33: /* VTRN */ + case NEON_2RM_VTRN: tmp2 = neon_load_reg(rd, pass); switch (size) { case 0: gen_neon_trn_u8(tmp, tmp2); break; case 1: gen_neon_trn_u16(tmp, tmp2); break; - case 2: abort(); - default: return 1; + default: abort(); } neon_store_reg(rm, pass, tmp2); break; - case 56: /* Integer VRECPE */ + case NEON_2RM_VRECPE: gen_helper_recpe_u32(tmp, tmp, cpu_env); break; - case 57: /* Integer VRSQRTE */ + case NEON_2RM_VRSQRTE: gen_helper_rsqrte_u32(tmp, tmp, cpu_env); break; - case 58: /* Float VRECPE */ + case NEON_2RM_VRECPE_F: gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); break; - case 59: /* Float VRSQRTE */ + case NEON_2RM_VRSQRTE_F: gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); break; - case 60: /* VCVT.F32.S32 */ + case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */ gen_vfp_sito(0); break; - case 61: /* VCVT.F32.U32 */ + case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */ gen_vfp_uito(0); break; - case 62: /* VCVT.S32.F32 */ + case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */ gen_vfp_tosiz(0); break; - case 63: /* VCVT.U32.F32 */ + case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */ gen_vfp_touiz(0); break; default: - /* Reserved: 21, 29, 39-56 */ - return 1; + /* Reserved op values were caught by the + * neon_2rm_sizes[] check earlier. + */ + abort(); } - if (op == 30 || op == 31 || op >= 58) { + if (neon_2rm_is_float_op(op)) { tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); } else { From fc2a9b37849d25d21d161c1319581420499ab4b2 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:21 +0100 Subject: [PATCH 173/386] target-arm: Handle UNDEF cases for Neon 2 register misc forms Add missing UNDEF checks for Neon "two register miscellaneous" forms: * all instructions except VMOVN,VQMOVN must UNDEF if Q==1 && (Vd<0> == 1 || Vm<0> == 1) * VMOVN,VQMOVN,VCVT.F16.F32 UNDEF if Q == 1 || Vm<0> == 1 * VSHLL,VCVT.F32.F16 UNDEF if Q == 1 || Vd<0> == 1 (The only other UNDEF case is VZIP,VUZP if Q == 0 && size == 10, which we already handle.) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 472824889d..b647c7bdde 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5677,6 +5677,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if ((neon_2rm_sizes[op] & (1 << size)) == 0) { return 1; } + if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && + q && ((rm | rd) & 1)) { + return 1; + } switch (op) { case NEON_2RM_VREV64: for (pass = 0; pass < (q ? 2 : 1); pass++) { @@ -5747,6 +5751,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: /* also VQMOVUN; op field and mnemonics don't line up */ + if (rm & 1) { + return 1; + } TCGV_UNUSED(tmp2); for (pass = 0; pass < 2; pass++) { neon_load_reg64(cpu_V0, rm + pass); @@ -5762,7 +5769,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } break; case NEON_2RM_VSHLL: - if (q) { + if (q || (rd & 1)) { return 1; } tmp = neon_load_reg(rm, 0); @@ -5776,8 +5783,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } break; case NEON_2RM_VCVT_F16_F32: - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; + if (!arm_feature(env, ARM_FEATURE_VFP_FP16) || + q || (rm & 1)) { + return 1; + } tmp = tcg_temp_new_i32(); tmp2 = tcg_temp_new_i32(); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0)); @@ -5798,8 +5807,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp); break; case NEON_2RM_VCVT_F32_F16: - if (!arm_feature(env, ARM_FEATURE_VFP_FP16)) - return 1; + if (!arm_feature(env, ARM_FEATURE_VFP_FP16) || + q || (rd & 1)) { + return 1; + } tmp3 = tcg_temp_new_i32(); tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); From 56907d776e1133bf4f633e4e542267d23d2c09cf Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:26:22 +0100 Subject: [PATCH 174/386] target-arm: Treat UNPREDICTABLE VTBL, VTBX case as UNDEF Catch the UNPREDICTABLE case for Neon VTBL,VTBX, and UNDEF it rather than allowing the helper function to index off the end of the register file. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index b647c7bdde..be25c8f33a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6023,7 +6023,14 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else if ((insn & (1 << 10)) == 0) { /* VTBL, VTBX. */ - int n = ((insn >> 5) & 0x18) + 8; + int n = ((insn >> 8) & 3) + 1; + if ((rn + n) > 32) { + /* This is UNPREDICTABLE; we choose to UNDEF to avoid the + * helper function running off the end of the register file. + */ + return 1; + } + n <<= 3; if (insn & (1 << 6)) { tmp = neon_load_reg(rd, 0); } else { From 133da6aae1edc0118fbac8cd9ba46dff69ddd5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= <juha.riihimaki@nokia.com> Date: Mon, 11 Apr 2011 16:26:23 +0100 Subject: [PATCH 175/386] target-arm: Handle UNDEF cases for VDUP (scalar) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the UNDEF cases for VDUP(scalar): imm4 == x000 Q == 1 && Vd<0> == 1 Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index be25c8f33a..6190028d08 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6057,6 +6057,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(tmp); } else if ((insn & 0x380) == 0) { /* VDUP */ + if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) { + return 1; + } if (insn & (1 << 19)) { tmp = neon_load_reg(rm, 1); } else { From c29aca44614e12a310dd903dc4fd56b14a6b71c9 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 12 Apr 2011 13:56:40 +0100 Subject: [PATCH 176/386] softfloat: Add setter function for tininess detection mode Add a setter function for the underflow tininess detection mode, in line with the similar functions for other parts of the float status structure. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 7abcbe899e..c7654d4c63 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -211,6 +211,10 @@ typedef struct float_status { void set_float_rounding_mode(int val STATUS_PARAM); void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_float_detect_tininess(int val STATUS_PARAM) +{ + STATUS(float_detect_tininess) = val; +} INLINE void set_flush_to_zero(flag val STATUS_PARAM) { STATUS(flush_to_zero) = val; From 9df38c47d01eb1fd7eb9d60ac70a4170e638b4a2 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 12 Apr 2011 13:56:41 +0100 Subject: [PATCH 177/386] target-arm: Detect tininess before rounding for FP operations The ARM architecture mandates that we detect tininess before rounding, so set the softfloat fp_status up appropriately. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index ce9a9d8fd2..9172fc7279 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -269,6 +269,10 @@ void cpu_reset(CPUARMState *env) set_flush_to_zero(1, &env->vfp.standard_fp_status); set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status); set_default_nan_mode(1, &env->vfp.standard_fp_status); + set_float_detect_tininess(float_tininess_before_rounding, + &env->vfp.fp_status); + set_float_detect_tininess(float_tininess_before_rounding, + &env->vfp.standard_fp_status); tlb_flush(env, 1); } From d54f10bba7635b5ad8b750afd2bb2f0f8eb68b45 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Fri, 17 Dec 2010 15:58:21 +0000 Subject: [PATCH 178/386] docs: Describe zero data clusters in QED specification Zero data clusters are a space-efficient way of storing zeroed regions of the image. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- docs/specs/qed_spec.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/specs/qed_spec.txt b/docs/specs/qed_spec.txt index 1d5fa87e01..7982e058b2 100644 --- a/docs/specs/qed_spec.txt +++ b/docs/specs/qed_spec.txt @@ -89,6 +89,7 @@ L1, L2, and data cluster offsets must be aligned to header.cluster_size. The fo ===Data cluster offsets=== * 0 - unallocated. The data cluster is not yet allocated. +* 1 - zero. The data cluster contents are all zeroes and no cluster is allocated. Future format extensions may wish to store per-offset information. The least significant 12 bits of an offset are reserved for this purpose and must be set to zero. Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed. @@ -97,6 +98,13 @@ Reads to an unallocated area of the image file access the backing file. If ther Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated. The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written. +===Zero data clusters=== +Zero data clusters are a space-efficient way of storing zeroed regions of the image. + +Reads to a zero data cluster produce zeroes. Note that the difference between an unallocated and a zero data cluster is that zero data clusters stop the reading of contents from the backing file. + +Writes to a zero data cluster cause a new data cluster to be allocated. The new data cluster is populated with zeroes and the data being written. + ===Logical offset translation=== Logical offsets are translated into cluster offsets as follows: From 21df65b6444858ddee3a86d8666571bb41695614 Mon Sep 17 00:00:00 2001 From: Anthony Liguori <aliguori@us.ibm.com> Date: Fri, 17 Dec 2010 15:58:22 +0000 Subject: [PATCH 179/386] qed: Add support for zero clusters Zero clusters are similar to unallocated clusters except instead of reading their value from a backing file when one is available, the cluster is always read as zero. This implements read support only. At this stage, QED will never write a zero cluster. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/qed-check.c | 5 +++-- block/qed-cluster.c | 31 +++++++++++++++++++++---------- block/qed.c | 21 ++++++++++++++++----- block/qed.h | 26 ++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/block/qed-check.c b/block/qed-check.c index 4600932bf2..ea4ebc8e20 100644 --- a/block/qed-check.c +++ b/block/qed-check.c @@ -72,7 +72,8 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table) for (i = 0; i < s->table_nelems; i++) { uint64_t offset = table->offsets[i]; - if (!offset) { + if (qed_offset_is_unalloc_cluster(offset) || + qed_offset_is_zero_cluster(offset)) { continue; } @@ -111,7 +112,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table) unsigned int num_invalid_l2; uint64_t offset = table->offsets[i]; - if (!offset) { + if (qed_offset_is_unalloc_cluster(offset)) { continue; } diff --git a/block/qed-cluster.c b/block/qed-cluster.c index 0ec864b14c..3e19ad1766 100644 --- a/block/qed-cluster.c +++ b/block/qed-cluster.c @@ -23,7 +23,8 @@ * @n: Maximum number of clusters * @offset: Set to first cluster offset * - * This function scans tables for contiguous allocated or free clusters. + * This function scans tables for contiguous clusters. A contiguous run of + * clusters may be allocated, unallocated, or zero. */ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s, QEDTable *table, @@ -38,9 +39,14 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s, *offset = last; for (i = index + 1; i < end; i++) { - if (last == 0) { - /* Counting free clusters */ - if (table->offsets[i] != 0) { + if (qed_offset_is_unalloc_cluster(last)) { + /* Counting unallocated clusters */ + if (!qed_offset_is_unalloc_cluster(table->offsets[i])) { + break; + } + } else if (qed_offset_is_zero_cluster(last)) { + /* Counting zero clusters */ + if (!qed_offset_is_zero_cluster(table->offsets[i])) { break; } } else { @@ -87,14 +93,19 @@ static void qed_find_cluster_cb(void *opaque, int ret) n = qed_count_contiguous_clusters(s, request->l2_table->table, index, n, &offset); - ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2; - len = MIN(find_cluster_cb->len, n * s->header.cluster_size - - qed_offset_into_cluster(s, find_cluster_cb->pos)); - - if (offset && !qed_check_cluster_offset(s, offset)) { + if (qed_offset_is_unalloc_cluster(offset)) { + ret = QED_CLUSTER_L2; + } else if (qed_offset_is_zero_cluster(offset)) { + ret = QED_CLUSTER_ZERO; + } else if (qed_check_cluster_offset(s, offset)) { + ret = QED_CLUSTER_FOUND; + } else { ret = -EINVAL; } + len = MIN(find_cluster_cb->len, n * s->header.cluster_size - + qed_offset_into_cluster(s, find_cluster_cb->pos)); + out: find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len); qemu_free(find_cluster_cb); @@ -132,7 +143,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos, len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos); l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)]; - if (!l2_offset) { + if (qed_offset_is_unalloc_cluster(l2_offset)) { cb(opaque, QED_CLUSTER_L1, 0, len); return; } diff --git a/block/qed.c b/block/qed.c index 75ae2440ee..c8c5930448 100644 --- a/block/qed.c +++ b/block/qed.c @@ -573,7 +573,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l { QEDIsAllocatedCB *cb = opaque; *cb->pnum = len / BDRV_SECTOR_SIZE; - cb->is_allocated = ret == QED_CLUSTER_FOUND; + cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO); } static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num, @@ -745,7 +745,10 @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, * @table: L2 table * @index: First cluster index * @n: Number of contiguous clusters - * @cluster: First cluster byte offset in image file + * @cluster: First cluster offset + * + * The cluster offset may be an allocated byte offset in the image file, the + * zero cluster marker, or the unallocated cluster marker. */ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index, unsigned int n, uint64_t cluster) @@ -753,7 +756,10 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index, int i; for (i = index; i < index + n; i++) { table->offsets[i] = cluster; - cluster += s->header.cluster_size; + if (!qed_offset_is_unalloc_cluster(cluster) && + !qed_offset_is_zero_cluster(cluster)) { + cluster += s->header.cluster_size; + } } } @@ -1075,6 +1081,7 @@ static void qed_aio_write_data(void *opaque, int ret, case QED_CLUSTER_L2: case QED_CLUSTER_L1: + case QED_CLUSTER_ZERO: qed_aio_write_alloc(acb, len); break; @@ -1114,8 +1121,12 @@ static void qed_aio_read_data(void *opaque, int ret, qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len); - /* Handle backing file and unallocated sparse hole reads */ - if (ret != QED_CLUSTER_FOUND) { + /* Handle zero cluster and backing file reads */ + if (ret == QED_CLUSTER_ZERO) { + qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size); + qed_aio_next_io(acb, 0); + return; + } else if (ret != QED_CLUSTER_FOUND) { qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov, qed_aio_next_io, acb); return; diff --git a/block/qed.h b/block/qed.h index 2925e37b1c..3e1ab84781 100644 --- a/block/qed.h +++ b/block/qed.h @@ -161,6 +161,7 @@ typedef struct { enum { QED_CLUSTER_FOUND, /* cluster found */ + QED_CLUSTER_ZERO, /* zero cluster found */ QED_CLUSTER_L2, /* cluster missing in L2 */ QED_CLUSTER_L1, /* cluster missing in L1 */ }; @@ -298,4 +299,29 @@ static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset) qed_check_cluster_offset(s, end_offset); } +static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s, + uint64_t offset) +{ + if (qed_offset_into_cluster(s, offset)) { + return false; + } + return true; +} + +static inline bool qed_offset_is_unalloc_cluster(uint64_t offset) +{ + if (offset == 0) { + return true; + } + return false; +} + +static inline bool qed_offset_is_zero_cluster(uint64_t offset) +{ + if (offset == 1) { + return true; + } + return false; +} + #endif /* BLOCK_QED_H */ From 8aa71917f7be78151cff50b850a25f26de614b13 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Sat, 9 Apr 2011 15:54:38 +0530 Subject: [PATCH 180/386] atapi: Drives can be locked without media present Drivers are free to lock drives without any media present. Such a condition should not result in an error condition. See Table 341 in MMC-5 spec for details. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index c11d457b7a..a290142c57 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1230,13 +1230,8 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - if (bdrv_is_inserted(s->bs)) { - bdrv_set_locked(s->bs, packet[4] & 1); - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } + bdrv_set_locked(s->bs, packet[4] & 1); + ide_atapi_cmd_ok(s); break; case GPCMD_READ_10: case GPCMD_READ_12: From 88f2bb58ef97ca269b29fe92bb4834f5ddbcde80 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Sat, 9 Apr 2011 15:54:39 +0530 Subject: [PATCH 181/386] atapi: Report correct errors on guest eject request Table 629 of the MMC-5 spec mentions two different error conditions when a CDROM eject is requested: a) while a disc is inserted and b) while a disc is not inserted. Ensure we return the appropriate error for the present condition of the drive and disc status. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index a290142c57..b5de22e86a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1304,7 +1304,7 @@ static void ide_atapi_cmd(IDEState *s) break; case GPCMD_START_STOP_UNIT: { - int start, eject, err = 0; + int start, eject, sense, err = 0; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; @@ -1317,7 +1317,11 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_ok(s); break; case -EBUSY: - ide_atapi_cmd_error(s, SENSE_NOT_READY, + sense = SENSE_NOT_READY; + if (bdrv_is_inserted(s->bs)) { + sense = SENSE_ILLEGAL_REQUEST; + } + ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); break; default: From 0c370a35498bf9e300a035864bee7ce8460da669 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Tue, 12 Apr 2011 21:36:03 +0530 Subject: [PATCH 182/386] atapi: Allow GET_EVENT_STATUS_NOTIFICATION after media change After a media change, the only commands allowed from the guest were REQUEST_SENSE and INQUIRY. The guest may also issue GET_EVENT_STATUS_NOTIFICATION commands to get media changed notification. Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index b5de22e86a..f0da95d728 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1102,13 +1102,21 @@ static void ide_atapi_cmd(IDEState *s) printf("\n"); } #endif - /* If there's a UNIT_ATTENTION condition pending, only - REQUEST_SENSE and INQUIRY commands are allowed to complete. */ + /* + * If there's a UNIT_ATTENTION condition pending, only + * REQUEST_SENSE, INQUIRY, GET_CONFIGURATION and + * GET_EVENT_STATUS_NOTIFICATION commands are allowed to complete. + * MMC-5, section 4.1.6.1 lists only these commands being allowed + * to complete, with other commands getting a CHECK condition + * response unless a higher priority status, defined by the drive + * here, is pending. + */ if (s->sense_key == SENSE_UNIT_ATTENTION && - s->io_buffer[0] != GPCMD_REQUEST_SENSE && - s->io_buffer[0] != GPCMD_INQUIRY) { - ide_atapi_cmd_check_status(s); - return; + s->io_buffer[0] != GPCMD_REQUEST_SENSE && + s->io_buffer[0] != GPCMD_INQUIRY && + s->io_buffer[0] != GPCMD_GET_EVENT_STATUS_NOTIFICATION) { + ide_atapi_cmd_check_status(s); + return; } switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: From 493accd624149e9dcf4b89dcbbdbc42621cbc231 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Tue, 12 Apr 2011 21:36:04 +0530 Subject: [PATCH 183/386] atapi: Move GET_EVENT_STATUS_NOTIFICATION command handling to its own function This makes the code more readable. Also, there's a block like: if () { ... } else { ... } Split that into if () { ... return; } ... Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index f0da95d728..4e4ade2bf9 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1084,6 +1084,29 @@ static int ide_dvd_read_structure(IDEState *s, int format, } } +static void handle_get_event_status_notification(IDEState *s, + uint8_t *buf, + const uint8_t *packet) +{ + unsigned int max_len; + + max_len = ube16_to_cpu(packet + 7); + + if (!(packet[1] & 0x01)) { /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + return; + } + + /* polling */ + /* We don't support any event class (yet). */ + cpu_to_ube16(buf, 0x00); /* No event descriptor returned */ + buf[2] = 0x80; /* No Event Available (NEA) */ + buf[3] = 0x00; /* Empty supported event classes */ + ide_atapi_cmd_reply(s, 4, max_len); +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1529,19 +1552,7 @@ static void ide_atapi_cmd(IDEState *s) break; } case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - max_len = ube16_to_cpu(packet + 7); - - if (packet[1] & 0x01) { /* polling */ - /* We don't support any event class (yet). */ - cpu_to_ube16(buf, 0x00); /* No event descriptor returned */ - buf[2] = 0x80; /* No Event Available (NEA) */ - buf[3] = 0x00; /* Empty supported event classes */ - ide_atapi_cmd_reply(s, 4, max_len); - } else { /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - } + handle_get_event_status_notification(s, buf, packet); break; default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, From 8f8e834d70216372619b79a10392cdf208bbd3d0 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Tue, 12 Apr 2011 21:36:05 +0530 Subject: [PATCH 184/386] atapi: GESN: Use structs for commonly-used field types Instead of using magic numbers, use structs that are more descriptive of the fields being used. Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 4e4ade2bf9..f976947cc5 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1088,11 +1088,23 @@ static void handle_get_event_status_notification(IDEState *s, uint8_t *buf, const uint8_t *packet) { + struct { + uint8_t opcode; + uint8_t polled; /* lsb bit is polled; others are reserved */ + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } __attribute__((packed)) *gesn_cdb; + unsigned int max_len; - max_len = ube16_to_cpu(packet + 7); + gesn_cdb = (void *)packet; + max_len = be16_to_cpu(gesn_cdb->len); - if (!(packet[1] & 0x01)) { /* asynchronous mode */ + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */ /* Only polling is supported, asynchronous mode is not. */ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); From 0af63ba3629e6f826846a73636ca391a810b2c6e Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Tue, 12 Apr 2011 21:36:06 +0530 Subject: [PATCH 185/386] atapi: GESN: Standardise event response handling for future additions Handle GET_EVENT_STATUS_NOTIFICATION's No Event Available response in a generic way so that future additions to the code to handle other response types is easier. Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index f976947cc5..a38cc14aaf 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1098,9 +1098,17 @@ static void handle_get_event_status_notification(IDEState *s, uint8_t control; } __attribute__((packed)) *gesn_cdb; - unsigned int max_len; + struct { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } __attribute((packed)) *gesn_event_header; + + unsigned int max_len, used_len; gesn_cdb = (void *)packet; + gesn_event_header = (void *)buf; + max_len = be16_to_cpu(gesn_cdb->len); /* It is fine by the MMC spec to not support async mode operations */ @@ -1111,12 +1119,17 @@ static void handle_get_event_status_notification(IDEState *s, return; } - /* polling */ + /* polling mode operation */ + /* We don't support any event class (yet). */ - cpu_to_ube16(buf, 0x00); /* No event descriptor returned */ - buf[2] = 0x80; /* No Event Available (NEA) */ - buf[3] = 0x00; /* Empty supported event classes */ - ide_atapi_cmd_reply(s, 4, max_len); + gesn_event_header->supported_events = 0; + + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + + gesn_event_header->len = cpu_to_be16(used_len + - sizeof(*gesn_event_header)); + ide_atapi_cmd_reply(s, used_len, max_len); } static void ide_atapi_cmd(IDEState *s) From 996faf1ad4a93342e381766d95686b16624f0dbd Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Tue, 12 Apr 2011 21:36:07 +0530 Subject: [PATCH 186/386] atapi: GESN: implement 'media' subcommand Implement the 'media' sub-command of the GET_EVENT_STATUS_NOTIFICATION command. This helps us report tray open, tray closed, no media, media present states to the guest. Newer Linux kernels (2.6.38+) rely on this command to revalidate discs after media change. This patch also sends out tray open/closed status to the guest driver when requested e.g. via the CDROM_DRIVE_STATUS ioctl (thanks Markus). Without such notification, the guest and qemu's tray open/close status was frequently out of sync, causing installers like Anaconda detecting no disc instead of tray open, confusing them terribly. Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 113 ++++++++++++++++++++++++++++++++++++++++++++-- hw/ide/internal.h | 6 +++ 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index a38cc14aaf..f028ddb495 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1084,6 +1084,48 @@ static int ide_dvd_read_structure(IDEState *s, int format, } } +static unsigned int event_status_media(IDEState *s, + uint8_t *buf) +{ + enum media_event_code { + MEC_NO_CHANGE = 0, /* Status unchanged */ + MEC_EJECT_REQUESTED, /* received a request from user to eject */ + MEC_NEW_MEDIA, /* new media inserted and ready for access */ + MEC_MEDIA_REMOVAL, /* only for media changers */ + MEC_MEDIA_CHANGED, /* only for media changers */ + MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */ + MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */ + }; + enum media_status { + MS_TRAY_OPEN = 1, + MS_MEDIA_PRESENT = 2, + }; + uint8_t event_code, media_status; + + media_status = 0; + if (s->bs->tray_open) { + media_status = MS_TRAY_OPEN; + } else if (bdrv_is_inserted(s->bs)) { + media_status = MS_MEDIA_PRESENT; + } + + /* Event notification descriptor */ + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN && s->events.new_media) { + event_code = MEC_NEW_MEDIA; + s->events.new_media = false; + } + + buf[4] = event_code; + buf[5] = media_status; + + /* These fields are reserved, just clear them. */ + buf[6] = 0; + buf[7] = 0; + + return 8; /* We wrote to 4 extra bytes from the header */ +} + static void handle_get_event_status_notification(IDEState *s, uint8_t *buf, const uint8_t *packet) @@ -1104,6 +1146,26 @@ static void handle_get_event_status_notification(IDEState *s, uint8_t supported_events; } __attribute((packed)) *gesn_event_header; + enum notification_class_request_type { + NCR_RESERVED1 = 1 << 0, + NCR_OPERATIONAL_CHANGE = 1 << 1, + NCR_POWER_MANAGEMENT = 1 << 2, + NCR_EXTERNAL_REQUEST = 1 << 3, + NCR_MEDIA = 1 << 4, + NCR_MULTI_HOST = 1 << 5, + NCR_DEVICE_BUSY = 1 << 6, + NCR_RESERVED2 = 1 << 7, + }; + enum event_notification_class_field { + ENC_NO_EVENTS = 0, + ENC_OPERATIONAL_CHANGE, + ENC_POWER_MANAGEMENT, + ENC_EXTERNAL_REQUEST, + ENC_MEDIA, + ENC_MULTIPLE_HOSTS, + ENC_DEVICE_BUSY, + ENC_RESERVED, + }; unsigned int max_len, used_len; gesn_cdb = (void *)packet; @@ -1121,12 +1183,32 @@ static void handle_get_event_status_notification(IDEState *s, /* polling mode operation */ - /* We don't support any event class (yet). */ - gesn_event_header->supported_events = 0; + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + */ + gesn_event_header->supported_events = NCR_MEDIA; - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & NCR_MEDIA) { + gesn_event_header->notification_class |= ENC_MEDIA; + used_len = event_status_media(s, buf); + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } gesn_event_header->len = cpu_to_be16(used_len - sizeof(*gesn_event_header)); ide_atapi_cmd_reply(s, used_len, max_len); @@ -1655,6 +1737,7 @@ static void cdrom_change_cb(void *opaque, int reason) s->sense_key = SENSE_UNIT_ATTENTION; s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; s->cdrom_changed = 1; + s->events.new_media = true; ide_set_irq(s->bus); } @@ -2799,6 +2882,25 @@ static bool ide_drive_pio_state_needed(void *opaque) return (s->status & DRQ_STAT) != 0; } +static bool ide_atapi_gesn_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->events.new_media || s->events.eject_request; +} + +/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */ +const VMStateDescription vmstate_ide_atapi_gesn_state = { + .name ="ide_drive/atapi/gesn_state", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_BOOL(events.new_media, IDEState), + VMSTATE_BOOL(events.eject_request, IDEState), + } +}; + const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, @@ -2852,6 +2954,9 @@ const VMStateDescription vmstate_ide_drive = { { .vmsd = &vmstate_ide_drive_pio_state, .needed = ide_drive_pio_state_needed, + }, { + .vmsd = &vmstate_ide_atapi_gesn_state, + .needed = ide_atapi_gesn_needed, }, { /* empty */ } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index d533fb63b3..ba7e9a8ee2 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -373,6 +373,11 @@ typedef int DMAFunc(IDEDMA *); typedef int DMAIntFunc(IDEDMA *, int); typedef void DMARestartFunc(void *, int, int); +struct unreported_events { + bool eject_request; + bool new_media; +}; + /* NOTE: IDEState represents in fact one drive */ struct IDEState { IDEBus *bus; @@ -408,6 +413,7 @@ struct IDEState { BlockDriverState *bs; char version[9]; /* ATAPI specific */ + struct unreported_events events; uint8_t sense_key; uint8_t asc; uint8_t cdrom_changed; From 2d56a546a73ca3f588196f4065621ff5f11f50e4 Mon Sep 17 00:00:00 2001 From: Mitnick Lyu <mitnick.lyu@gmail.com> Date: Wed, 13 Apr 2011 17:30:54 +0800 Subject: [PATCH 187/386] vpc.c: Use get_option_parameter() does the search Use get_option_parameter() to instead of duplicating the loop, and use BDRV_SECTOR_SIZE to instead of 512 Signed-off-by: Mitnick Lyu <mitnick.lyu@gmail.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/vpc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 7b025be01d..56865da5bc 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -505,12 +505,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options) int ret = -EIO; // Read out options - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_sectors = options->value.n / 512; - } - options++; - } + total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n / + BDRV_SECTOR_SIZE; // Create the file fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); From 7f7454ec296b3403b4accec55349a8f0232d3576 Mon Sep 17 00:00:00 2001 From: Anthony Liguori <aliguori@us.ibm.com> Date: Wed, 13 Apr 2011 07:41:19 -0500 Subject: [PATCH 188/386] lm32: fix build breakage due to uninitialized variable 'r' gcc 4.5.2 correctly complains that r is potentially uninitialized in this function. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> --- hw/milkymist-pfpu.c | 2 +- roms/seabios | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 4831e00b81..94e631510f 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -163,7 +163,7 @@ static int pfpu_decode_insn(MilkymistPFPUState *s) uint32_t reg_b = (insn >> 11) & 0x7f; uint32_t op = (insn >> 7) & 0xf; uint32_t reg_d = insn & 0x7f; - uint32_t r; + uint32_t r = 0; int latency = 0; switch (op) { diff --git a/roms/seabios b/roms/seabios index cc975646af..06d0bdd9e2 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit cc975646af69f279396d4d5e1379ac6af80ee637 +Subproject commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4 From cc9453f457888bdd3ab7b37988adbfc4712fa125 Mon Sep 17 00:00:00 2001 From: Anthony Liguori <aliguori@us.ibm.com> Date: Wed, 13 Apr 2011 08:16:53 -0500 Subject: [PATCH 189/386] Revert SeaBIOS change due to overzealous commit -a Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> --- roms/seabios | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roms/seabios b/roms/seabios index 06d0bdd9e2..cc975646af 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4 +Subproject commit cc975646af69f279396d4d5e1379ac6af80ee637 From 4d9ad7f793605abd9806fc932b3e04e028894565 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 11 Apr 2011 16:32:08 +0100 Subject: [PATCH 190/386] target-arm: Don't overflow when calculating value for signed VABAL In the VABAL instruction we take the absolute difference of two values of size x and store it in a result of size 2x. This means we have to be careful to calculate the absolute difference using a wide enough type that we don't accidentally overflow. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/neon_helper.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index c3ac96a099..7df925ad31 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1514,9 +1514,13 @@ uint64_t HELPER(neon_addl_saturate_s64)(uint64_t a, uint64_t b) return result; } -#define DO_ABD(dest, x, y, type) do { \ - type tmp_x = x; \ - type tmp_y = y; \ +/* We have to do the arithmetic in a larger type than + * the input type, because for example with a signed 32 bit + * op the absolute difference can overflow a signed 32 bit value. + */ +#define DO_ABD(dest, x, y, intype, arithtype) do { \ + arithtype tmp_x = (intype)(x); \ + arithtype tmp_y = (intype)(y); \ dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ } while(0) @@ -1524,12 +1528,12 @@ uint64_t HELPER(neon_abdl_u16)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, uint8_t); - DO_ABD(tmp, a >> 8, b >> 8, uint8_t); + DO_ABD(result, a, b, uint8_t, uint32_t); + DO_ABD(tmp, a >> 8, b >> 8, uint8_t, uint32_t); result |= tmp << 16; - DO_ABD(tmp, a >> 16, b >> 16, uint8_t); + DO_ABD(tmp, a >> 16, b >> 16, uint8_t, uint32_t); result |= tmp << 32; - DO_ABD(tmp, a >> 24, b >> 24, uint8_t); + DO_ABD(tmp, a >> 24, b >> 24, uint8_t, uint32_t); result |= tmp << 48; return result; } @@ -1538,12 +1542,12 @@ uint64_t HELPER(neon_abdl_s16)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, int8_t); - DO_ABD(tmp, a >> 8, b >> 8, int8_t); + DO_ABD(result, a, b, int8_t, int32_t); + DO_ABD(tmp, a >> 8, b >> 8, int8_t, int32_t); result |= tmp << 16; - DO_ABD(tmp, a >> 16, b >> 16, int8_t); + DO_ABD(tmp, a >> 16, b >> 16, int8_t, int32_t); result |= tmp << 32; - DO_ABD(tmp, a >> 24, b >> 24, int8_t); + DO_ABD(tmp, a >> 24, b >> 24, int8_t, int32_t); result |= tmp << 48; return result; } @@ -1552,8 +1556,8 @@ uint64_t HELPER(neon_abdl_u32)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, uint16_t); - DO_ABD(tmp, a >> 16, b >> 16, uint16_t); + DO_ABD(result, a, b, uint16_t, uint32_t); + DO_ABD(tmp, a >> 16, b >> 16, uint16_t, uint32_t); return result | (tmp << 32); } @@ -1561,22 +1565,22 @@ uint64_t HELPER(neon_abdl_s32)(uint32_t a, uint32_t b) { uint64_t tmp; uint64_t result; - DO_ABD(result, a, b, int16_t); - DO_ABD(tmp, a >> 16, b >> 16, int16_t); + DO_ABD(result, a, b, int16_t, int32_t); + DO_ABD(tmp, a >> 16, b >> 16, int16_t, int32_t); return result | (tmp << 32); } uint64_t HELPER(neon_abdl_u64)(uint32_t a, uint32_t b) { uint64_t result; - DO_ABD(result, a, b, uint32_t); + DO_ABD(result, a, b, uint32_t, uint64_t); return result; } uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b) { uint64_t result; - DO_ABD(result, a, b, int32_t); + DO_ABD(result, a, b, int32_t, int64_t); return result; } #undef DO_ABD From 420b6c317de87890e06225de6e2f8af7bf714df0 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Thu, 14 Apr 2011 14:11:56 +0100 Subject: [PATCH 191/386] tests/test-mmap.c: Check mmap() return value before using it Correct the position of a "stop if MAP_FAILED" check in the mmap() tests, so that if mmap() does fail we print a failure message rather than segfaulting inside memcpy(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- tests/test-mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-mmap.c b/tests/test-mmap.c index fcb365f40c..c578e2572a 100644 --- a/tests/test-mmap.c +++ b/tests/test-mmap.c @@ -164,6 +164,7 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void) nlen = pagesize * 8; p3 = mmap(NULL, nlen, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + fail_unless (p3 != MAP_FAILED); /* Check if the mmaped areas collide. */ if (p3 < p2 @@ -174,7 +175,6 @@ void check_aligned_anonymous_unfixed_colliding_mmaps(void) /* Make sure we get pages aligned with the pagesize. The target expects this. */ - fail_unless (p3 != MAP_FAILED); p = (uintptr_t) p3; fail_unless ((p & pagemask) == 0); munmap (p2, pagesize); From 3b2319a30b5ae528787bf3769b1a28a863b53252 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 13 Apr 2011 10:03:43 +0200 Subject: [PATCH 192/386] really fix -icount in the iothread case The correct fix for -icount is to consider the biggest difference between iothread and non-iothread modes. In the traditional model, CPUs run _before_ the iothread calls select (or WaitForMultipleObjects for Win32). In the iothread model, CPUs run while the iothread isn't holding the mutex, i.e. _during_ those same calls. So, the iothread should always block as long as possible to let the CPUs run smoothly---the timeout might as well be infinite---and either the OS or the CPU thread itself will let the iothread know when something happens. At this point, the iothread wakes up and interrupts the CPU. This is exactly the approach that this patch takes: when cpu_exec_all returns in -icount mode, and it is because a vm_clock deadline has been met, it wakes up the iothread to process the timers. This is really the "bulk" of fixing icount. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- cpus.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpus.c b/cpus.c index 41bec7cc56..cbeac7a40e 100644 --- a/cpus.c +++ b/cpus.c @@ -830,6 +830,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { cpu_exec_all(); + if (use_icount && qemu_next_deadline() <= 0) { + qemu_notify_event(); + } qemu_tcg_wait_io_event(); } From ab33fcda9f96b9195dfb3fcf5bd9bb5383caeaea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 13 Apr 2011 10:03:44 +0200 Subject: [PATCH 193/386] enable vm_clock to "warp" in the iothread+icount case The previous patch however is not enough, because if the virtual CPU goes to sleep waiting for a future timer interrupt to wake it up, qemu deadlocks. The timer interrupt never comes because time is driven by icount, but the vCPU doesn't run any insns. You could say that VCPUs should never go to sleep in icount mode if there is a pending vm_clock timer; rather time should just warp to the next vm_clock event with no sleep ever taking place. Even better, you can sleep for some time related to the time left until the next event, to avoid that the warps are too visible externally; for example, you could be sending network packets continously instead of every 100ms. This is what this patch implements. qemu_clock_warp is called: 1) whenever a vm_clock timer is adjusted, to ensure the warp_timer is synchronized; 2) at strategic points in the CPU thread, to make sure the insn counter is synchronized before the CPU starts running. In any case, the warp_timer is disabled while the CPU is running, because the insn counter will then be making progress on its own. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- cpus.c | 8 ++++- qemu-common.h | 1 + qemu-timer.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++- qemu-timer.h | 1 + 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/cpus.c b/cpus.c index cbeac7a40e..6a50199039 100644 --- a/cpus.c +++ b/cpus.c @@ -155,7 +155,7 @@ static bool cpu_thread_is_idle(CPUState *env) return true; } -static bool all_cpu_threads_idle(void) +bool all_cpu_threads_idle(void) { CPUState *env; @@ -739,6 +739,9 @@ static void qemu_tcg_wait_io_event(void) CPUState *env; while (all_cpu_threads_idle()) { + /* Start accounting real time to the virtual clock if the CPUs + are idle. */ + qemu_clock_warp(vm_clock); qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex); } @@ -1073,6 +1076,9 @@ bool cpu_exec_all(void) { int r; + /* Account partial waits to the vm_clock. */ + qemu_clock_warp(vm_clock); + if (next_cpu == NULL) { next_cpu = first_cpu; } diff --git a/qemu-common.h b/qemu-common.h index 82e27c18d3..4f6037bab9 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -298,6 +298,7 @@ void qemu_notify_event(void); void qemu_cpu_kick(void *env); void qemu_cpu_kick_self(void); int qemu_cpu_is_self(void *env); +bool all_cpu_threads_idle(void); /* work queue */ struct qemu_work_item { diff --git a/qemu-timer.c b/qemu-timer.c index 50f1943afd..4959688895 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -153,6 +153,8 @@ void cpu_disable_ticks(void) struct QEMUClock { int type; int enabled; + + QEMUTimer *warp_timer; }; struct QEMUTimer { @@ -386,6 +388,90 @@ void qemu_clock_enable(QEMUClock *clock, int enabled) clock->enabled = enabled; } +static int64_t vm_clock_warp_start; + +static void icount_warp_rt(void *opaque) +{ + if (vm_clock_warp_start == -1) { + return; + } + + if (vm_running) { + int64_t clock = qemu_get_clock_ns(rt_clock); + int64_t warp_delta = clock - vm_clock_warp_start; + if (use_icount == 1) { + qemu_icount_bias += warp_delta; + } else { + /* + * In adaptive mode, do not let the vm_clock run too + * far ahead of real time. + */ + int64_t cur_time = cpu_get_clock(); + int64_t cur_icount = qemu_get_clock_ns(vm_clock); + int64_t delta = cur_time - cur_icount; + qemu_icount_bias += MIN(warp_delta, delta); + } + if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], + qemu_get_clock_ns(vm_clock))) { + qemu_notify_event(); + } + } + vm_clock_warp_start = -1; +} + +void qemu_clock_warp(QEMUClock *clock) +{ + int64_t deadline; + + if (!clock->warp_timer) { + return; + } + + /* + * There are too many global variables to make the "warp" behavior + * applicable to other clocks. But a clock argument removes the + * need for if statements all over the place. + */ + assert(clock == vm_clock); + + /* + * If the CPUs have been sleeping, advance the vm_clock timer now. This + * ensures that the deadline for the timer is computed correctly below. + * This also makes sure that the insn counter is synchronized before the + * CPU starts running, in case the CPU is woken by an event other than + * the earliest vm_clock timer. + */ + icount_warp_rt(NULL); + if (!all_cpu_threads_idle() || !active_timers[clock->type]) { + qemu_del_timer(clock->warp_timer); + return; + } + + vm_clock_warp_start = qemu_get_clock_ns(rt_clock); + deadline = qemu_next_deadline(); + if (deadline > 0) { + /* + * Ensure the vm_clock proceeds even when the virtual CPU goes to + * sleep. Otherwise, the CPU might be waiting for a future timer + * interrupt to wake it up, but the interrupt never comes because + * the vCPU isn't running any insns and thus doesn't advance the + * vm_clock. + * + * An extreme solution for this problem would be to never let VCPUs + * sleep in icount mode if there is a pending vm_clock timer; rather + * time could just advance to the next vm_clock event. Instead, we + * do stop VCPUs and only advance vm_clock after some "real" time, + * (related to the time left until the next event) has passed. This + * rt_clock timer will do this. This avoids that the warps are too + * visible externally---for example, you will not be sending network + * packets continously instead of every 100ms. + */ + qemu_mod_timer(clock->warp_timer, vm_clock_warp_start + deadline); + } else { + qemu_notify_event(); + } +} + QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque) { @@ -454,8 +540,10 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) qemu_rearm_alarm_timer(alarm_timer); } /* Interrupt execution to force deadline recalculation. */ - if (use_icount) + qemu_clock_warp(ts->clock); + if (use_icount) { qemu_notify_event(); + } } } @@ -576,6 +664,10 @@ void configure_icount(const char *option) if (!option) return; +#ifdef CONFIG_IOTHREAD + vm_clock->warp_timer = qemu_new_timer_ns(rt_clock, icount_warp_rt, NULL); +#endif + if (strcmp(option, "auto") != 0) { icount_time_shift = strtol(option, NULL, 0); use_icount = 1; diff --git a/qemu-timer.h b/qemu-timer.h index 75d567578b..c01bcaba66 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -39,6 +39,7 @@ extern QEMUClock *host_clock; int64_t qemu_get_clock_ns(QEMUClock *clock); void qemu_clock_enable(QEMUClock *clock, int enabled); +void qemu_clock_warp(QEMUClock *clock); QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, QEMUTimerCB *cb, void *opaque); From 1ece93a91b8435b815ce7214cf41bbbbe7929e8b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 13 Apr 2011 10:03:45 +0200 Subject: [PATCH 194/386] Revert wrong fixes for -icount in the iothread case This reverts commits 225d02cd and c9f7383c. While some parts of the latter could be saved, I preferred a smooth, complete revert. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- qemu-timer.c | 66 ++++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index 4959688895..7998f37a51 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -110,9 +110,12 @@ static int64_t cpu_get_clock(void) } } +#ifndef CONFIG_IOTHREAD static int64_t qemu_icount_delta(void) { - if (use_icount == 1) { + if (!use_icount) { + return 5000 * (int64_t) 1000000; + } else if (use_icount == 1) { /* When not using an adaptive execution frequency we tend to get badly out of sync with real time, so just delay for a reasonable amount of time. */ @@ -121,6 +124,7 @@ static int64_t qemu_icount_delta(void) return cpu_get_icount() - cpu_get_clock(); } } +#endif /* enable cpu_get_ticks() */ void cpu_enable_ticks(void) @@ -1147,39 +1151,41 @@ void quit_timers(void) int qemu_calculate_timeout(void) { +#ifndef CONFIG_IOTHREAD int timeout; - int64_t add; - int64_t delta; - /* When using icount, making forward progress with qemu_icount when the - guest CPU is idle is critical. We only use the static io-thread timeout - for non icount runs. */ - if (!use_icount || !vm_running) { - return 5000; - } - - /* Advance virtual time to the next event. */ - delta = qemu_icount_delta(); - if (delta > 0) { - /* If virtual time is ahead of real time then just - wait for IO. */ - timeout = (delta + 999999) / 1000000; - } else { - /* Wait for either IO to occur or the next - timer event. */ - add = qemu_next_deadline(); - /* We advance the timer before checking for IO. - Limit the amount we advance so that early IO - activity won't get the guest too far ahead. */ - if (add > 10000000) - add = 10000000; - delta += add; - qemu_icount += qemu_icount_round (add); - timeout = delta / 1000000; - if (timeout < 0) - timeout = 0; + if (!vm_running) + timeout = 5000; + else { + /* XXX: use timeout computed from timers */ + int64_t add; + int64_t delta; + /* Advance virtual time to the next event. */ + delta = qemu_icount_delta(); + if (delta > 0) { + /* If virtual time is ahead of real time then just + wait for IO. */ + timeout = (delta + 999999) / 1000000; + } else { + /* Wait for either IO to occur or the next + timer event. */ + add = qemu_next_deadline(); + /* We advance the timer before checking for IO. + Limit the amount we advance so that early IO + activity won't get the guest too far ahead. */ + if (add > 10000000) + add = 10000000; + delta += add; + qemu_icount += qemu_icount_round (add); + timeout = delta / 1000000; + if (timeout < 0) + timeout = 0; + } } return timeout; +#else /* CONFIG_IOTHREAD */ + return 1000; +#endif } From cb842c90a485d9dbf05fa51e1500b3c1a1931256 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Wed, 13 Apr 2011 10:03:46 +0200 Subject: [PATCH 195/386] qemu_next_deadline should not consider host-time timers It is purely for icount-based virtual timers. And now that we got the code right, rename the function to clarify the intended scope. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- cpus.c | 4 ++-- qemu-timer.c | 13 ++++--------- qemu-timer.h | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/cpus.c b/cpus.c index 6a50199039..1fc34b75c2 100644 --- a/cpus.c +++ b/cpus.c @@ -833,7 +833,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) while (1) { cpu_exec_all(); - if (use_icount && qemu_next_deadline() <= 0) { + if (use_icount && qemu_next_icount_deadline() <= 0) { qemu_notify_event(); } qemu_tcg_wait_io_event(); @@ -1050,7 +1050,7 @@ static int tcg_cpu_exec(CPUState *env) qemu_icount -= (env->icount_decr.u16.low + env->icount_extra); env->icount_decr.u16.low = 0; env->icount_extra = 0; - count = qemu_icount_round (qemu_next_deadline()); + count = qemu_icount_round(qemu_next_icount_deadline()); qemu_icount += count; decr = (count > 0xffff) ? 0xffff : count; count -= decr; diff --git a/qemu-timer.c b/qemu-timer.c index 7998f37a51..b8c0c8870d 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -452,7 +452,7 @@ void qemu_clock_warp(QEMUClock *clock) } vm_clock_warp_start = qemu_get_clock_ns(rt_clock); - deadline = qemu_next_deadline(); + deadline = qemu_next_icount_deadline(); if (deadline > 0) { /* * Ensure the vm_clock proceeds even when the virtual CPU goes to @@ -765,21 +765,16 @@ static void host_alarm_handler(int host_signum) } } -int64_t qemu_next_deadline(void) +int64_t qemu_next_icount_deadline(void) { /* To avoid problems with overflow limit this to 2^32. */ int64_t delta = INT32_MAX; + assert(use_icount); if (active_timers[QEMU_CLOCK_VIRTUAL]) { delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - qemu_get_clock_ns(vm_clock); } - if (active_timers[QEMU_CLOCK_HOST]) { - int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock_ns(host_clock); - if (hdelta < delta) - delta = hdelta; - } if (delta < 0) delta = 0; @@ -1169,7 +1164,7 @@ int qemu_calculate_timeout(void) } else { /* Wait for either IO to occur or the next timer event. */ - add = qemu_next_deadline(); + add = qemu_next_icount_deadline(); /* We advance the timer before checking for IO. Limit the amount we advance so that early IO activity won't get the guest too far ahead. */ diff --git a/qemu-timer.h b/qemu-timer.h index c01bcaba66..3a9228f7df 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -51,7 +51,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); void qemu_run_all_timers(void); int qemu_alarm_pending(void); -int64_t qemu_next_deadline(void); +int64_t qemu_next_icount_deadline(void); void configure_alarms(char const *opt); void configure_icount(const char *option); int qemu_calculate_timeout(void); From 1a00282a739d5cb7247ac3634ddd3e76537ef5eb Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Thu, 14 Apr 2011 19:19:00 +0200 Subject: [PATCH 196/386] sparc: Fix assertion caused by empty memory slot with 0 byte If the memory size given on the command line is equal to the maximum size of memory defined by the hardware, there is no "empty slot" after physical memory. The following command qemu-system-sparc -m 256 raised an assertion: exec.c:2614: cpu_register_physical_memory_offset: Assertion `size' failed This can be fixed either at the caller side (don't call empty_slot_init) or in empty_slot_init (do nothing) when size == 0. The second solution was choosen here because it is more robust. Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- hw/empty_slot.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 664b8d9c4d..da8adc4d03 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -53,18 +53,21 @@ static CPUWriteMemoryFunc * const empty_slot_write[3] = { void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size) { - DeviceState *dev; - SysBusDevice *s; - EmptySlot *e; + if (slot_size > 0) { + /* Only empty slots larger than 0 byte need handling. */ + DeviceState *dev; + SysBusDevice *s; + EmptySlot *e; - dev = qdev_create(NULL, "empty_slot"); - s = sysbus_from_qdev(dev); - e = FROM_SYSBUS(EmptySlot, s); - e->size = slot_size; + dev = qdev_create(NULL, "empty_slot"); + s = sysbus_from_qdev(dev); + e = FROM_SYSBUS(EmptySlot, s); + e->size = slot_size; - qdev_init_nofail(dev); + qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, addr); + sysbus_mmio_map(s, 0, addr); + } } static int empty_slot_init1(SysBusDevice *dev) From 33d05394a6f5e7923bc115faf5122b7f38b0418a Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 09:07:54 +0000 Subject: [PATCH 197/386] json-lexer: fix conflict with mingw32 ERROR definition The name ERROR is too generic, it conflicts with mingw32 ERROR definition. Replace ERROR with IN_ERROR. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- json-lexer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json-lexer.c b/json-lexer.c index c736f42900..65c9720d65 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -28,7 +28,7 @@ */ enum json_lexer_state { - ERROR = 0, + IN_ERROR = 0, IN_DQ_UCODE3, IN_DQ_UCODE2, IN_DQ_UCODE1, @@ -150,7 +150,7 @@ static const uint8_t json_lexer[][256] = { /* Zero */ [IN_ZERO] = { TERMINAL(JSON_INTEGER), - ['0' ... '9'] = ERROR, + ['0' ... '9'] = IN_ERROR, ['.'] = IN_MANTISSA, }, @@ -302,7 +302,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch) lexer->token = qstring_new(); new_state = IN_START; break; - case ERROR: + case IN_ERROR: return -EINVAL; default: break; From a08784dd11794fc60fcc724c7ef2cd1a75a5356d Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 14:12:29 +0000 Subject: [PATCH 198/386] Remove unused sysemu.h include directives Remove unused sysemu.h include directives to speed up build with the following patches. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- acl.c | 1 - arm-semi.c | 1 - balloon.c | 1 - bt-host.c | 1 - bt-vhci.c | 1 - buffered_file.c | 1 - device_tree.c | 1 - hw/an5206.c | 1 - hw/armv7m.c | 1 - hw/axis_dev88.c | 1 - hw/blizzard.c | 1 - hw/bt-hci-csr.c | 1 - hw/cris-boot.c | 1 - hw/dummy_m68k.c | 1 - hw/etraxfs.c | 1 - hw/gumstix.c | 1 - hw/ide/ich.c | 1 - hw/ide/isa.c | 1 - hw/ide/macio.c | 1 - hw/ide/microdrive.c | 1 - hw/ide/mmio.c | 1 - hw/ide/pci.c | 1 - hw/integratorcp.c | 1 - hw/isa-bus.c | 1 - hw/lm32_boards.c | 1 - hw/mainstone.c | 1 - hw/omap_sx1.c | 1 - hw/ppc440_bamboo.c | 1 - hw/ppc4xx_devs.c | 1 - hw/stellaris.c | 1 - hw/syborg.c | 1 - hw/syborg_virtio.c | 1 - hw/sysbus.c | 1 - hw/tc58128.c | 1 - hw/tosa.c | 1 - hw/twl92230.c | 1 - hw/virtio-balloon.c | 1 - hw/virtio.c | 1 - hw/vmport.c | 1 - hw/xen_console.c | 1 - hw/xen_domainbuild.c | 1 - hw/xen_machine_pv.c | 1 - hw/xenfb.c | 1 - hw/xilinx_timer.c | 1 - kvm-stub.c | 1 - migration-exec.c | 1 - migration-fd.c | 1 - migration-tcp.c | 1 - migration-unix.c | 1 - net.c | 1 - net/slirp.c | 1 - net/vde.c | 1 - osdep.c | 1 - qemu-config.c | 1 - qemu-error.c | 1 - qemu-tool.c | 1 - 56 files changed, 56 deletions(-) diff --git a/acl.c b/acl.c index 311dade4e2..82c27043c1 100644 --- a/acl.c +++ b/acl.c @@ -24,7 +24,6 @@ #include "qemu-common.h" -#include "sysemu.h" #include "acl.h" #ifdef CONFIG_FNMATCH diff --git a/arm-semi.c b/arm-semi.c index 1d5179b601..e9e6f8993f 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -33,7 +33,6 @@ #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) #else #include "qemu-common.h" -#include "sysemu.h" #include "gdbstub.h" #endif diff --git a/balloon.c b/balloon.c index 0021fef4b8..248c1b50a9 100644 --- a/balloon.c +++ b/balloon.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ -#include "sysemu.h" #include "monitor.h" #include "qjson.h" #include "qint.h" diff --git a/bt-host.c b/bt-host.c index 6931e7cc62..095254ddc6 100644 --- a/bt-host.c +++ b/bt-host.c @@ -19,7 +19,6 @@ #include "qemu-common.h" #include "qemu-char.h" -#include "sysemu.h" #include "net.h" #include "bt-host.h" diff --git a/bt-vhci.c b/bt-vhci.c index 679c5e05d7..3c5772093e 100644 --- a/bt-vhci.c +++ b/bt-vhci.c @@ -19,7 +19,6 @@ #include "qemu-common.h" #include "qemu-char.h" -#include "sysemu.h" #include "net.h" #include "hw/bt.h" diff --git a/buffered_file.c b/buffered_file.c index b5e2baff46..41b42c3d5a 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -14,7 +14,6 @@ #include "qemu-common.h" #include "hw/hw.h" #include "qemu-timer.h" -#include "sysemu.h" #include "qemu-char.h" #include "buffered_file.h" diff --git a/device_tree.c b/device_tree.c index 21be070759..f5d5eb1bca 100644 --- a/device_tree.c +++ b/device_tree.c @@ -20,7 +20,6 @@ #include "config.h" #include "qemu-common.h" -#include "sysemu.h" #include "device_tree.h" #include "hw/loader.h" diff --git a/hw/an5206.c b/hw/an5206.c index b9f19a9944..42a0163fbd 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -9,7 +9,6 @@ #include "hw.h" #include "pc.h" #include "mcf.h" -#include "sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" diff --git a/hw/armv7m.c b/hw/armv7m.c index 304cd34bc2..72d010a63b 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -9,7 +9,6 @@ #include "sysbus.h" #include "arm-misc.h" -#include "sysemu.h" #include "loader.h" #include "elf.h" diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 57b5e2f041..0e2135afd0 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -26,7 +26,6 @@ #include "net.h" #include "flash.h" #include "boards.h" -#include "sysemu.h" #include "etraxfs.h" #include "loader.h" #include "elf.h" diff --git a/hw/blizzard.c b/hw/blizzard.c index 5f329ad13f..c5245504af 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -19,7 +19,6 @@ */ #include "qemu-common.h" -#include "sysemu.h" #include "console.h" #include "devices.h" #include "vga_int.h" diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 65ffa37fdf..d135ef4790 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -22,7 +22,6 @@ #include "qemu-char.h" #include "qemu-timer.h" #include "irq.h" -#include "sysemu.h" #include "net.h" #include "bt.h" diff --git a/hw/cris-boot.c b/hw/cris-boot.c index 2ef17f606c..37894f8b53 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -23,7 +23,6 @@ */ #include "hw.h" -#include "sysemu.h" #include "loader.h" #include "elf.h" #include "cris-boot.h" diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 61efb39896..cec1cc8e82 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -7,7 +7,6 @@ */ #include "hw.h" -#include "sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" diff --git a/hw/etraxfs.c b/hw/etraxfs.c index 5ee5f979aa..b84d74a11e 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -24,7 +24,6 @@ #include "sysbus.h" #include "boards.h" -#include "sysemu.h" #include "net.h" #include "flash.h" #include "etraxfs.h" diff --git a/hw/gumstix.c b/hw/gumstix.c index ee63f634cc..853f7e1ee8 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -35,7 +35,6 @@ #include "pxa.h" #include "net.h" #include "flash.h" -#include "sysemu.h" #include "devices.h" #include "boards.h" #include "blockdev.h" diff --git a/hw/ide/ich.c b/hw/ide/ich.c index f242d7a81f..a3d475c59a 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -67,7 +67,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8c59c5a47c..4ac745324c 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -27,7 +27,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/macio.c b/hw/ide/macio.c index c1b4caab5b..7107f6b3c2 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -27,7 +27,6 @@ #include <hw/mac_dbdma.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 2ceeb87c0c..9fbbf0e78a 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -27,7 +27,6 @@ #include <hw/pcmcia.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 82b24b673b..10f6f4063c 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -25,7 +25,6 @@ #include <hw/hw.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 35168cb469..65cb56c38c 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -28,7 +28,6 @@ #include <hw/isa.h> #include "block.h" #include "block_int.h" -#include "sysemu.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/integratorcp.c b/hw/integratorcp.c index b049940821..a6c27be82c 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -10,7 +10,6 @@ #include "sysbus.h" #include "primecell.h" #include "devices.h" -#include "sysemu.h" #include "boards.h" #include "arm-misc.h" #include "net.h" diff --git a/hw/isa-bus.c b/hw/isa-bus.c index d07aa410f7..27655436a0 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -17,7 +17,6 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "sysemu.h" #include "monitor.h" #include "sysbus.h" #include "isa.h" diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 85190f0bfa..64629230cf 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -21,7 +21,6 @@ #include "hw.h" #include "net.h" #include "flash.h" -#include "sysemu.h" #include "devices.h" #include "boards.h" #include "loader.h" diff --git a/hw/mainstone.c b/hw/mainstone.c index 50691ca41e..4792f0e3ed 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,7 +14,6 @@ #include "net.h" #include "devices.h" #include "boards.h" -#include "sysemu.h" #include "flash.h" #include "blockdev.h" #include "sysbus.h" diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 06bccbdc4e..a7b687bc41 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -26,7 +26,6 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "sysemu.h" #include "console.h" #include "omap.h" #include "boards.h" diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 645e84fd36..20b862939e 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -17,7 +17,6 @@ #include "hw.h" #include "pci.h" #include "boards.h" -#include "sysemu.h" #include "ppc440.h" #include "kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 5f581fe2c4..7f9ed17138 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -24,7 +24,6 @@ #include "hw.h" #include "ppc.h" #include "ppc4xx.h" -#include "sysemu.h" #include "qemu-log.h" //#define DEBUG_MMIO diff --git a/hw/stellaris.c b/hw/stellaris.c index 0d5292688e..7932c24576 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -14,7 +14,6 @@ #include "qemu-timer.h" #include "i2c.h" #include "net.h" -#include "sysemu.h" #include "boards.h" #define GPIO_A 0 diff --git a/hw/syborg.c b/hw/syborg.c index 758c69a9cd..bc200e48aa 100644 --- a/hw/syborg.c +++ b/hw/syborg.c @@ -25,7 +25,6 @@ #include "sysbus.h" #include "boards.h" #include "arm-misc.h" -#include "sysemu.h" #include "net.h" static struct arm_boot_info syborg_binfo; diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index ee08c49105..2f3e6da4e2 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -26,7 +26,6 @@ #include "sysbus.h" #include "virtio.h" #include "virtio-net.h" -#include "sysemu.h" //#define DEBUG_SYBORG_VIRTIO diff --git a/hw/sysbus.c b/hw/sysbus.c index acad72abe4..2e22be7b25 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -18,7 +18,6 @@ */ #include "sysbus.h" -#include "sysemu.h" #include "monitor.h" static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); diff --git a/hw/tc58128.c b/hw/tc58128.c index 672a01c467..61b99dd4da 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -1,6 +1,5 @@ #include "hw.h" #include "sh.h" -#include "sysemu.h" #include "loader.h" #define CE1 0x0100 diff --git a/hw/tosa.c b/hw/tosa.c index b8b6c4f390..a7967a286e 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -11,7 +11,6 @@ #include "hw.h" #include "pxa.h" #include "arm-misc.h" -#include "sysemu.h" #include "devices.h" #include "sharpsl.h" #include "pcmcia.h" diff --git a/hw/twl92230.c b/hw/twl92230.c index 8e74acc059..a75448f06a 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -22,7 +22,6 @@ #include "hw.h" #include "qemu-timer.h" #include "i2c.h" -#include "sysemu.h" #include "console.h" #define VERBOSE 1 diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 257baf8d4f..70a8710343 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -15,7 +15,6 @@ #include "qemu-common.h" #include "virtio.h" #include "pc.h" -#include "sysemu.h" #include "cpu.h" #include "monitor.h" #include "balloon.h" diff --git a/hw/virtio.c b/hw/virtio.c index 31bd9e32dc..6e8814cb64 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -16,7 +16,6 @@ #include "trace.h" #include "qemu-error.h" #include "virtio.h" -#include "sysemu.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ diff --git a/hw/vmport.c b/hw/vmport.c index 19010e4843..c8aefaabb8 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -24,7 +24,6 @@ #include "hw.h" #include "isa.h" #include "pc.h" -#include "sysemu.h" #include "kvm.h" #include "qdev.h" diff --git a/hw/xen_console.c b/hw/xen_console.c index d2261f4139..c6c8163813 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -33,7 +33,6 @@ #include <xenctrl.h> #include "hw.h" -#include "sysemu.h" #include "qemu-char.h" #include "xen_backend.h" diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index 371c56206d..4093587df1 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,7 +1,6 @@ #include <signal.h> #include "xen_backend.h" #include "xen_domainbuild.h" -#include "sysemu.h" #include "qemu-timer.h" #include "qemu-log.h" diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 77a34bf111..0d7f73ed82 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -24,7 +24,6 @@ #include "hw.h" #include "pc.h" -#include "sysemu.h" #include "boards.h" #include "xen_backend.h" #include "xen_domainbuild.h" diff --git a/hw/xenfb.c b/hw/xenfb.c index da5297b498..1db75fbe49 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -44,7 +44,6 @@ #include <xen/io/protocols.h> #include "hw.h" -#include "sysemu.h" #include "console.h" #include "qemu-char.h" #include "xen_backend.h" diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 30827b03cd..d398c18e9e 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -23,7 +23,6 @@ */ #include "sysbus.h" -#include "sysemu.h" #include "qemu-timer.h" #define D(x) diff --git a/kvm-stub.c b/kvm-stub.c index 30f6ec3956..1c95452140 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -11,7 +11,6 @@ */ #include "qemu-common.h" -#include "sysemu.h" #include "hw/hw.h" #include "exec-all.h" #include "gdbstub.h" diff --git a/migration-exec.c b/migration-exec.c index 14718dd1d1..4b7aad8b6b 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -17,7 +17,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" #include <sys/types.h> diff --git a/migration-fd.c b/migration-fd.c index 6d14505632..66d51c1cc0 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -16,7 +16,6 @@ #include "migration.h" #include "monitor.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" #include "qemu_socket.h" diff --git a/migration-tcp.c b/migration-tcp.c index e8dff9d71a..d3d80c9702 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -15,7 +15,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" diff --git a/migration-unix.c b/migration-unix.c index 8b967f2938..c8625c7f65 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -15,7 +15,6 @@ #include "qemu_socket.h" #include "migration.h" #include "qemu-char.h" -#include "sysemu.h" #include "buffered_file.h" #include "block.h" diff --git a/net.c b/net.c index 8d6a555374..4f777c3dac 100644 --- a/net.c +++ b/net.c @@ -32,7 +32,6 @@ #include "net/vde.h" #include "net/util.h" #include "monitor.h" -#include "sysemu.h" #include "qemu-common.h" #include "qemu_socket.h" #include "hw/qdev.h" diff --git a/net/slirp.c b/net/slirp.c index b41c60a39b..e387a116ad 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -30,7 +30,6 @@ #endif #include "net.h" #include "monitor.h" -#include "sysemu.h" #include "qemu_socket.h" #include "slirp/libslirp.h" diff --git a/net/vde.c b/net/vde.c index 0b46fa6405..ac48ab2f0a 100644 --- a/net/vde.c +++ b/net/vde.c @@ -31,7 +31,6 @@ #include "qemu-char.h" #include "qemu-common.h" #include "qemu-option.h" -#include "sysemu.h" typedef struct VDEState { VLANClientState nc; diff --git a/osdep.c b/osdep.c index 327583baf7..56e6963f15 100644 --- a/osdep.c +++ b/osdep.c @@ -46,7 +46,6 @@ extern int madvise(caddr_t, size_t, int); #include "qemu-common.h" #include "trace.h" -#include "sysemu.h" #include "qemu_socket.h" int qemu_madvise(void *addr, size_t len, int advice) diff --git a/qemu-config.c b/qemu-config.c index 323d3c2c29..14d34194d0 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -2,7 +2,6 @@ #include "qemu-error.h" #include "qemu-option.h" #include "qemu-config.h" -#include "sysemu.h" #include "hw/qdev.h" static QemuOptsList qemu_drive_opts = { diff --git a/qemu-error.c b/qemu-error.c index 5a35e7c1c2..41c191d528 100644 --- a/qemu-error.c +++ b/qemu-error.c @@ -12,7 +12,6 @@ #include <stdio.h> #include "monitor.h" -#include "sysemu.h" /* * Print to current monitor if we have one, else to stderr. diff --git a/qemu-tool.c b/qemu-tool.c index d45840de28..f4a6ad081c 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -15,7 +15,6 @@ #include "monitor.h" #include "qemu-timer.h" #include "qemu-log.h" -#include "sysemu.h" #include <sys/time.h> From d8dfad9c41c3431dbb97ad722a93e6ad1e9e9279 Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 14:31:31 +0000 Subject: [PATCH 199/386] Use qemu-common.h or qemu-timer.h in place of sysemu.h In some cases qemu-common.h or qemu-timer.h can be used in place of sysemu.h. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- hw/pcie.c | 3 +-- hw/usb-hid.c | 2 +- net/dump.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/pcie.c b/hw/pcie.c index 6a113a9327..9de6149043 100644 --- a/hw/pcie.c +++ b/hw/pcie.c @@ -18,8 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "sysemu.h" -#include "range.h" +#include "qemu-common.h" #include "pci_bridge.h" #include "pcie.h" #include "msix.h" diff --git a/hw/usb-hid.c b/hw/usb-hid.c index c25362cc95..89c293c466 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -26,7 +26,7 @@ #include "console.h" #include "usb.h" #include "usb-desc.h" -#include "sysemu.h" +#include "qemu-timer.h" /* HID interface requests */ #define GET_REPORT 0xa101 diff --git a/net/dump.c b/net/dump.c index 83eda0fcc6..0d0cbb2591 100644 --- a/net/dump.c +++ b/net/dump.c @@ -24,9 +24,9 @@ #include "dump.h" #include "qemu-common.h" -#include "sysemu.h" #include "qemu-error.h" #include "qemu-log.h" +#include "qemu-timer.h" typedef struct DumpState { VLANClientState nc; From 082b5557996764fb21ba8cff17aabec7242ed342 Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 09:04:57 +0000 Subject: [PATCH 200/386] Move generic or OS function declarations to qemu-common.h Move generic or OS related function declarations and macro TFR to qemu-common.h. Move win32 include directives to qemu-os-win32.h. While moving, also add #include <winsock2.h> to fix a recent mingw32 build breakage. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- qemu-common.h | 19 +++++++++++++++++++ qemu-os-win32.h | 3 +++ sysemu.h | 21 --------------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/qemu-common.h b/qemu-common.h index 4f6037bab9..f9f705da85 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -12,6 +12,7 @@ #endif #define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1]; +#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) typedef struct QEMUTimer QEMUTimer; typedef struct QEMUFile QEMUFile; @@ -39,6 +40,14 @@ typedef struct Monitor Monitor; #include <sys/time.h> #include <assert.h> +#ifdef _WIN32 +#include "qemu-os-win32.h" +#endif + +#ifdef CONFIG_POSIX +#include "qemu-os-posix.h" +#endif + #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif @@ -339,6 +348,16 @@ void qemu_progress_init(int enabled, float min_skip); void qemu_progress_end(void); void qemu_progress_print(float percent, int max); +#define QEMU_FILE_TYPE_BIOS 0 +#define QEMU_FILE_TYPE_KEYMAP 1 +char *qemu_find_file(int type, const char *name); + +/* OS specific functions */ +void os_setup_early_signal_handling(void); +char *os_find_datadir(const char *argv0); +void os_parse_cmd_args(int index, const char *optarg); +void os_pidfile_error(void); + /* Convert a byte between binary and BCD. */ static inline uint8_t to_bcd(uint8_t val) { diff --git a/qemu-os-win32.h b/qemu-os-win32.h index 1a07e5e264..ed2753d1b7 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -26,6 +26,9 @@ #ifndef QEMU_OS_WIN32_H #define QEMU_OS_WIN32_H +#include <windows.h> +#include <winsock2.h> + /* Polling handling */ /* return TRUE if no sleep should be done afterwards */ diff --git a/sysemu.h b/sysemu.h index bbbd0fd799..f112c227ac 100644 --- a/sysemu.h +++ b/sysemu.h @@ -8,22 +8,9 @@ #include "qemu-timer.h" #include "notify.h" -#ifdef _WIN32 -#include <windows.h> -#include "qemu-os-win32.h" -#endif - -#ifdef CONFIG_POSIX -#include "qemu-os-posix.h" -#endif - /* vl.c */ extern const char *bios_name; -#define QEMU_FILE_TYPE_BIOS 0 -#define QEMU_FILE_TYPE_KEYMAP 1 -char *qemu_find_file(int type, const char *name); - extern int vm_running; extern const char *qemu_name; extern uint8_t qemu_uuid[]; @@ -100,12 +87,6 @@ int qemu_loadvm_state(QEMUFile *f); /* SLIRP */ void do_info_slirp(Monitor *mon); -/* OS specific functions */ -void os_setup_early_signal_handling(void); -char *os_find_datadir(const char *argv0); -void os_parse_cmd_args(int index, const char *optarg); -void os_pidfile_error(void); - typedef enum DisplayType { DT_DEFAULT, @@ -191,8 +172,6 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; -#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) - void do_usb_add(Monitor *mon, const QDict *qdict); void do_usb_del(Monitor *mon, const QDict *qdict); void usb_info(Monitor *mon); From 70c3b5575ee3e0d528aa176c8c5add3e7355c01e Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 15:45:39 +0000 Subject: [PATCH 201/386] Move clock related functions to qemu-timer.h Move declarations for clock related functions from sysemu.h to qemu-timer.h. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- qemu-timer.h | 4 ++++ sysemu.h | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu-timer.h b/qemu-timer.h index 3a9228f7df..bbc3452bc3 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -59,6 +59,10 @@ void init_clocks(void); int init_timer_alarm(void); void quit_timers(void); +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) { diff --git a/sysemu.h b/sysemu.h index f112c227ac..a379024120 100644 --- a/sysemu.h +++ b/sysemu.h @@ -41,10 +41,6 @@ uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_transferred(void); uint64_t ram_bytes_total(void); -int64_t cpu_get_ticks(void); -void cpu_enable_ticks(void); -void cpu_disable_ticks(void); - void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); From 17a4663e2dddbac36126a6fd7048634a4c95fa6e Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 27 Mar 2011 16:05:08 +0000 Subject: [PATCH 202/386] Move CPU related functions to cpus.h Move declarations of CPU related functions to cpus.h. Adjust the only user. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- cpus.h | 4 ++++ savevm.c | 1 + sysemu.h | 4 ---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cpus.h b/cpus.h index e0211260c3..6fdeb0d8f2 100644 --- a/cpus.h +++ b/cpus.h @@ -8,6 +8,10 @@ void resume_all_vcpus(void); void pause_all_vcpus(void); void cpu_stop_current(void); +void cpu_synchronize_all_states(void); +void cpu_synchronize_all_post_reset(void); +void cpu_synchronize_all_post_init(void); + /* vl.c */ extern int smp_cores; extern int smp_threads; diff --git a/savevm.c b/savevm.c index 03fce62975..be44fdb473 100644 --- a/savevm.c +++ b/savevm.c @@ -82,6 +82,7 @@ #include "migration.h" #include "qemu_socket.h" #include "qemu-queue.h" +#include "cpus.h" #define SELF_ANNOUNCE_ROUNDS 5 diff --git a/sysemu.h b/sysemu.h index a379024120..6effd8a122 100644 --- a/sysemu.h +++ b/sysemu.h @@ -64,10 +64,6 @@ int load_vmstate(const char *name); void do_delvm(Monitor *mon, const QDict *qdict); void do_info_snapshots(Monitor *mon); -void cpu_synchronize_all_states(void); -void cpu_synchronize_all_post_reset(void); -void cpu_synchronize_all_post_init(void); - void qemu_announce_self(void); void main_loop_wait(int nonblocking); From adc56dda0c4eed62149d28939b7d7e329ad95ae8 Mon Sep 17 00:00:00 2001 From: Blue Swirl <blauwirbel@gmail.com> Date: Sun, 3 Apr 2011 08:23:19 +0000 Subject: [PATCH 203/386] migration: move some declarations to migration.h Move a few migration related declarations to migration.h. Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- arch_init.h | 2 -- migration.h | 9 +++++++++ sysemu.h | 5 ----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch_init.h b/arch_init.h index c83360c3a6..86ebc149bc 100644 --- a/arch_init.h +++ b/arch_init.h @@ -22,8 +22,6 @@ enum { extern const uint32_t arch_type; void select_soundhw(const char *optarg); -int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque); -int ram_load(QEMUFile *f, void *opaque, int version_id); void do_acpitable_option(const char *optarg); void do_smbios_option(const char *optarg); void cpudef_init(void); diff --git a/migration.h b/migration.h index 21707922ef..050c56c5a4 100644 --- a/migration.h +++ b/migration.h @@ -139,4 +139,13 @@ void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); int get_migration_state(void); +uint64_t ram_bytes_remaining(void); +uint64_t ram_bytes_transferred(void); +uint64_t ram_bytes_total(void); + +int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque); +int ram_load(QEMUFile *f, void *opaque, int version_id); + +extern int incoming_expected; + #endif diff --git a/sysemu.h b/sysemu.h index 6effd8a122..b0296a0d46 100644 --- a/sysemu.h +++ b/sysemu.h @@ -37,10 +37,6 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); void vm_start(void); void vm_stop(int reason); -uint64_t ram_bytes_remaining(void); -uint64_t ram_bytes_transferred(void); -uint64_t ram_bytes_total(void); - void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); @@ -89,7 +85,6 @@ typedef enum DisplayType } DisplayType; extern int autostart; -extern int incoming_expected; extern int bios_size; typedef enum { From 61cc8701f3e019f154c3662f3c9f998629813745 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Wed, 13 Apr 2011 22:45:22 +0200 Subject: [PATCH 204/386] Fix some typos in comments and documentation helpfull -> helpful usefull -> useful cotrol -> control and a grammar fix. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- qemu-options.hx | 4 ++-- savevm.c | 2 +- target-arm/helper.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index ef60730e47..677c550103 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -937,8 +937,8 @@ a lot of bandwidth at the expense of quality. Disable adaptive encodings. Adaptive encodings are enabled by default. An adaptive encoding will try to detect frequently updated screen regions, and send updates in these regions using a lossy encoding (like JPEG). -This can be really helpfull to save bandwidth when playing videos. Disabling -adaptive encodings allow to restore the original static behavior of encodings +This can be really helpful to save bandwidth when playing videos. Disabling +adaptive encodings allows to restore the original static behavior of encodings like Tight. @end table diff --git a/savevm.c b/savevm.c index be44fdb473..f4ff1a1db4 100644 --- a/savevm.c +++ b/savevm.c @@ -1008,7 +1008,7 @@ const VMStateInfo vmstate_info_buffer = { }; /* unused buffers: space that was used for some fields that are - not usefull anymore */ + not useful anymore */ static int get_unused_buffer(QEMUFile *f, void *pv, size_t size) { diff --git a/target-arm/helper.c b/target-arm/helper.c index 9172fc7279..a0ec6439da 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1378,7 +1378,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; - case 1: /* Auxiliary cotrol register. */ + case 1: /* Auxiliary control register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_xscaleauxcr = val; break; From 7a734b8f68b4a72aba90c3abd9a52e341f4c996a Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Wed, 13 Apr 2011 16:42:16 +1000 Subject: [PATCH 205/386] Makefile: Clean up after "make pdf" Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- .gitignore | 3 +++ Makefile | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1d79680626..08013fc57b 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,9 @@ QMP/qmp-commands.txt *.ky *.log *.pdf +*.cps +*.fns +*.kys *.pg *.pyc *.toc diff --git a/Makefile b/Makefile index fa93be5ed7..dc39efdeb4 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,10 @@ distclean: clean rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi rm -f config-all-devices.mak rm -f roms/seabios/config.mak roms/vgabios/config.mak - rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr + rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi + rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys + rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp + rm -f qemu-doc.vr rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr for d in $(TARGET_DIRS) $(QEMULIBS); do \ rm -rf $$d || exit 1 ; \ From 94843f66ab06f45240d2afa7a648c5722da14dfb Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Wed, 13 Apr 2011 19:45:31 +1000 Subject: [PATCH 206/386] usb: trivial spelling fixes Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/usb-msd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 76f5b027b2..947fd3f83c 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -33,7 +33,7 @@ do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0) enum USBMSDMode { USB_MSDM_CBW, /* Command Block. */ - USB_MSDM_DATAOUT, /* Tranfer data to device. */ + USB_MSDM_DATAOUT, /* Transfer data to device. */ USB_MSDM_DATAIN, /* Transfer data from device. */ USB_MSDM_CSW /* Command Status. */ }; @@ -253,7 +253,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, usb_msd_copy_data(s); if (s->usb_len == 0) { /* Set s->packet to NULL before calling usb_packet_complete - because annother request may be issued before + because another request may be issued before usb_packet_complete returns. */ DPRINTF("Packet complete %p\n", p); s->packet = NULL; From 021730f7285923460e81004c9dae74b6a1c8aa0c Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Wed, 13 Apr 2011 19:45:32 +1000 Subject: [PATCH 207/386] usb: initialise data element in Linux USB_DISCONNECT ioctl This isn't used, but leaving it empty causes valgrind noise. Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- usb-linux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/usb-linux.c b/usb-linux.c index 255009f539..d958853634 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -344,6 +344,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) for (interface = 0; interface < nb_interfaces; interface++) { ctrl.ioctl_code = USBDEVFS_DISCONNECT; ctrl.ifno = interface; + ctrl.data = 0; ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); if (ret < 0 && errno != ENODATA) { perror("USBDEVFS_DISCONNECT"); From a0102082de4026833afbd2525e8a6320d1f92885 Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Wed, 13 Apr 2011 19:45:33 +1000 Subject: [PATCH 208/386] usb: fix spelling errors in usb-linux.c Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- usb-linux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index d958853634..1f33c2c230 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -107,7 +107,7 @@ enum { /* * Control transfer state. * Note that 'buffer' _must_ follow 'req' field because - * we need contigious buffer when we submit control URB. + * we need contiguous buffer when we submit control URB. */ struct ctrl_struct { uint16_t len; @@ -580,7 +580,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p) /* * Setup ctrl transfer. * - * s->ctrl is layed out such that data buffer immediately follows + * s->ctrl is laid out such that data buffer immediately follows * 'req' struct which is exactly what usbdevfs expects. */ urb = &aurb->urb; From b3b4c7f33fc8e51db75bf4abaf4a631c2f1fb23b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 209/386] softfloat: use GCC builtins to count the leading zeros Softfloat has its own implementation to count the leading zeros. However a lot of architectures have either a dedicated instruction or an optimized to do that. When using GCC >= 3.4, this patch uses GCC builtins instead of the handcoded implementation. Note that I amware that QEMU_GNUC_PREREQ is defined in osdep.h and that clz32() and clz64() are defined in host-utils.h, but I think it is better to keep the softfloat implementation self contained. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-macros.h | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index 3128e60cbf..e82ce2332d 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -35,6 +35,17 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ +/*---------------------------------------------------------------------------- +| This macro tests for minimum version of the GNU C compiler. +*----------------------------------------------------------------------------*/ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define SOFTFLOAT_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0 +#endif + + /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of @@ -616,6 +627,13 @@ static uint32_t estimateSqrt32( int16 aExp, uint32_t a ) static int8 countLeadingZeros32( uint32_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clz(a); + } else { + return 32; + } +#else static const int8 countLeadingZerosHigh[] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -647,7 +665,7 @@ static int8 countLeadingZeros32( uint32_t a ) } shiftCount += countLeadingZerosHigh[ a>>24 ]; return shiftCount; - +#endif } /*---------------------------------------------------------------------------- @@ -657,6 +675,13 @@ static int8 countLeadingZeros32( uint32_t a ) static int8 countLeadingZeros64( uint64_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clzll(a); + } else { + return 64; + } +#else int8 shiftCount; shiftCount = 0; @@ -668,7 +693,7 @@ static int8 countLeadingZeros64( uint64_t a ) } shiftCount += countLeadingZeros32( a ); return shiftCount; - +#endif } /*---------------------------------------------------------------------------- From 602308f0f54daa7503ea0f4909b51aef5f3b0ca1 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 210/386] cpu-all.h: define CPU_LDoubleU Add a CPU_LDoubleU type, matching the floatx80 definition and the long double type on x86 hosts. Based on a patch from Laurent Vivier <laurent@vivier.eu>. Cc: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- cpu-all.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index dc0f2f02ab..0bae6df8ec 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -138,6 +138,16 @@ typedef union { uint64_t ll; } CPU_DoubleU; +#if defined(FLOATX80) +typedef union { + floatx80 d; + struct { + uint64_t lower; + uint16_t upper; + } l; +} CPU_LDoubleU; +#endif + #if defined(CONFIG_SOFTFLOAT) typedef union { float128 q; From 1ffd41ee0c5b3409492d237201d50b78578064e5 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 211/386] target-i386: use CPU_LDoubleU instead of a private union Use CPU_LDoubleU in cpu_dump_state() instead of redefining a union for doing the conversion. Based on a patch from Laurent Vivier <laurent@vivier.eu>. Cc: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/helper.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index d15fca591e..89df997436 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -404,16 +404,10 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, env->mxcsr); for(i=0;i<8;i++) { #if defined(USE_X86LDOUBLE) - union { - long double d; - struct { - uint64_t lower; - uint16_t upper; - } l; - } tmp; - tmp.d = env->fpregs[i].d; + CPU_LDoubleU u; + u.d = env->fpregs[i].d; cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", - i, tmp.l.lower, tmp.l.upper); + i, u.l.lower, u.l.upper); #else cpu_fprintf(f, "FPR%d=%016" PRIx64, i, env->fpregs[i].mmx.q); From c41372230e441cb28dcf246d5f2a3226830156bd Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 212/386] target-i386: use float unions from cpu-all.h Use float unions from cpu-all.h instead of redefining new (wrong for arm) ones in target-i386. This also allows building cpu-exec.o with softfloat. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 6f9f709d8a..63a23cd999 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -144,13 +144,7 @@ static inline void svm_check_intercept(uint32_t type) #ifdef USE_X86LDOUBLE /* only for x86 */ -typedef union { - long double d; - struct { - unsigned long long lower; - unsigned short upper; - } l; -} CPU86_LDoubleU; +typedef CPU_LDoubleU CPU86_LDoubleU; /* the following deal with x86 long double-precision numbers */ #define MAXEXPD 0x7fff @@ -162,24 +156,7 @@ typedef union { #else -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ -typedef union { - double d; -#if !defined(HOST_WORDS_BIGENDIAN) && !defined(__arm__) - struct { - uint32_t lower; - int32_t upper; - } l; -#else - struct { - int32_t upper; - uint32_t lower; - } l; -#endif -#ifndef __arm__ - int64_t ll; -#endif -} CPU86_LDoubleU; +typedef CPU_DoubleU CPU86_LDoubleU; /* the following deal with IEEE double-precision numbers */ #define MAXEXPD 0x7ff From 67dd64bfae87b4464b880de03c1d04f5f605d48d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 213/386] target-i386: add floatx_{add,mul,sub} and use them Add floatx_{add,mul,sub} defines, and use them instead of using direct C operations. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 6 ++++++ target-i386/op_helper.c | 18 ++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 63a23cd999..ae6b94740f 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -110,6 +110,9 @@ static inline void svm_check_intercept(uint32_t type) #define float64_to_floatx float64_to_floatx80 #define floatx_to_float32 floatx80_to_float32 #define floatx_to_float64 floatx80_to_float64 +#define floatx_add floatx80_add +#define floatx_mul floatx80_mul +#define floatx_sub floatx80_sub #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs #define floatx_round_to_int floatx80_round_to_int @@ -126,6 +129,9 @@ static inline void svm_check_intercept(uint32_t type) #define float64_to_floatx(x, e) (x) #define floatx_to_float32 float64_to_float32 #define floatx_to_float64(x, e) (x) +#define floatx_add float64_add +#define floatx_mul float64_mul +#define floatx_sub float64_sub #define floatx_abs float64_abs #define floatx_chs float64_chs #define floatx_round_to_int float64_round_to_int diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 43fbd0c778..a73427fe45 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -3711,22 +3711,22 @@ void helper_fucomi_ST0_FT0(void) void helper_fadd_ST0_FT0(void) { - ST0 += FT0; + ST0 = floatx_add(ST0, FT0, &env->fp_status); } void helper_fmul_ST0_FT0(void) { - ST0 *= FT0; + ST0 = floatx_mul(ST0, FT0, &env->fp_status); } void helper_fsub_ST0_FT0(void) { - ST0 -= FT0; + ST0 = floatx_sub(ST0, FT0, &env->fp_status); } void helper_fsubr_ST0_FT0(void) { - ST0 = FT0 - ST0; + ST0 = floatx_sub(FT0, ST0, &env->fp_status); } void helper_fdiv_ST0_FT0(void) @@ -3743,24 +3743,22 @@ void helper_fdivr_ST0_FT0(void) void helper_fadd_STN_ST0(int st_index) { - ST(st_index) += ST0; + ST(st_index) = floatx_add(ST(st_index), ST0, &env->fp_status); } void helper_fmul_STN_ST0(int st_index) { - ST(st_index) *= ST0; + ST(st_index) = floatx_mul(ST(st_index), ST0, &env->fp_status); } void helper_fsub_STN_ST0(int st_index) { - ST(st_index) -= ST0; + ST(st_index) = floatx_sub(ST(st_index), ST0, &env->fp_status); } void helper_fsubr_STN_ST0(int st_index) { - CPU86_LDouble *p; - p = &ST(st_index); - *p = ST0 - *p; + ST(st_index) = floatx_sub(ST0, ST(st_index), &env->fp_status); } void helper_fdiv_STN_ST0(int st_index) From 67b7861d63f5218fe46809f4f84d4412940b9260 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 214/386] softfloat: add float*_unordered_{,quiet}() functions Add float*_unordered() functions to softfloat, matching the softfloat-native ones. Also add float*_unordered_quiet() functions to match the others comparison functions. This allow target-i386/ops_sse.h to be compiled with softfloat. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 8 +++ 2 files changed, 175 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 03fb9487bd..11f6584067 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2393,6 +2393,25 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_unordered( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The invalid exception is @@ -2480,6 +2499,29 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is @@ -3617,6 +3659,26 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_unordered( float64 a, float64 b STATUS_PARAM ) +{ + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the | corresponding value `b', and 0 otherwise. The invalid exception is raised @@ -3704,6 +3766,29 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM ) +{ + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -4596,6 +4681,24 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is equal | to the corresponding value `b', and 0 otherwise. The invalid exception is @@ -4695,6 +4798,28 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. Quiet NaNs do not cause an exception. +| The comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif #ifdef FLOAT128 @@ -5717,6 +5842,25 @@ int float128_lt( float128 a, float128 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The invalid exception is @@ -5816,6 +5960,29 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif /* misc functions */ diff --git a/fpu/softfloat.h b/fpu/softfloat.h index c7654d4c63..55c0c1cda5 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -323,9 +323,11 @@ float32 float32_log2( float32 STATUS_PARAM ); int float32_eq( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); +int float32_unordered( 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_unordered_quiet( float32, float32 STATUS_PARAM ); int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); float32 float32_min(float32, float32 STATUS_PARAM); @@ -437,9 +439,11 @@ float64 float64_log2( float64 STATUS_PARAM ); int float64_eq( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); +int float64_unordered( 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_unordered_quiet( float64, float64 STATUS_PARAM ); int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); float64 float64_min(float64, float64 STATUS_PARAM); @@ -538,9 +542,11 @@ floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +int floatx80_unordered( 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_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); floatx80 floatx80_maybe_silence_nan( floatx80 ); @@ -621,9 +627,11 @@ float128 float128_sqrt( float128 STATUS_PARAM ); int float128_eq( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); +int float128_unordered( 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_unordered_quiet( float128, float128 STATUS_PARAM ); int float128_compare( float128, float128 STATUS_PARAM ); int float128_compare_quiet( float128, float128 STATUS_PARAM ); int float128_is_quiet_nan( float128 ); From b4a0ef7911297567e17b56d96ae06d6283049630 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 215/386] softfloat-native: add float*_unordered_quiet() functions Add float*_unordered_quiet() functions to march the softfloat versions. As FPU status is not tracked with softfloat-native, they don't differ from the signaling version. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 80b5f288e3..406e180c51 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -237,7 +237,10 @@ INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); } int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); @@ -346,7 +349,10 @@ INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); } int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); @@ -450,7 +456,10 @@ INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); } int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); From a4d2d1a063897b859b7f25e414b229370b679bc8 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 216/386] target-alpha: use new float64_unordered_quiet() function Use float64_unordered_quiet() in helper_cmptun() instead of doing the the comparison manually. According to the "Alpha Compiler Writer's Guide", we should use the _quiet version here, as CMPTUN and CMPTEQ should generate InvalidOp for SNaNs but not for QNaNs. Thanks to Peter Maydell <peter.maydell@linaro.org> and Richard Henderson <rth@twiddle.net> for digging into the manuals. Acked-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-alpha/op_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 6c2ae2061f..36f4f6d3b8 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -904,10 +904,11 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b) fa = t_to_float64(a); fb = t_to_float64(b); - if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb)) + if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { return 0x4000000000000000ULL; - else + } else { return 0; + } } uint64_t helper_cmpteq(uint64_t a, uint64_t b) From 3a599383592a26f2c614e1a7d92efd1e8eb26c6d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 217/386] target-mips: use new float*_unordered*() functions Use the new float*_unordered*() functions from softfloat instead of redefining a private version. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-mips/op_helper.c | 168 +++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 98 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index bd16ce3543..e9de692fe1 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2889,40 +2889,26 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ CLEAR_FP_COND(cc, env->active_fpu); \ } -static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) -{ - if (float64_is_signaling_nan(a) || - float64_is_signaling_nan(b) || - (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) { - return 1; - } else { - return 0; - } -} - /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + * but float64_unordered_quiet() is still called. */ +FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(eq, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(olt, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ole, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + * but float64_unordered() is still called. */ +FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) +FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)) +FOP_COND_D(seq, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(lt, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(le, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) #define FOP_COND_S(op, cond) \ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ @@ -2947,40 +2933,26 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ CLEAR_FP_COND(cc, env->active_fpu); \ } -static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) -{ - if (float32_is_signaling_nan(a) || - float32_is_signaling_nan(b) || - (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) { - return 1; - } else { - return 0; - } -} - /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + * but float32_unordered_quiet() is still called. */ +FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ole, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + * but float32_unordered() is still called. */ +FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) +FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status)) +FOP_COND_S(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(le, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) #define FOP_COND_PS(op, condl, condh) \ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ @@ -3023,38 +2995,38 @@ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ } /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0), - (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) + * but float32_unordered_quiet() is still called. */ +FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ole, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0), - (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), - float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) + * but float32_unordered() is still called. */ +FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0), + (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0)) +FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)) +FOP_COND_PS(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(le, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) From e0b29ce1cf961223a21caa459b14647c1da117ec Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 218/386] target-i386: fix CMPUNORDPS/D and CMPORDPS/D instructions SSE instructions CMPUNORDPS/D and CMPORDPS/D do not trigger an invalid exception if operands are qNANs. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/ops_sse.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 3232abd965..986cbe3d88 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -924,11 +924,11 @@ void helper_ ## name ## sd (Reg *d, Reg *s)\ #define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0 -#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0 +#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? - 1 : 0 #define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1 -#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1 SSE_HELPER_CMP(cmpeq, FPU_CMPEQ) SSE_HELPER_CMP(cmplt, FPU_CMPLT) From 211315fb5eb35c055e3134d58f2880d466bd5902 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 219/386] softfloat: rename float*_eq() into float*_eq_quiet() float*_eq functions have a different semantics than other comparison functions. Fix that by first renaming float*_quiet() into float*_eq_quiet(). Note that it is purely mechanical, and the behaviour should be unchanged. That said it clearly highlight problems due to this different semantics, they are fixed later in this patch series. Cc: Alexander Graf <agraf@suse.de> Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.h | 6 +++--- fpu/softfloat.c | 8 ++++---- fpu/softfloat.h | 8 ++++---- linux-user/arm/nwfpe/fpa11_cprt.c | 2 +- target-alpha/op_helper.c | 4 ++-- target-i386/ops_sse.h | 8 ++++---- target-microblaze/op_helper.c | 4 ++-- target-mips/op_helper.c | 32 +++++++++++++++---------------- target-ppc/op_helper.c | 4 ++-- 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 406e180c51..0c7f48b4fa 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -210,7 +210,7 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) } float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); -INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM) { return a == b; } @@ -321,7 +321,7 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) } float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM) { return a == b; } @@ -428,7 +428,7 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) } floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return a == b; } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 11f6584067..492ef36a3d 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2318,7 +2318,7 @@ float32 float32_log2( float32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq( float32 a, float32 b STATUS_PARAM ) +int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) { a = float32_squash_input_denormal(a STATUS_VAR); b = float32_squash_input_denormal(b STATUS_VAR); @@ -3582,7 +3582,7 @@ float64 float64_log2( float64 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq( float64 a, float64 b STATUS_PARAM ) +int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) { uint64_t av, bv; a = float64_squash_input_denormal(a STATUS_VAR); @@ -4592,7 +4592,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -5754,7 +5754,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq( float128 a, float128 b STATUS_PARAM ) +int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 55c0c1cda5..738a50c11f 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -320,7 +320,7 @@ float32 float32_rem( float32, float32 STATUS_PARAM ); float32 float32_sqrt( float32 STATUS_PARAM ); float32 float32_exp2( float32 STATUS_PARAM ); float32 float32_log2( float32 STATUS_PARAM ); -int float32_eq( float32, float32 STATUS_PARAM ); +int float32_eq_quiet( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); int float32_unordered( float32, float32 STATUS_PARAM ); @@ -436,7 +436,7 @@ float64 float64_div( float64, float64 STATUS_PARAM ); float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); float64 float64_log2( float64 STATUS_PARAM ); -int float64_eq( float64, float64 STATUS_PARAM ); +int float64_eq_quiet( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); int float64_unordered( float64, float64 STATUS_PARAM ); @@ -539,7 +539,7 @@ 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 ); -int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered( floatx80, floatx80 STATUS_PARAM ); @@ -624,7 +624,7 @@ 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 ); -int float128_eq( float128, float128 STATUS_PARAM ); +int float128_eq_quiet( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); int float128_unordered( float128, float128 STATUS_PARAM ); diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index be54e9515d..801189798b 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -159,7 +159,7 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) } /* test for equal condition */ - if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) + if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status)) { flags |= CC_ZERO; } diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 36f4f6d3b8..9f71db4c3a 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -918,7 +918,7 @@ uint64_t helper_cmpteq(uint64_t a, uint64_t b) fa = t_to_float64(a); fb = t_to_float64(b); - if (float64_eq(fa, fb, &FP_STATUS)) + if (float64_eq_quiet(fa, fb, &FP_STATUS)) return 0x4000000000000000ULL; else return 0; @@ -957,7 +957,7 @@ uint64_t helper_cmpgeq(uint64_t a, uint64_t b) fa = g_to_float64(a); fb = g_to_float64(b); - if (float64_eq(fa, fb, &FP_STATUS)) + if (float64_eq_quiet(fa, fb, &FP_STATUS)) return 0x4000000000000000ULL; else return 0; diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 986cbe3d88..ac0f150070 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -921,11 +921,11 @@ void helper_ ## name ## sd (Reg *d, Reg *s)\ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } -#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0 +#define FPU_CMPEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0 #define FPU_CMPUNORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? - 1 : 0 -#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPNEQ(size, a, b) float ## size ## _eq_quiet(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1 #define FPU_CMPORD(size, a, b) float ## size ## _unordered_quiet(a, b, &env->sse_status) ? 0 : -1 @@ -1216,8 +1216,8 @@ void helper_pfadd(MMXReg *d, MMXReg *s) void helper_pfcmpeq(MMXReg *d, MMXReg *s) { - d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; - d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; + d->MMX_L(0) = float32_eq_quiet(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; + d->MMX_L(1) = float32_eq_quiet(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; } void helper_pfcmpge(MMXReg *d, MMXReg *s) diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index 39b8ec1e15..b7cd6b288f 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -338,7 +338,7 @@ uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) set_float_exception_flags(0, &env->fp_status); fa.l = a; fb.l = b; - r = float32_eq(fa.f, fb.f, &env->fp_status); + r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); update_fpu_flags(flags & float_flag_invalid); @@ -384,7 +384,7 @@ uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) fa.l = a; fb.l = b; set_float_exception_flags(0, &env->fp_status); - r = !float32_eq(fa.f, fb.f, &env->fp_status); + r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); flags = get_float_exception_flags(&env->fp_status); update_fpu_flags(flags & float_flag_invalid); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e9de692fe1..31a19bab75 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2893,8 +2893,8 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ * but float64_unordered_quiet() is still called. */ FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0)) FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(eq, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(eq, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(olt, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(ole, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) @@ -2903,8 +2903,8 @@ FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) * but float64_unordered() is still called. */ FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(seq, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(seq, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(lt, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(le, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) @@ -2937,8 +2937,8 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ * but float32_unordered_quiet() is still called. */ FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0)) FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(ole, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) @@ -2947,8 +2947,8 @@ FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) * but float32_unordered() is still called. */ FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(le, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) @@ -3000,10 +3000,10 @@ FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0)) FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), @@ -3018,10 +3018,10 @@ FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0), (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0)) FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status), float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), - float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 8c993a1cf5..898ffd0b79 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3364,7 +3364,7 @@ static inline uint32_t efststeq(uint32_t op1, uint32_t op2) CPU_FloatU u1, u2; u1.l = op1; u2.l = op2; - return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; + return float32_eq_quiet(u1.f, u2.f, &env->vec_status) ? 4 : 0; } static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) @@ -3678,7 +3678,7 @@ uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2) CPU_DoubleU u1, u2; u1.ll = op1; u2.ll = op2; - return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0; + return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; } uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2) From 2657d0ff8f71cc5c084ee958d0087a5313099e74 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 220/386] softfloat: rename float*_eq_signaling() into float*_eq() float*_eq_signaling functions have a different semantics than other comparison functions. Fix that by renaming float*_quiet_signaling() into float*_eq(). Note that it is purely mechanical, and the behaviour should be unchanged. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.h | 6 +++--- fpu/softfloat.c | 8 ++++---- fpu/softfloat.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 0c7f48b4fa..ea7a15e1c4 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -222,7 +222,7 @@ INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) { return a < b; } -INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) { return a <= b && a >= b; } @@ -333,7 +333,7 @@ INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) { return a < b; } -INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) { return a <= b && a >= b; } @@ -440,7 +440,7 @@ INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) { return a < b; } -INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b && a >= b; } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 492ef36a3d..2e029405d8 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2419,7 +2419,7 @@ int float32_unordered( float32 a, float32 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +int float32_eq( float32 a, float32 b STATUS_PARAM ) { uint32_t av, bv; a = float32_squash_input_denormal(a STATUS_VAR); @@ -3686,7 +3686,7 @@ int float64_unordered( float64 a, float64 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +int float64_eq( float64 a, float64 b STATUS_PARAM ) { uint64_t av, bv; a = float64_squash_input_denormal(a STATUS_VAR); @@ -4706,7 +4706,7 @@ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -5868,7 +5868,7 @@ int float128_unordered( float128 a, float128 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +int float128_eq( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 738a50c11f..b9440b2c75 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -324,7 +324,7 @@ int float32_eq_quiet( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); int float32_unordered( float32, float32 STATUS_PARAM ); -int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_eq( float32, float32 STATUS_PARAM ); int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); int float32_unordered_quiet( float32, float32 STATUS_PARAM ); @@ -440,7 +440,7 @@ int float64_eq_quiet( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); int float64_unordered( float64, float64 STATUS_PARAM ); -int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_eq( float64, float64 STATUS_PARAM ); int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); int float64_unordered_quiet( float64, float64 STATUS_PARAM ); @@ -543,7 +543,7 @@ int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered( floatx80, floatx80 STATUS_PARAM ); -int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); @@ -628,7 +628,7 @@ int float128_eq_quiet( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); int float128_unordered( float128, float128 STATUS_PARAM ); -int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_eq( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); int float128_unordered_quiet( float128, float128 STATUS_PARAM ); From b689362d14e7b5689c6e006f962268764ed5df64 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:29 +0200 Subject: [PATCH 221/386] softfloat: move float*_eq and float*_eq_quiet I am not a big fan of code moving, but having the signaling version in the middle of quiet versions and vice versa doesn't make the code easy to read. This patch is a simple code move, basically swapping locations of float*_eq and float*_eq_quiet. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 101 ++++++++++++++++++++++++------------------------ fpu/softfloat.h | 16 ++++---- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 2e029405d8..efd718bbcb 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2314,26 +2314,26 @@ float32 float32_log2( float32 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_eq( float32 a, float32 b STATUS_PARAM ) { + uint32_t av, bv; a = float32_squash_input_denormal(a STATUS_VAR); b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( float32_val(a) == float32_val(b) ) || - ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); - + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- @@ -2412,29 +2412,28 @@ int float32_unordered( float32 a, float32 b STATUS_PARAM ) } return 0; } + /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed +| the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq( float32 a, float32 b STATUS_PARAM ) +int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) { - uint32_t av, bv; a = float32_squash_input_denormal(a STATUS_VAR); b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } - av = float32_val(a); - bv = float32_val(b); - return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); - + return ( float32_val(a) == float32_val(b) ) || + ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- @@ -3578,11 +3577,12 @@ float64 float64_log2( float64 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The comparison is performed +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_eq( float64 a, float64 b STATUS_PARAM ) { uint64_t av, bv; a = float64_squash_input_denormal(a STATUS_VAR); @@ -3591,9 +3591,7 @@ int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } av = float64_val(a); @@ -3681,12 +3679,11 @@ int float64_unordered( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The invalid exception is raised -| if either operand is a NaN. Otherwise, the comparison is performed +| corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq( float64 a, float64 b STATUS_PARAM ) +int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) { uint64_t av, bv; a = float64_squash_input_denormal(a STATUS_VAR); @@ -3695,7 +3692,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } av = float64_val(a); @@ -4586,13 +4585,13 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -4600,10 +4599,7 @@ int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return @@ -4700,13 +4696,13 @@ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is equal -| to the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. *----------------------------------------------------------------------------*/ -int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -4714,7 +4710,10 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return @@ -5750,11 +5749,12 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) +int float128_eq( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5762,10 +5762,7 @@ int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return @@ -5863,12 +5860,11 @@ int float128_unordered( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed +| the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq( float128 a, float128 b STATUS_PARAM ) +int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5876,7 +5872,10 @@ int float128_eq( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return diff --git a/fpu/softfloat.h b/fpu/softfloat.h index b9440b2c75..340f0a9f2e 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -320,11 +320,11 @@ float32 float32_rem( float32, float32 STATUS_PARAM ); float32 float32_sqrt( float32 STATUS_PARAM ); float32 float32_exp2( float32 STATUS_PARAM ); float32 float32_log2( float32 STATUS_PARAM ); -int float32_eq_quiet( float32, float32 STATUS_PARAM ); +int float32_eq( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); int float32_unordered( float32, float32 STATUS_PARAM ); -int float32_eq( float32, float32 STATUS_PARAM ); +int float32_eq_quiet( float32, float32 STATUS_PARAM ); int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); int float32_unordered_quiet( float32, float32 STATUS_PARAM ); @@ -436,11 +436,11 @@ float64 float64_div( float64, float64 STATUS_PARAM ); float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); float64 float64_log2( float64 STATUS_PARAM ); -int float64_eq_quiet( float64, float64 STATUS_PARAM ); +int float64_eq( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); int float64_unordered( float64, float64 STATUS_PARAM ); -int float64_eq( float64, float64 STATUS_PARAM ); +int float64_eq_quiet( float64, float64 STATUS_PARAM ); int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); int float64_unordered_quiet( float64, float64 STATUS_PARAM ); @@ -539,11 +539,11 @@ 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 ); -int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered( floatx80, floatx80 STATUS_PARAM ); -int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); @@ -624,11 +624,11 @@ 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 ); -int float128_eq_quiet( float128, float128 STATUS_PARAM ); +int float128_eq( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); int float128_unordered( float128, float128 STATUS_PARAM ); -int float128_eq( float128, float128 STATUS_PARAM ); +int float128_eq_quiet( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); int float128_unordered_quiet( float128, float128 STATUS_PARAM ); From f5a64251f2db2271970a1f4b7f8176d4de4dec91 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 222/386] softfloat: improve description of comparison functions Make clear for all comparison functions which ones trigger an exception for all NaNs, and which one only for sNaNs. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 85 ++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index efd718bbcb..6ce0b61c19 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2338,9 +2338,9 @@ int float32_eq( float32 a, float32 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_le( float32 a, float32 b STATUS_PARAM ) @@ -2367,8 +2367,9 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_lt( float32 a, float32 b STATUS_PARAM ) @@ -2395,8 +2396,9 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_unordered( float32 a, float32 b STATUS_PARAM ) @@ -2415,8 +2417,9 @@ int float32_unordered( float32 a, float32 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) @@ -3602,9 +3605,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_le( float64 a, float64 b STATUS_PARAM ) @@ -3631,8 +3634,9 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_lt( float64 a, float64 b STATUS_PARAM ) @@ -3659,8 +3663,9 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_unordered( float64 a, float64 b STATUS_PARAM ) @@ -3679,8 +3684,9 @@ int float64_unordered( float64 a, float64 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception.The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) @@ -4614,8 +4620,9 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | less than or equal to the corresponding value `b', and 0 otherwise. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. +| invalid exception is raised if either operand is a NaN. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4646,9 +4653,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is -| less than the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| less than the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4679,8 +4686,9 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point values `a' and `b' -| cannot be compared, and 0 otherwise. The comparison is performed according -| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| cannot be compared, and 0 otherwise. The invalid exception is raised if +| either operand is a NaN. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) { @@ -4697,9 +4705,9 @@ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) @@ -5776,9 +5784,9 @@ int float128_eq( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_le( float128 a, float128 b STATUS_PARAM ) @@ -5809,8 +5817,9 @@ int float128_le( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_lt( float128 a, float128 b STATUS_PARAM ) @@ -5841,8 +5850,9 @@ int float128_lt( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot -| be compared, and 0 otherwise. The comparison is performed according to the -| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_unordered( float128 a, float128 b STATUS_PARAM ) @@ -5860,8 +5870,9 @@ int float128_unordered( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) From 019702c8156ee442378a520b733d823c0c62072b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 223/386] target-ppc: fix SPE comparison functions efstst*() functions are fast SPE funtions which do not take into account special values (infinites, NaN, etc.), while efscmp*() functions are IEEE754 compliant. Given that float32_*() functions are IEEE754 compliant, the efscmp*() functions are correctly implemented, while efstst*() are not. This patch reverse the implementation of this two groups of functions and fix the comments. It also use float32_eq() instead of float32_eq_quiet() as qNaNs should not be ignored. Cc: Alexander Graf <agraf@suse.de> Cc: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-ppc/op_helper.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 898ffd0b79..28d40ac9aa 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3343,7 +3343,7 @@ HELPER_SPE_VECTOR_ARITH(fsmul); HELPER_SPE_VECTOR_ARITH(fsdiv); /* Single-precision floating-point comparisons */ -static inline uint32_t efststlt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; @@ -3351,7 +3351,7 @@ static inline uint32_t efststlt(uint32_t op1, uint32_t op2) return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efststgt(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; @@ -3359,30 +3359,30 @@ static inline uint32_t efststgt(uint32_t op1, uint32_t op2) return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; } -static inline uint32_t efststeq(uint32_t op1, uint32_t op2) +static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) { CPU_FloatU u1, u2; u1.l = op1; u2.l = op2; - return float32_eq_quiet(u1.f, u2.f, &env->vec_status) ? 4 : 0; + return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; } -static inline uint32_t efscmplt(uint32_t op1, uint32_t op2) +static inline uint32_t efststlt(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststlt(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmplt(op1, op2); } -static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2) +static inline uint32_t efststgt(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststgt(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpgt(op1, op2); } -static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2) +static inline uint32_t efststeq(uint32_t op1, uint32_t op2) { - /* XXX: TODO: test special values (NaN, infinites, ...) */ - return efststeq(op1, op2); + /* XXX: TODO: ignore special values (NaN, infinites, ...) */ + return efscmpeq(op1, op2); } #define HELPER_SINGLE_SPE_CMP(name) \ From 06a0e6b104718803bceecbb5efd4125bcf71d8c7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 224/386] target-mips: simplify FP comparisons As the softfloat comparison functions already test for NaN, there is no need to always call the float*_unordered*() functions. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-mips/op_helper.c | 72 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 31a19bab75..abcb6eb8bc 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2893,21 +2893,21 @@ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ * but float64_unordered_quiet() is still called. */ FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0)) FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(eq, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(olt, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ole, !float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float64_unordered() is still called. */ FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0)) FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)) -FOP_COND_D(seq, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(lt, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)) -FOP_COND_D(le, !float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) +FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) #define FOP_COND_S(op, cond) \ @@ -2937,21 +2937,21 @@ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ * but float32_unordered_quiet() is still called. */ FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0)) FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ole, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float32_unordered() is still called. */ FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0)) FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status)) -FOP_COND_S(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status)) -FOP_COND_S(le, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status)) +FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status)) FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) #define FOP_COND_PS(op, condl, condh) \ @@ -3000,33 +3000,33 @@ FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0)) FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(eq, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(olt, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), - float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ole, !float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), - float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float32_unordered() is still called. */ FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0), (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0)) FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status), float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)) -FOP_COND_PS(seq, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status), - float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(lt, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status), + float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status), + float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status), float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status)) -FOP_COND_PS(le, !float32_unordered(fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status), - !float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) +FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status), + float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status), float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status)) From 353ebb7ac22f2866ac3680a3340aa21185c50407 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 225/386] target-mips: don't hardcode softfloat exception bits Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-mips/op_helper.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index abcb6eb8bc..0a623614fc 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2077,22 +2077,27 @@ void helper_ctc1 (target_ulong arg1, uint32_t reg) helper_raise_exception(EXCP_FPE); } -static inline char ieee_ex_to_mips(char xcpt) +static inline int ieee_ex_to_mips(int xcpt) { - return (xcpt & float_flag_inexact) >> 5 | - (xcpt & float_flag_underflow) >> 3 | - (xcpt & float_flag_overflow) >> 1 | - (xcpt & float_flag_divbyzero) << 1 | - (xcpt & float_flag_invalid) << 4; -} - -static inline char mips_ex_to_ieee(char xcpt) -{ - return (xcpt & FP_INEXACT) << 5 | - (xcpt & FP_UNDERFLOW) << 3 | - (xcpt & FP_OVERFLOW) << 1 | - (xcpt & FP_DIV0) >> 1 | - (xcpt & FP_INVALID) >> 4; + int ret = 0; + if (xcpt) { + if (xcpt & float_flag_invalid) { + ret |= FP_INVALID; + } + if (xcpt & float_flag_overflow) { + ret |= FP_OVERFLOW; + } + if (xcpt & float_flag_underflow) { + ret |= FP_UNDERFLOW; + } + if (xcpt & float_flag_divbyzero) { + ret |= FP_DIV0; + } + if (xcpt & float_flag_inexact) { + ret |= FP_INEXACT; + } + } + return ret; } static inline void update_fcr31(void) From 30a00bc142796f6d436b0b79f01757afb1e4c1e7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 226/386] target-mips: fix c.ps.* instructions Contrary to cabs.ps.* instructions, c.ps.* should not compare the absolute value of the operand, but directly the operands. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-mips/op_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 0a623614fc..b35a6d2936 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2962,10 +2962,10 @@ FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || fl #define FOP_COND_PS(op, condl, condh) \ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ - uint32_t fsth0 = float32_abs(fdt0 >> 32); \ - uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ - uint32_t fsth1 = float32_abs(fdt1 >> 32); \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ int cl = condl; \ int ch = condh; \ \ From 6a385343e42c500f8404ecf9365ff63f4c942057 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Thu, 14 Apr 2011 00:49:30 +0200 Subject: [PATCH 227/386] target-mips: clear softfpu exception state for comparison instructions MIPS FPU instructions should start with a clean softfpu status. This is done for the most instructions, but not for comparison ones. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-mips/op_helper.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b35a6d2936..8cba535a32 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2874,7 +2874,9 @@ uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) #define FOP_COND_D(op, cond) \ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - int c = cond; \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ update_fcr31(); \ if (c) \ SET_FP_COND(cc, env->active_fpu); \ @@ -2884,6 +2886,7 @@ void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ fdt0 = float64_abs(fdt0); \ fdt1 = float64_abs(fdt1); \ c = cond; \ @@ -2918,7 +2921,9 @@ FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || fl #define FOP_COND_S(op, cond) \ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ { \ - int c = cond; \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ update_fcr31(); \ if (c) \ SET_FP_COND(cc, env->active_fpu); \ @@ -2928,6 +2933,7 @@ void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ { \ int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ fst0 = float32_abs(fst0); \ fst1 = float32_abs(fst1); \ c = cond; \ @@ -2962,13 +2968,15 @@ FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || fl #define FOP_COND_PS(op, condl, condh) \ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ - uint32_t fsth0 = fdt0 >> 32; \ - uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ - uint32_t fsth1 = fdt1 >> 32; \ - int cl = condl; \ - int ch = condh; \ - \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + fst0 = fdt0 & 0XFFFFFFFF; \ + fsth0 = fdt0 >> 32; \ + fst1 = fdt1 & 0XFFFFFFFF; \ + fsth1 = fdt1 >> 32; \ + cl = condl; \ + ch = condh; \ update_fcr31(); \ if (cl) \ SET_FP_COND(cc, env->active_fpu); \ @@ -2981,13 +2989,14 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ } \ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ { \ - uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ - uint32_t fsth0 = float32_abs(fdt0 >> 32); \ - uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ - uint32_t fsth1 = float32_abs(fdt1 >> 32); \ - int cl = condl; \ - int ch = condh; \ - \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ + fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \ + fsth0 = float32_abs(fdt0 >> 32); \ + fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \ + fsth1 = float32_abs(fdt1 >> 32); \ + cl = condl; \ + ch = condh; \ update_fcr31(); \ if (cl) \ SET_FP_COND(cc, env->active_fpu); \ From 685ff50f698f11dec8e9e193e8bc86b051a8cf26 Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Wed, 13 Apr 2011 14:42:00 +0300 Subject: [PATCH 228/386] libcacard: fix opposite usage of isspace Signed-off-by: Alon Levy <alevy@redhat.com> Tested-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- libcacard/vcard_emul_nss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 71f2ba3ae5..baada52a3c 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -955,7 +955,7 @@ count_tokens(const char *str, char token, char token_end) static const char * strip(const char *str) { - for (; *str && !isspace(*str); str++) { + for (; *str && isspace(*str); str++) { } return str; } @@ -963,7 +963,7 @@ strip(const char *str) static const char * find_blank(const char *str) { - for (; *str && isspace(*str); str++) { + for (; *str && !isspace(*str); str++) { } return str; } From 7b59220ef31a9c8758f8de16e6aaf3fc14b6540c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs?= <xscript@gmx.net> Date: Wed, 13 Apr 2011 18:38:24 +0200 Subject: [PATCH 229/386] move helpers.h to helper.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides a consistent naming scheme across all targets. Signed-off-by: LluÃs Vilanova <vilanova@ac.upc.edu> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helper.c | 2 +- target-arm/{helpers.h => helper.h} | 0 target-arm/iwmmxt_helper.c | 2 +- target-arm/neon_helper.c | 2 +- target-arm/op_helper.c | 2 +- target-arm/translate.c | 6 +++--- 6 files changed, 7 insertions(+), 7 deletions(-) rename target-arm/{helpers.h => helper.h} (100%) diff --git a/target-arm/helper.c b/target-arm/helper.c index a0ec6439da..12127dee74 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,7 +5,7 @@ #include "cpu.h" #include "exec-all.h" #include "gdbstub.h" -#include "helpers.h" +#include "helper.h" #include "qemu-common.h" #include "host-utils.h" #if !defined(CONFIG_USER_ONLY) diff --git a/target-arm/helpers.h b/target-arm/helper.h similarity index 100% rename from target-arm/helpers.h rename to target-arm/helper.h diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c index 3941f1fd89..ebe6eb9fae 100644 --- a/target-arm/iwmmxt_helper.c +++ b/target-arm/iwmmxt_helper.c @@ -24,7 +24,7 @@ #include "cpu.h" #include "exec.h" -#include "helpers.h" +#include "helper.h" /* iwMMXt macros extracted from GNU gdb. */ diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 7df925ad31..f5b173aa71 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -11,7 +11,7 @@ #include "cpu.h" #include "exec.h" -#include "helpers.h" +#include "helper.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 3de2610348..ee7286b77a 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -17,7 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "exec.h" -#include "helpers.h" +#include "helper.h" #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) diff --git a/target-arm/translate.c b/target-arm/translate.c index 6190028d08..fc9ff8d9e8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -30,9 +30,9 @@ #include "tcg-op.h" #include "qemu-log.h" -#include "helpers.h" +#include "helper.h" #define GEN_HELPER 1 -#include "helpers.h" +#include "helper.h" #define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T) #define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5) @@ -129,7 +129,7 @@ void arm_translate_init(void) #endif #define GEN_HELPER 2 -#include "helpers.h" +#include "helper.h" } static inline TCGv load_cpu_offset(int offset) From 5ee8ad71e159e724e2fa1af6b2c502668179502a Mon Sep 17 00:00:00 2001 From: Alex Williamson <alex.williamson@redhat.com> Date: Mon, 18 Apr 2011 11:46:01 -0600 Subject: [PATCH 230/386] PXE: Use consistent naming for PXE ROMs And add missing ROMs to tarbin build target. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- Makefile | 16 ++++++++-------- configure | 2 +- hw/e1000.c | 2 +- hw/eepro100.c | 2 +- hw/ne2000.c | 2 +- hw/pcnet-pci.c | 2 +- hw/rtl8139.c | 2 +- hw/virtio-pci.c | 2 +- pc-bios/{pxe-e1000.bin => pxe-e1000.rom} | Bin ...e-eepro100-80861209.rom => pxe-eepro100.rom} | Bin pc-bios/{pxe-ne2k_pci.bin => pxe-ne2k_pci.rom} | Bin pc-bios/{pxe-pcnet.bin => pxe-pcnet.rom} | Bin pc-bios/{pxe-rtl8139.bin => pxe-rtl8139.rom} | Bin pc-bios/{pxe-virtio.bin => pxe-virtio.rom} | Bin 14 files changed, 15 insertions(+), 15 deletions(-) rename pc-bios/{pxe-e1000.bin => pxe-e1000.rom} (100%) rename pc-bios/{gpxe-eepro100-80861209.rom => pxe-eepro100.rom} (100%) rename pc-bios/{pxe-ne2k_pci.bin => pxe-ne2k_pci.rom} (100%) rename pc-bios/{pxe-pcnet.bin => pxe-pcnet.rom} (100%) rename pc-bios/{pxe-rtl8139.bin => pxe-rtl8139.rom} (100%) rename pc-bios/{pxe-virtio.bin => pxe-virtio.rom} (100%) diff --git a/Makefile b/Makefile index fa93be5ed7..9df4fff630 100644 --- a/Makefile +++ b/Makefile @@ -177,10 +177,8 @@ ifdef INSTALL_BLOBS BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ -gpxe-eepro100-80861209.rom \ -pxe-e1000.bin \ -pxe-ne2k_pci.bin pxe-pcnet.bin \ -pxe-rtl8139.bin pxe-virtio.bin \ +pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ +pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin \ s390-zipl.rom \ @@ -326,10 +324,12 @@ tarbin: $(datadir)/openbios-sparc32 \ $(datadir)/openbios-sparc64 \ $(datadir)/openbios-ppc \ - $(datadir)/pxe-ne2k_pci.bin \ - $(datadir)/pxe-rtl8139.bin \ - $(datadir)/pxe-pcnet.bin \ - $(datadir)/pxe-e1000.bin \ + $(datadir)/pxe-e1000.rom \ + $(datadir)/pxe-eepro100.rom \ + $(datadir)/pxe-ne2k_pci.rom \ + $(datadir)/pxe-pcnet.rom \ + $(datadir)/pxe-rtl8139.rom \ + $(datadir)/pxe-virtio.rom \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ $(mandir)/man1/qemu.1 \ diff --git a/configure b/configure index ae97e11a97..813ef7a7a2 100755 --- a/configure +++ b/configure @@ -3445,7 +3445,7 @@ FILES="Makefile tests/Makefile" FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" -for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do +for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do FILES="$FILES pc-bios/`basename $bios_file`" done mkdir -p $DIRS diff --git a/hw/e1000.c b/hw/e1000.c index fe3e812610..f160bfc2ab 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1220,7 +1220,7 @@ static PCIDeviceInfo e1000_info = { .qdev.vmsd = &vmstate_e1000, .init = pci_e1000_init, .exit = pci_e1000_uninit, - .romfile = "pxe-e1000.bin", + .romfile = "pxe-e1000.rom", .qdev.props = (Property[]) { DEFINE_NIC_PROPERTIES(E1000State, conf), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/eepro100.c b/hw/eepro100.c index edf48f61d1..369ad7f840 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -2054,7 +2054,7 @@ static void eepro100_register_devices(void) PCIDeviceInfo *pci_dev = &e100_devices[i].pci; /* We use the same rom file for all device ids. QEMU fixes the device id during rom load. */ - pci_dev->romfile = "gpxe-eepro100-80861209.rom"; + pci_dev->romfile = "pxe-eepro100.rom"; pci_dev->init = e100_nic_init; pci_dev->exit = pci_nic_uninit; pci_dev->qdev.props = e100_properties; diff --git a/hw/ne2000.c b/hw/ne2000.c index 5966359852..b668ad1070 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -742,7 +742,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev) if (!pci_dev->qdev.hotplugged) { static int loaded = 0; if (!loaded) { - rom_add_option("pxe-ne2k_pci.bin", -1); + rom_add_option("pxe-ne2k_pci.rom", -1); loaded = 1; } } diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 339a401967..40ee29d38b 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -310,7 +310,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev) if (!pci_dev->qdev.hotplugged) { static int loaded = 0; if (!loaded) { - rom_add_option("pxe-pcnet.bin", -1); + rom_add_option("pxe-pcnet.rom", -1); loaded = 1; } } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d5459336e5..8790a00afb 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3484,7 +3484,7 @@ static PCIDeviceInfo rtl8139_info = { .qdev.vmsd = &vmstate_rtl8139, .init = pci_rtl8139_init, .exit = pci_rtl8139_uninit, - .romfile = "pxe-rtl8139.bin", + .romfile = "pxe-rtl8139.rom", .qdev.props = (Property[]) { DEFINE_NIC_PROPERTIES(RTL8139State, conf), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 555f23f1da..c19629d507 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -877,7 +877,7 @@ static PCIDeviceInfo virtio_info[] = { .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_net_init_pci, .exit = virtio_net_exit_pci, - .romfile = "pxe-virtio.bin", + .romfile = "pxe-virtio.rom", .qdev.props = (Property[]) { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), diff --git a/pc-bios/pxe-e1000.bin b/pc-bios/pxe-e1000.rom similarity index 100% rename from pc-bios/pxe-e1000.bin rename to pc-bios/pxe-e1000.rom diff --git a/pc-bios/gpxe-eepro100-80861209.rom b/pc-bios/pxe-eepro100.rom similarity index 100% rename from pc-bios/gpxe-eepro100-80861209.rom rename to pc-bios/pxe-eepro100.rom diff --git a/pc-bios/pxe-ne2k_pci.bin b/pc-bios/pxe-ne2k_pci.rom similarity index 100% rename from pc-bios/pxe-ne2k_pci.bin rename to pc-bios/pxe-ne2k_pci.rom diff --git a/pc-bios/pxe-pcnet.bin b/pc-bios/pxe-pcnet.rom similarity index 100% rename from pc-bios/pxe-pcnet.bin rename to pc-bios/pxe-pcnet.rom diff --git a/pc-bios/pxe-rtl8139.bin b/pc-bios/pxe-rtl8139.rom similarity index 100% rename from pc-bios/pxe-rtl8139.bin rename to pc-bios/pxe-rtl8139.rom diff --git a/pc-bios/pxe-virtio.bin b/pc-bios/pxe-virtio.rom similarity index 100% rename from pc-bios/pxe-virtio.bin rename to pc-bios/pxe-virtio.rom From 36d8d02dc8c45780cae74e2ba7a6135b95c16f81 Mon Sep 17 00:00:00 2001 From: Alex Williamson <alex.williamson@redhat.com> Date: Mon, 18 Apr 2011 11:46:41 -0600 Subject: [PATCH 231/386] PXE: Refresh all PXE ROMs from the ipxe submodule Add script to make this easy to repeat later. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> --- pc-bios/README | 17 +++---- pc-bios/pxe-e1000.rom | Bin 72192 -> 67072 bytes pc-bios/pxe-eepro100.rom | Bin 56832 -> 61440 bytes pc-bios/pxe-ne2k_pci.rom | Bin 56320 -> 61440 bytes pc-bios/pxe-pcnet.rom | Bin 56832 -> 61440 bytes pc-bios/pxe-rtl8139.rom | Bin 56320 -> 61440 bytes pc-bios/pxe-virtio.rom | Bin 56320 -> 60416 bytes scripts/refresh-pxe-roms.sh | 99 ++++++++++++++++++++++++++++++++++++ 8 files changed, 107 insertions(+), 9 deletions(-) create mode 100755 scripts/refresh-pxe-roms.sh diff --git a/pc-bios/README b/pc-bios/README index 646a31a313..fe221a940f 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -18,16 +18,15 @@ https://github.com/dgibson/SLOF, and the image currently in qemu is built from git tag qemu-slof-20110323. -- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0 +- The PXE roms come from the iPXE project. Built with BANNER_TIME 0. + Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: - e1000 8086:100E - eepro100 8086:1209 (also used for 8086:1229 and 8086:2449) - ns8390 1050:0940 - pcnet32 1022:2000 - rtl8139 10ec:8139 - virtio 1af4:1000 - - http://rom-o-matic.net/ + 8086:100e -> pxe-e1000.rom + 8086:1209 -> pxe-eepro100.rom + 1050:0940 -> pxe-ne2k_pci.rom + 1022:2000 -> pxe-pcnet.rom + 10ec:8139 -> pxe-rtl8139.rom + 1af4:1000 -> pxe-virtio.rom - The S390 zipl loader is an addition to the official IBM s390-tools package. That fork is maintained in its own git repository at: diff --git a/pc-bios/pxe-e1000.rom b/pc-bios/pxe-e1000.rom index 7ac744eb39f55aa1d6f18cc9257efe1aa3be401d..2e5f8b28a414960cd58f793957435e9451be8fb4 100644 GIT binary patch literal 67072 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 literal 72192 zcmZs?2UrtZ*C;&cl_Wrb(4!PVx>BVWsvw8~q)10FB1I4rKoKbcB!pluM@8YF$F6Wh zssbU>tbj@}Qf(7Mwa_6qzTfxV``_pOJ5Ofz+I!DhE35CxjQ<^;=p^6^{NF7bPy?(1 zy0eFGK{kN|NFf*$0C)fd0J3@iS*lGxK!-@jfc`&V5ReE+fnR_6masp^SSB-hi;2lz zX6)XSJxNJS<D`^*z&?7AE1)MuOHEJTlAdmyt`GQoyLc#00{{g23)X4aX;_W=Lp4$Z zNh~AYS|Mnbh&jtmub^fU5C#V=;LT|OXaa9X9t5bBRO#RwSaBx^fiwIVzKp=dI!M(k zm6QNR&e9(mtQ~ouSsqPOe=cr^6)u1xSfw#o3M(7{`(W7;Sc*|GXb+U7s1?7k8DMG= zYY0$)KZbxvp+gGAFCd*Z1F15V>%e$eF(|!^K)lU}U<5Nl8YR=t%&jE?T}F-r0Q?aI zYuc>WY))5-0RiaV16s$ISVK)e|Iqb@=}IhB0gYI5SX`v8L_-E(KSSrYFtwYYFzK`j z%&euPMVBG5i~$%YkQp%Ityo)_uCyBih|x_8e^B6Hjgk>(VqPuqe@O1w!J7PkND7-) z|Ew268IcTP4H614_@fvGg4PKG*qssv@o6VpL~McpZ@<PN8FA8q+IHy*JcAwwNI64E zIm74oGI!3mk^rWxZyXQ@{qJEUWKR5&qi77{bW8D{fmYJMKqzMhJPG~7J%j6D2xFMd zNoh(2$l#A*_Wiuh;5eAV+NC_e8Bu0Jv$_8kF6JH}7+==YKmz~Ko-9-<S!d|~OqR5m z&6!Dze_n6G{1J{Ev?&n)@z5q67>I;6LM31!<cf5h4sFthfxjT7EI0ui2Z*<c<tWXl zIx6r2i~VC^RK5Q{<I|@aQ30ydE~JM8bb#vQ<R|Uz*a1*Iymy(|09bm;-b06|&dihq zBPS{|i5i`BfU$ocD`hVgFg7*@u-HFlEp0UEmjK2AF9@1VS%3J9gZ$w$2GUdt1H&PW z-Xq{B@Q2S^kfw4N=mjZdO8MLZ7&FQ<U<|455yleZ4A?8mA7uYU)cX&;L-G5QsefE$ z|ABo}MoLoR|E4P?ln6)>LLf~eFmM@Q#CrL<?keu(e38n(`w4KA!L^jCfGZU_cmN7s zhnBp3(rHMKy$yRoJ;aPk`47gu>3gGD%>79RumB@~5vYOmBWQ9yS#q=FEK9bL19iD! zcwMe5;s1jw6dJ*Zo$QwW+E^nvJyss}A|xaPr73lS@E1PxYRD@^Cep0sm7@4pJpg#5 zD}V~Xe+GY17pw(L<dr{jr9ry|3_7u_js}#B#xTkgfGf+tN@Ezd$OM4-i&)MG68sUv z|7mnT|9lA(QHa<kCN`pgYJwe>1%E}VlzBx83ked?@8wAa2o6ZZb3p<Izmo*Qr6$)& zDtHD$fr4i(op2BaNRM=Fq8(OkzX|w2BE3jD`&m-C1uT~oj<$d>uwNn#1ZSmyHVS<A zXMs<p445aWq}J~Qz@w7!Whuy#?3PkEsrlcmNhH$FWdQik`ON>E-~4aJ{W)K9CiDRI z=NZNo;w@qsQbUmtD?<1L1S+DMs0d!ufTUgzklJ=c_--PkU_rv5GXfcAEydkZAB0PN zadjVqmuEd7kw_Svf)A47&gM}G7zz}3H-i#z7a)~-5QDzNAVSU$NQl%HJcPKu<$Egv z4b+i<lI}VRP%==`QZiZsGJ+)C#ohk{NtbG`NteD*(nJx<r6Ej;KuWxnGZ7}>x4=2h zP<AwQrqCIl9StW67(Rb|cej9Er-=j&q>^FyFap8%0AqfT0qLQewe0(OCy2prCo<Sy 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℘l^6K<-{kwgb-<uCY4ys;Po;t2 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 O0MuIH|J(nKJMh0mlr&=i diff --git a/pc-bios/pxe-eepro100.rom b/pc-bios/pxe-eepro100.rom index 2ca59ec369fa3aa829aa64b80339dc9aaab9026f..d292e8feca0b63b512a3b04db37caa590ca003e4 100644 GIT binary patch literal 61440 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 GQ20Nj;8;cg literal 56832 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 diff --git a/pc-bios/pxe-ne2k_pci.rom b/pc-bios/pxe-ne2k_pci.rom index 5cb68ab2da08df832be1a5451ad4806281abd7ab..62010cbc726fc5fb8fa8c9db9fafdb4140339d09 100644 GIT binary patch literal 61440 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 literal 56320 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 OfQzC2zsBAFFa8hrhr+M` diff --git a/pc-bios/pxe-pcnet.rom b/pc-bios/pxe-pcnet.rom index 7a54baba1e485a8c97866df5369c0d3392361b6a..512d6d4339b7b3e3ea8b132d261d553f09bb3d96 100644 GIT binary patch literal 61440 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 literal 56832 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 aJJq(+IulZJ{-1Dg#SaVo@00KUU;hWfvWUL` diff --git a/pc-bios/pxe-rtl8139.rom b/pc-bios/pxe-rtl8139.rom index db7d76d9ca41889cb993fdfd73a9f260f0debbd4..67c77fbf73135d9f81467cb36d3d1c64362ba8c5 100644 GIT binary patch literal 61440 zcmagFcUTi^_b58)38}OYdVqi+T`3}<bWuQ&u1FIdB3(!Tr4vv>2-a<Hh`QBn0Sg48 zp(&tj6)cDp!9F208z5~?_`csg=eg(pag*nH>w4FkS?{Xv%miQ0k{$pCfdBU|A7BDb zKv<WH)Zcx5z$ne35CF6Q6cPZk00aOOWc>%6<)7@2kdFZ;mb%-3L_ps8wbV{SEtPBz zCv~-@<*wAMofau+alkJBFi*f(j**#_wK^-yBFh8_-srKOE(b**51@O^dd;rlmk37d zV5t|VSLZ3Z6*B%@)lQUT7HJJb9%v{7-IxJDspvLrD!{B}$_Hua@(#!i4F-Y%VCWwa zqUM=KS_oJ;yF`ZTSNxf~USful!{N}SGthE$wFUGZRoV-wp$lMCnt3_o3|vUlD(`gY z<rq+FDM+CC0|p`QrK^^AB03y;Gsx9?&<#{MBwt3MUIU}Rtzftqo^a<ZuV^&_3)cX^ z5*xS^)-SE6jN}+FfYA-0<>M@OP-4AA_W(+!FL7LIm7uJfDw>Qy*lq^^9>CV4s8`up zC?k1u2Ox%r+^NM!f&YWk&yPFy|H0WWv0K9AhytTQY8@p31<EfM6a%zdjE5hPP$K~H z?cz{ry4WR3Ab%RPo&x`KS8_N)+|Nt63rVPpNC2$I+5-Ss*bM6~RUd$17zX*B%`y^L z*a<M@$YzjG+7hy46c}UOZ$0%ttRdV0T0hPi>tKQZ@ct-L&X+di|1(+9WIbgKTl~Bv zaa+2|zmSqd06Kt_M4})*QjCP5H;6Ox@mEO6b`+F}Jj=!Wp+Hdx>NRR5PB%ux1Uf<g z&_*Tz2F4?dU>zL5dxQ<}2P46fDGnZfldcE4%Ra>;<y*Zu9{3*s(h@+UDIka8BL1A= z&&UZZAVB^kWPm&y1%|c$mlc&-fKeRixKB$iYaGNMT<c7$!jd>LGpsGFEUe6J9jwjc z>|=KBTxo6l-wEUYOL|S108=hg@*>$^UikR|%=H_CtQ`Oa|FoUy=}dP{TB5ldlas=X zO-TlK#c|ViG64$<3qU~ufZ-)|$O14+)eHqn06HnUl7~x7N<}O&DIOu|M?pIf;*CR4 zHL%2_TL{Sz3JO4+<zVCsRs$AbWjzWkY2sikV2gUxGsY6C|5Dz#L^M5NS1NORN(yIJ zavT#(OG*0Q#3{Px<s{@NF$jqX8iE0k?Hk}3RQ{6x#k#-Z)dL{s+!<&&@+>Hjiw-DQ zlZ=7_krEfQe8nq3KHqER&$dE$GSfLRY5&2#Gizrom$NG+dFk#_5)^>V{`U~i=o~qx zpV4K%>H%PVmMWwQ{AchNb7oa52YY5|?rhkWR?we%LF58d4DSFd6M-{xzs~Le9kGc3 z=NGk7zFS}j7^;H}r0DWL*$MKM>?+o&gc=DVNJaur%Ky2*8K?#k1+wksyGda`LHn~$ zp*q9E!*RND^^ENF4-77WIhaz+IvG`r1MX3r6u9VTv}*D*T10qQtN)E+ITxW`ST-f6 z*W5va(7;l)?-7Iq_C0FqKtm`%Ui!1BP6}GPETLPle35+iGhDqIs)S32n;;bQ7M5F* zqw)?52fbbb*j!D9is5Qz{U!j)fj`d4yIgpSoWf?g-huKP-|TPQ6!-Ibn7n-k^aq1M zHgM#Hd^47W17uqf4gmCc7-Uz=8x(mXUf$J}EBPqc3?k7WA{i-fD4^wq5}G%Pry{&& zs8^{MusU=K`!{A5q#{B9Dzk}%pz1e`^kMLThz3-2i5NgdZ$(qZa0LXvl25Z1<<p&N zx;Sd3+?dJN%<vu=gAriZS@{J9ir?d)?Jzj~4n%Z|cVVCq80584LEhI%kk>A+zfFeA zubz4#-i2DZqf!}Y9>$tKNBWx!0RLtPyQ4}O2n(lH{$~^A{9Q6W*6<930hYF<6_i`` z`7;z<kiQ_`W$UT(=V0?!G+5YHfR{6XS~mkWe?x=yqjI?h8<t8a5e6eE>}yzm_9vh- zT|rWclgs4VMcE>SEs+m?lMm9Y<%Vk#vR{<k$3ZOl)RG;*{ts%DT`>-<7vYu=E|rib zET=Q~UpgQEL#NkFK8%Jd`sF)PGR9qYuk@KJ|1ntj7(mNc6^;!qK{bC-01FoYfCi*v z!G}vV7zXkuz<TdUgdBBrDhhy_7ORfR4dw)_a~L>#CQY~MgnUzN=K%oLIR?mmMrfco z1_NOh!@;N}kg7BCiBrH?xyZ(}MiT%)!FyL6o0+sTDJ5+Wb60XqY^>a<?Ao5VlWES3 zjY&>U;Vjt|x&Co?D#%Sv%$~%Qm>vJWfbzSN8%r>F9<&|<{babfOCX}3i-Hn?v|pfg z6X*g(0H9(M6bhvO26+%FO$lrs#>bUmK`)Ru33E1sa%NaRf$Zf_Pax~1lB)>1Ld*Ws z*IQcUD*wxw^Hc6Yc-;svBn}jEoPnQ4a#E49Lrdg{aiBm4<c-gRiv6u}S=$1J%Qaoj z*rngihn=w0Pp*NR!Fnbj!xL~sSh4{7>nz#rUhj&gGqd|Cibj<*0C(1*d8QwRVJ`M- zLEOi0e{i}>y5uiHu%4-=p`dy=j09zNrob9Nb@$gDkTQ1YYcxcH$ru32pR29Eti8=Y z;=(=zu=ewgt0)c;jt!r_ir}D$(SBnaJ|89_S&Lr}LsMh$-Ar?6C!D^<qH+W%X)=bp zWGmM6)=dq<SLBAvqDqC9t|#(S7);rpLl+5%n+7b}u_Md>0Kj;DD0CO@oarRXWoPME zAlK~7b=bMNXSCT?H2ut0tP?X0mfs$(9s%4Vs9X2nlSerJqn;IA{MTbCFf4a%ovmRM z|BAkfmWr3wpD6)s0Abx^3g^#_SwFF+$~~<07_*`o8#;Fi$N}U&65R^JLyKo9?Cl89 zpKb^1<S73~*_J{mu#%$;8ZN?(3vWqG0IVX|@r??UANVT&*Xe>W;8{CC^_baL#TA-a z=4Tu|d#igjmv3J84xaM2yRhEk;%|fu2zv%^6;0KI%pf<3Q2+*y0okTDuUFi8I45^y zh+b$X@Pf8+>tBbytqdaCt#==TKOA)3tV^J%J?OyU!sNR&H?f!!FV~qZOTiNufrtd7 z9z4gXS%CZCemMU#PVUlv;aY?FU#N$@@DaI7Ld%~KdjlWFlIEZ&K<tm%0`b@ELr)KZ zMGI<@-13g90)^&bwD=IT7LW^^)+)1D_@RzY8KBu~QH929rRw)5laExGxS<NMXqWqS zL)*jE)qVJ3o&0r3iw+tau3acyhc1o75t`~D?n2t4MWt7UU1%>AwCAGB+{csPDPA)z zcC7r3++e&8g1~5ThOE{`#nfn46+z#I(aAa)H4Xo7dkc<SO2$)Ji`_-m;%|At)_5Pc z50f_%R)DRikDs3FC&Notnm0-#BR1kuUckKEa(G3|wH2l5RRhvUSbarEQn6ZId?Y?s zMHd$lBjBbqP6~FgMi)Ef!C{eh3{1yFFO02x>BRKbgQJ#gZM;jJnw@0j4hO8VCYQ%s zgT2V5-gE0;zz6`$bEMXeDm5RbXn3`SLN~0Cn*&9|ja|ngA3|d=iNC$WdCC7fJWZeD zB08TjbkAtH5TdsBR%Zukf0hLWX#~azwteWIo?<Cgv|@8uG$O_51som~SNW?Ye_Q7n zXa5kc{>GQ(Ph)PRB*nPj{fIu_g7*<^44HCV)K(|}@rw~>U!2uEgMX&l`Uf@0elT_> zQW%W$V9ouK{OYlLeDEN;6TtoHQJzaf%~_AHMi}MkEav+82ate2=iwpAo`*QZg~e3t z8DE_X_%jE*umyRrDyKgxYg(x+WFC*_5_G7#Wppl}I}kA{xm@=mMk5{hwH1dC0KL`d z73P<k$;f+Di)~?;<cGi7%Ddu%Fcv`}m_S4)P@iP_2<TO+U<g#khH7i$j951iNX2f@ zF$m2)HGT8`m?JuUTA+YJI{K2hn6aL|jBWUgC;<^g08LE4DU464cc<@2=?AmxFi&S{ zKah)>KPec3q9__5sUEFM8ECi$8#T)m&c5eIYJo8(QKlVqL)v9S-lDyM0gVRTgyo@v zGvLI@pDP)9*Wc=(Gd!Ui8X`IB>PUI5m4QjNe2`Ft1vme^^f@xheWGh7L)hQW%D}c` zF)*x$;bP6&71TZ$9ULWb6xJBeFB{|{|J>dz&wJ!S(}lRI!9fYGF_ibm#W~x>r-a%s z&@uUwa|w@{i+VN0_E|`q1YG?BIru+rk?9fS+B7~3y^lS5j{bhjX?U+RFhmkD(?gDo zh%A}%kX(4@2B*1#b>gm{Uj-OcFd7|!-*YZ`&W{8gSj6#F`Fwtr%XIi0uZ>o?IDx)@ zEaL??n=cEw9zK(Q|1NaC^DU=;le!5n7eT|3@JTVFv4vr>!I{$}=a;MoqFODBgY`4{ zH<k&#Y^dme2|uLc_}`$~1EX(Z(sS!9lZab%KHI(5h5m(67IPD8NAJG)39;tXG8PZ* z?}Jh?w+?--*44&-S6LVvtaXm!))vl2|2QkV;f#QKGxjdx?iS3KK2frh+eYqMw4OZ5 z55whCqpA-l)S^*wFc4-~dr)nv*9><R52RSut46*sMIcxCqk%+CyF0)p;yT)Tx$!Or zl;qAEn5tVi{h!2@DNhs-rWAmzpct_Tt1<tt^Z*Im9Xzrhu$RaB=<_ddt~y%|9-*E- z&|oqbjROkh>2TGyQ>Ux-q-x(3a7)?1L8Q05gn>mEJ`D(bS!jU@i?7Jvg67BI`MXH` z-8B9l6;a*T#G+QKAV}MTg%>CYw&J(r;z>gf=U_n^O|VymHv@1nB7^~-#A?N!@edZ5 zi!<T=Vjo3BB8wEy5SGNM_;-q!*oxkV{R{Aa!@!Cz#At*(+%p|1Qd<fV(^Kvi=&WU# zjGDL`XHt6ywLlSVt-!EAALN@)4-H82c0I+b=9v7;|Mv6J0Zciu2KKbWlx}F{HKVC@ zrVEQ}6R;*v`H<Wi3!P}D&U*Z>Qw7>$d%kU;$SQ7xi`qLTnVd2PgtIh%808&S?=4`r zieF3*smiWL!yFc?o<;j~GUh6^_I+;VT$8_O*$O;FXN1MP5bY<)NFtBC?7B(p@)7JT zgp?axgf<Xe**x~%zREu`-_REmL)xD=q+N+mGW1sT-y8s|GI@_`1wz#WiUJeI6TVnD zWvI4taot=izq`l3m)GJys$V#4gWx@`&F8g-h6G|8$eMid<j~^W^eg^*y-A#2C!u#d zJTj`M6uR`jw!hK3spKW~ucm3kVXB#;sS`NS3OB-Q1!3C+JSHzI2jJj&O<|DI2FS8s zmemWr*k^TD!;)@aP1Btl8y^=bkfCf4EzCpLtAxz|yxyMicA?!%%cb4j_}9j-y<BNU z01X}$4hBc@M#0B|6JCzO&^6$gX?Xg)JlCTZ6E+r7qt#xBBC=+zrzm&vl^h-L`>VGN zYKy}qGaN<hC(Y1};;kOq+f(50uorI;&3(-`V@d0u2QmciT5EEU$e!A-@Dv(};N<gX zpm5K&7_Nrl!*DiSKil}`x%EqrE%>7m(m38LxCFM<5*DvU4+rs^r@Nc~=;}4|)#@_s zGx>i^G2hUrU@w}`tS*_BbiQvCLahR6jzW^kM!1J`fB=oyuVC8!5TIGmK;b9Te)2T6 zelhtIZSe<t-2TkzKpf6+UiUCjct0t8C+)g&^r|VGJ?U$h=+9LI-rn$BYes_d8Y_N} zxpR3A?{`B=&NK%ndi+KfAaHAUBRRu<8H2ic@08(s*_s9?^GPUguT{2pV^T^vM~n|g zT@eYANtGA!9S0X6;b!K9!~`Pq$h3)dyl*HyEz^5^vxfB0z_Tu=a4pK8kL}2w_z?ct z{TKtf=rziqs2%1C!=vuBxz&_;wARhRlvU%dZoEHO?k^FVxnZvt%s68Ha?JYabJ+@G zBI;fRIi*f$h1$#|jbl7SRO!UfNW&Pf1192CNhp_-XaF_AZQPV~U8_xW;cQ7pK<n81 z@9#D%NTeyY?JmX#0|ZxNdc)x|zSlN>Dl}1lp%GR5Jto21)zeJ#ac|u_q{GEnGm`P8 z(XoW|C@iyGh=ood-O2}(86HnvI5Z8L0%LzIM`_*-8HMVC#abcGuRB-1$`|F7igPKq zk3GFINaPU^faI#m^58LHh?PoMU_21-QqQbXSZCy;vRj&)?`ai}ZNMq+9lsUD;|^%? zW|mJ<O!Cj?#vPZ~zYG-~d2rja*T+kr)1thl!JRo-`41)-z^<k>;7)J1$i;dd{yyV2 z1l4Th-dWunfArIy^KZ2Tg8`o~oeY_Sfzddqylc*JQJ4zrEt*W~5?_6F7|%e`L!A3F zrl<I`9&jM(hBCs&hUoK3YJMMv5bY+v<w;lTZZdi+e^GZd#D)JQ(r;3bix+NE;(eH} z%PS-U!oyT~{uycn<@#N=_I1XqHkNtT4c#XWl44G0W5n%^6CXk0PG)FE!!O?_*L>=a zaNTLqhE!-L2a8QB5Z7$U6;<<89PyjQ0rfDyC3S7|*an@lHvSv_i)BggBI4d7*dh7# z=;hcSxiZRg4~AA~a6Lx-$E1?MHrg%z3rHGmX`ay1`L-*Mj8-LNc9B~E;5_5!v)yJw zZ&9=TL;So`w~Y4*K|=8RF%6CfglHu!tz-k=K!tdGrdfJ|lEX6KQnq*JtBH8h8Wocc zGZ~u9?`SU66d_g3mw&+B;D}9W*U4zdZC+fx_rs5C7fWuDJdTra2B+6dYFIVsE1u|7 zTGk*Ug4IaM@f95U(M6=#@@<eRP-d#vaX?>z&{2w1?#*ZqgN!k}pOx<dn=lIEkQH8z zWUr#g{r+V_8-^_5ZI2E;JmGEE<L2woH!cygW+sICML?!AoZS9ht6?a83RKRLU!{^t zUnwyK0gU>jUH!T5p{p?h$|qzVK97u}3_yM6xPvj-l@AXH({pN3C*X7~)r${LGLBsC z%5vj-W-Pbe_ST(wewo!BeqA?d{F_ku!;`9!<>`${er#BC>J@?u$!P1e1^ZKO_<Q<k zWVl*2oF4Dmjq*>ks#RYp2yEFe1J6?M%aTc`EGcZR61b~rz(xrWySP#By`26D6V0~W z`W!==_d|S*sjmL&UfR(%)YtmetpSf^TxD`*!&@u)DQ3Ui(B7l#eWzbG&tg-?O1wDv zUClFiqhUND#=Wq$MZ7$}nmwsF@o{?c$5cAnUYm2g`4hh394L!d)PKUl{(ffrUd??g z*(hisq0k=Gx>M4>P=8zI#G8AcNR~`tcu(*+0{z3Z%=lr=0y+L84<=-iNHY$nFWO#F z-yyb_DJl0JD9^Lp4inyaIkctK@Wc9dss=gsoEj%lCCE0yN3tyEaHHQjkT$#8twXp4 zZWyZ@>hj(iH<y>8B-2tvI&^Tc*p>-QpBv&LfGnKVN`tVq%@6NasSGsi*uDKZTt?Ki zUvOLXj-%@S{l~3~>#G%BG_Yq7WeUYl9w^==b3~eEZQeP9$dJ~!Q$MoBzY12b(*h4F zvf+w<eoKG3nfxQb@+J$bZc`t+zHJeOjnrE{xKWVZlBFEO#(EA}Y37wrhewQEds>)f z<#;?3nPR0rFLU7!)t7&CTjTCjn5$_s(DL2xr<G5NYc2O=Z$Md~w^{KG+&fWo(uWq8 zA%Zc<@nD969nz=HJ3sGr|9h=}U`<WYz1=2+Ko(e-?H7EVb3xFUw0#i2*?UJ?Aa|>K zS3NfB5K2aGua6<S(+9<kw$$bkv_qFsZJ{Hqni(1sJ~Q=FM%WP;&HMNjmvK<#GI*j! zp~2@!ruLD}*L?Eq$)J<788`F{tJTwKNEHmM_KZ8HY(9%nZ!%Q)4o_*{bZyOD&fI;Y z_)h=6n@NEE&J-jn1LKmdH5P#T?rsohr5>}p4|=DD!S?K5UPs-;&N@^$x=i4`>?4$K z|NhEdpTbAfe+yUFW}w?@D|N@*qP&RX8Ps^tTwy3NUtsB$Ua%p$fQ}GsRmq?%w$#j` zw&GFRzFRZr!FD&NwN<v^b%RD**H~+r$6$@u-$^=N6xilwLyp6&O3nJvnc&2CWm>ri z3(rTdx^du4xU|Z=nA4j<9JIKYX58t}if_~|nUadD-{DRctVt+7*g0+cPXa0M7teJ_ zSUfDx+pzV?jB2Ze%BQz8-*D~Au$9m8AVJ}!3fNHmtmgHl!cGfClG*;dV)IO>nY_V@ z<^<hWzk#UZ?N|d{BOcKXB)$y_{R^9myx^Fc5*?kqb}#hXY}Kt;zWpy=+wQ#ikty>z z?9Im%fzUS$Z2|S@%tU_}a}N!|qUPs?9K-i+cMS55Hb;@DgOAw8CYXob*Eg2SCY8mV ztc6X~lIuIaJ33=QEqCZ=9fjeRoDg?NrKp>piJe>7J3!wXVkYpl2+{0+Kb4P0tx;x~ zx+#maOq-I~)WwGGTdm_6M!lFV6~(Mj2YzOvG*K9K_zbzBhxz4pQdOpDn0idRm+`l? zsI)1Wcf+8%;-W>v)v5F+hgMIAE~p5P24#$c%mMA=j%n%*AL#l9FN%u7%0C`EWYJ4K z)r3}DRZgJ~3_;O$&DQ;^Ew|A&B*JmbGFri`AIB`8gk87pcwOBP+K0PQW{XYWSfP_R zDsf!0MKA13z0|4D{6T^5>)^W1szq`qk=`=wA4Jy_9Xrj#?ZJ;t*!)UX&oX1UIyCDw z@3T*J;-I#_hWeL-#G~wC?HhjEWR}*-YAb9wlYP6HecFQXTDn+_rx(s$(&c{9mkC}^ z8Jrb(qaw`;KanOq<84L16Lp6Vk7tMy&5@ZWXWvLw_Neu~f8<C_!#XA&%-q*&YPVTG z#L@S7_x<{z2}KE|P-a&+hLP3FF8+>Oo~5-);C!e$b5r@Ct0{TKtYrRht02G1`i|KI zJfv-qP5(mI8k@^GW?PvY)=|=H&D5l^HExb|-~{6nqUck<Tz)Ddbh_P#%9|rn`7goB zBCyIu1KeRcMa*%Vo~$t+M*lnRvQ<2hX|FK$@yZx|+32ovR&hcE6f2ck^0FUh8a{r~ zhP)j9G*f%4p3_q`cK=+aRbd-Vi*zgXM}}q&0_PIq!fU0qqzz)0-Fs%IRAmQ^>dhj? z2-~?UaOehQ&6~tkL9Yc$DnVs;&622lv^M+fe^T#)&YKjT*kN5A@n+~IMiSQY0bYCl z;~G(d8k%M{GlZz$OGS`@Xw+YI(ZsN;yT>X6Lxk@~rsU^oIhLXRC*kf{*4CQVqVYw6 znGeora{L6;!Tg$gJU)!!R&>Z^j&@3wvQ7^zX|H%QefHO(%%{-TyT8viIWy`TwdYM1 z8vwlKY&}+Z+vDaOCYhXv|4M2*<<W*@0NAN1WdD4{mgX@UJ+Tc-9viQPTcX=MS`gKx zXe1sb6<C`*(|zE7UDIY`Gv2w6JA-b#^{`v?%VcJ3e%Ygs|2j(s4%JT=pDIhr4Loev zTiO_1tt<Vp0K>%AxmMn5+exK=&>73NqXGr112o|>R9OJJGyvDtFq6f%9w$PfL2V}Y zRT?aYjx*+R6=~cMs!PMT-s8vz=tF@s`I+52hZ&W`m9366?w&)tOTRhf&B=~y%CI+g zNV+&HZxwa1cjKQitCsD49GyT~Ln30mI@>5~zVWe0!DgG64S#J@TTSM5DsN5Xz_F_Q zPTrr~Jd8Luw6uqsP?Tx8g+*baN#xRV%4Jj^=LJ#ezQSMoij3dI7&(2Kh^3QCi&rW_ zwz{<v%Z|VOY*d>%*rsXOqwU`sN&p>_06j}{Af?f2XPeAF1sGJEZ6dZI8Wt`eQQ@dj zkJONV+EIC~Sw7l|`fD=%!)G_n=s$uNgEhPuwq=vX+5{qXVy{p6n09PUoMCA_o%~*1 zD{X!s1t#I*9vK1)JJ<u|gBNQark%N&i*I<rMpiN*YwMp*4TBNe{uz1o7V5&v7Oic( z>vi8BHLJH-HVhR6J9Kv>O*GItXv;gSSjl3)E)J$<Pj{eA_zuW^Mr}X8U7of$Mp<QU zvX~kQ+b^3zauo%kW{AGKYi~SX6kGZiI^954-_+#lt22XwKO)Cf)r-)m#@ek96MlWe z@FSV$V$pwPh%xnm9`{C4PIm)}6F$1`(N$JoQMsM7`WUM<UrS&cG$}kcKInFPm1VhN zfInMJvha9q$R?9X|3D}pJj)7Eb*!{&%w&y<^Iivx^2g`}DvW4A^!{<O`JU9*RP~sC z!hx(L7Ao^PKHGxRiqo~tgJ)D`V2<s=#a8Ka)w>qoSDQRo5y!mYFnGUT+^Q<uBU;q^ zBwZZ2$GX}-ek{v(T7*UXG{s+{zPV~U{eWd<?N`aaY!`njDwj5tK1tknyW00p>+@!l z@20l<CPsJo``wP*5)i!c-M~%YtLhU2vhBU!F`1*q{KiQp%9&gr_Ej>Zcej$#UZCNJ zTD(X8kOGJ&k&Z#eNuSwfMJjGV&uQDyd1clk7(Ch>FGE~jpVhu5wfnM$Q5H=~b=o>n z&C_q*cOWg5U!*cIeSP4#o3LoDA#R6YzZ%{fb;5_z!9)XALpAH-T9f?#7XIT<nB402 zptZhA1>^IjVmR4)bfTUyPM6LTm)o|4o6|V)A5ir-(fd~m_;)wyCi;(H-w0M1_DuFP z-SnAobxce9F8*@A#zQ!e`1Rt;?#86!>=#Ei!%?cSIjXdUpZ(jCsxIyF^z_D}*Q=fC zbTe^JTkxcKlIU3aS{ThLxcX(_eVV4XbOe1D&)H)LsCe}cuGSk4LA&vT*$dU?Lv=)w zDOQt4qUo!|rSwJGUuWnLv0R!y71!9%b)(B_MBx?I_D(qJZa-0*%g`K{jD8upoO=g0 zz`NS}K4v%~KByUvtV%2T@M?c-NMP17(aB@k3E8I5iLd8_l_MZAUZuvm<1)7inA&)* zJ?+`p?GDEUGjuCZ{F8g+AHr1C-tJayu3Gi>dg7N?X7{zo7|+vxeK9=?fwtc)9xJI- z{xepi;r0dB_}KZ?=ZTD&c*q6<%%Bu3cn^DfrqAX+f|Ao#{RIsQ#FPG-`^?w9xav^a z6d_tTa0iW7YW^xJqTw^7MT0?EN=6Fw2DEDUvCcduKUJS>y!@__WLt(~>Rs;@<W;MM z*HfMQb*7A!xg>=<tGO!6`ga~zU@}<>rz0?yCuf$Id1Fe;o(i+Vh8DaUFJj8n5$}8c zaHq?*seU)^EDdwd$0RF95a3v0n%PO@nA%<x66v;w`^UJol+n)I|44H#ohd1Ku~Hwu z|MPjVXJwty17)4kBF1u*>Y4!x^-!Z~4BK~C*_Vrtb%?j?nzqKMU3+UCra_-_4%7Tm zvuiq2Kz1r@K4aUk|F3F|@NomPcc1RjU^1KK6_#ez%50rm#WlSXaVb!w(d-Cg><iRZ zJzkR~m8f2R_NMuamfZgas+^7|Y`<NK-GW9w{ES!IJMfX;cKJg~wg4CkL|5+IaZsa> z7yIUMIC^XhD+?zSY4gX8pM2F~ppPM#*`of#PuiSA<JWClr=3wZs|E6ARM##?viAS@ z_oeNlJ5&Xjl1@bbsIz%dZGtFVR`eT@uxr!~NzFzQP>xrwbA~c%r5O|)<Ft)B5py?A z^M)#xRk)kd`|f!yo>4#`FxbAm8NGH?h9r$dEK5s_>wm}9BvbhWip@&LM9oo(65~c1 zjrjcBSmJ(FMHZ!qqP!*Dv7d2-pu+f#JV=R?HuUdi5E0IKM8h4mU$>mH(X*v8SG0^J zI%aFn>uazG28^P?=jX2JQdTfFBluH^acZB6m#JE_iuEbylBzRSG6<=RgyNfXwYu5P z9|49=`)Z90;$5!&vnzmVIwuFiHCuztd)84h-0$i9p~P9%CNX66P`)sxdCs3=H`(_P zU#Wg(0bP`@xPBp*@s99~@eScDsUB=LRAx6yZp?~Ffab%~`&Hvvo)QE$p!3|fxeNno zy_$${yY+IOxF@&Bm}R^ID?Lh!FwEODEhPlLT^4+<fYNK^H27^-#ct_xLP+<Xb6<ak z!6tSLv+Prwel9azon&ogsVvDHsuNQ-7*XWsAS)!>bZNOmb#t^U1aYY@mg2*hZq07k zbl=~S@W$S4|HLhmSJI~E=57X(wW=>(<(@-5<C#%bNY>>H{mj)?qTEhBd4X{8r}K-S z$8MI3%;=%enxP`foFcF@Bdlb6)6W#~a$>y1)|?h8S=2Yr7Z>q4;aUVSTGd-p`6o}3 zNt9Vhwkj#uN-T)@x&DC#6UhTTtfB-fR#Bo$GKkwg*M7q)eAghZ>h!$X5RY|`Zp6%< z;qKDdhJ||=k8VznyyK6oHQ$zLT#eSfV|~dVI`wvo*1cIvx7NZe^qqCD4`C#()Aqfa zWh;1DNaai-8S6jxt>|BcFc)NL<?$hjJ2Sgkip9stkKIZ6015Mc%BXC@xdFQcRUeYP zk+&z<;4|-rz!pnS3A9KS_Jwx}!qC_4ao$J|TuO*RUZTPU&+Esd!dr14FOUljzaZ(S z1&3)VbVLjP?J0Ju`n5b)1g}|{we8d7Y_K?fc-C26U;cD$>s$>_X}T9QyprlOAC!{N z9xWr_ld+le@10Lr*ltHcEXx&pXo;5Kew5V@Ym|pk_Efm3KlTJ(teB#0fJFJAH#cir zdHz-HhRpE7dks<^t?)*Mhz!}m|K8lG%foopDi-CgF%uv&uKmTWZSpwhc85xDxMU%J z?ag(=iO<BVXsoN-zA#nLm2qQOXLwGHIbCM@6y;W}hfH#Za_L7N5e%je?hRCG_;F;6 zfC{837r4_!sm<O!#^M@$UMtouPATl`^!gK6gR5iSyQgl<{o;wR{v47AdZi5KUsXr< zfzy5q4=$`|QXaYrTFoOeb#H^_bV<^By7MeGlcqW=KJ}?kz^d(LP{U5vkUvYnka6<{ zYEw-#mk<`aXI<;SWrRC)QUIzy>y9;jw(m;{!LdR6Y|(KjNC(V8w5rc(S5_KT<<(T` z6LXmNmfed_x5()Cy&it?(dAQ{c)ec_x<`#&mm5Ou@V3&sw)5G1%4RxOtzMP?qjFo$ zbS}<D<>3Wi#Odv|=n|M~Fse*9QUm3WjX=}Yxe52e71FWQc1|*jLfA<9altJE(}?|u z#g|}dW|?8|=T}w|RhMk`ITW_ehp8PIg<M@FI<U@pD7o@qbkzgGqoxZ@Nd+O8J9etC z<<Iy>>vDDfeBqLH95K3_;V{9&P`)ET7pWD!8$2MZ?83WLby0%;j_zq+JK(EuxTdx1 z<d2V=$aD>KLo5HefE8UAZo*J#yx~%B_NgfMmm`My$PZP$XXIhsJHowQU*)UdjDMrt zK{o)Ng$rYthZ!I6=PMh%4_I<M-Mk1W_Wh6hdOTB3mT07kV<Ukbo7bN0eNmQiT}xSo z8ys?Lo!@+Dfd6K;xhXrXdg3r*h7|}o`kbHX6CJ28;D^lTcc2lP1t=>S1d-N!!r*is z8HY#q2)z|7tRCC<BI6P9e`&O~2}9q$njZS{jpzmCy>ujPg81e|w%o<WMjy`(=Z<mC z=Sm!(clVCfXc+)#&MxkM<Uo^@1Ws<9%I8By9}mA-Zkk4#LLh#hFT!Co1+Hk6JHv7z zMY{kt=a>t8R2(|ek(NRyY~P~c2F|Ca4sSDXjkD}G1IXH;CxT#-{E(8=eMq@CFTws0 zj7ndHbV%1qN8z+m8w<?K2zwS6_t~BR?B}AGC4J?S31=3NAM4@)fTX+S8KP{lYKMRq zULO5;AJB4&Rz%BqWOe#bl9{HpUi1UbSg{r+jkd8tDQ)qXL&D#rVuOtZ0jFE(>NY~3 z`tSrNsP4$Y_Il#oKZ-4<%R?aFg{F;Ahv~-gEec_$)_12NWAp}Wc;%gqJ>jvQs4S`= zmGr0Z?LY+#?c5%uu;JF^=OQG_Po{t0aK6Yu;Sxj4RR$f}J~uTaO@iKBf+}K|>0PtX zPV{SX|7M03f1gQ88McfP1ds&WWOs^5&$<i?deX&n13t7Xs<ZcFZz#DSsD+Aq(kZ7b zYU^h40)L-CGZ**!%vk%$btD>=>{uIE6}P9Wte>@7C$_mj`PbiNHotj&+NL=y=C!>) z|JiJxs(l6heu}^2@xIm7NL9~2HB63uU3Oo5AnAKg71j{ESvW-ajgdb;*iIp(B=ZN* zENeZ`u60&4gS%TqE%Ng&%Q<Y5T4*S938B^SjlcJCx06<JcNZ%8MMCFhgoyI<4?URt zA8Uix0YD@276bcqJRR@tlx_XeN>zI#^@KR}IjstRS@*ZnySpKcgv;Poy+T7)29EVB z*l(?1Ln5D3_R4#2@09rY;S+d&1ti5dG*IW)5VlI-Y{6?!6dV7(7jr;6RH?B2D9t)X zk56_BkCG~s)T}HTsLV*c)K1@9<eu&${-_IwJSOprRhBQ5wIU^F*M>RlMb%TRE(90R zQw*yq(R0T&xV|#$HaFxe_YUDp+agpm7SmAoBllV}f>yc#hr=V?2v@`jiYP6j%+Lxo zBDhcNq7f}^84CF0kHL_ahyvtREmLyg@`q(1EcCXkz@lW2?q#>}v6XKG$;P)or{~NS zCwsY>y>`bA6uD~cdsKz7*(i=^n3<~)!@_J5uWi+3Kp3d?me*tjZ{`SoF4VZ2;oL0{ z7^|aQYm2E7t%2_TW>YTyi2h`rkQHA=-?Bm17rCxjgOR%mQl!{Lx3$H$9&|y|u^7Cr z{#az23k5|5ay^x(gLH%DqAY#Xon(ScF#!;2KH0(T8ld0ebDkb;0;44_-Sqs<X+*!T zJKrtQ4Hj<L<{-}!y{pvrnqfy<kjM>g(AiLj&yB7j8X5r5fB=39Qf%v_^5ZmY7R}`C z8>W|K+6V?)z)MQ={~eZSO|}tW#K>1{GtOg50E%PDeHxGl2jhj*kVj24ET+DlyI-{V zhZiZ&R3z@N&|x^?vEQpv_yXJTbtTv{rfcx;n~3)bxhGL3C@SgR<I-`K$qPJweC^@r z=~|=G;07UHp>&;JgFldyq^rV?{dKcqFq9#M+#TYu8W$E?+T3@@7=ln=<@aW6arZDi zS>3b==|t5uvKc+NSv^5Xxjqp%u~}<9iUvioZMU_teK*GMx#JIYyA_Kw(La?6j-9~L zl}U6J4dE)6W6>V(Qyoyx)mEo!)YBBpdk?M*{`WifSd9id7=h<```3CoW4}W&A%lmU zFpE@sHKRt4G?o*RgLOjv?9Eh8InkK7HC4Is43>1q_hrGHEV!|pY>Zc!E@&t#Asv*; z;{rC9c+rD~u2(XiA6o5&$0znEARsq~r)j@v$GW4pX>Vf~P%qT`{MLhbE)o}-!CPQ! z^NPplS2cwt=8@?2hg32`DpTt=`5$iHp@J5uC*;=g|AJ7vt;hIUEbSGziiO%y27245 z27jCVDE-k&I=WVCb>zTmR3CgS8v6IM=QSmV$7yYXHT2ydj8-NTWIJ$|YuQ&{boAC8 zLHmuEiYRs`f<y<LWc}L|v)#hHeQ}E6_qFY>_^-Mw$Z60=8#l$!_2APR2Yc=qUxERQ z>mp6-h8pDc7e@sqcYb6|sxFtlKRbJaLHxmHZH)Gx8%*`q^g0(5S@CZ>CK^ePLIyyu z;CIIk8vLQP)OcGv{*yHwSf|Wxevxs+VnqVKcU71CmAdHDmWQh3j_QiZ3y()gw&t6A z_#a6H`cJkU!1i8seGuH=N3^)`P+P_NM>%qJdo+M!AFX}9^?5Vzut0}2OK`31EBXPw zdFp46X^y(bKbX_QcJ=d<#I9`B`0+^{sB6wL(s1iy^GJo8161}yq_>fl7*sdK%_-y{ zB*e$@?_}EVY1_PO_dSimmQ`h8Rz(Dxc0ra}cL*M<qThZjadoT;Lvj@{`OvjGZig|x zKCJX$R<_-fpF71w?IOgFID4aCdQs9b-0)G%jyu_fWZSFgm25iF>G`uikz1E{U7aSg zb(O@2Ov;?W_T^yU=Zs~=Gae0w`gVIL**xmM0H85%_e$&FH$7bdzs@Y$XWzX(w1&Ui zM!o&VJ99eI)>og7(WrE(bR%)?HX+!?uRFi@Kwj!Ct9VbZVs42SZ;qKb;W-hRDnCQh zR*W0Ye(FhbGAbE3l<Y*@{^RbTtEPezLAhh6la=qzy1_F9Ctt-{AS0r-v7jG%(DB=N z>Gfp!F(J3Er!K$*!42N1AVXuA?256iA-XaTg$e_QzfHX&E~Yc5Ky>na<Fz&<stj9- z^KxQw)Txp)Fm{51oiG`LtZ-YVySDRU%@#3(eE~n(@hX8^Ha*@sHy`MWWv$=%Hh8_2 z$#fX+<Kk3wY!6ZE;s`t838^c1g_Qxf8C$4nRdYqezmt~Gl5*Wcnpw^=K{OL-vVJ!- zVFQ{qWHP}!5<`->d=dDfNr|#Ru7_IIxI0(Gr`_s^I9rAr8VvYxS8d>m@H(_TI3Jd2 z7ytu{Qx4PV82d{yqR<tVBHGLRCx&#~9939p{K7|R$^Er9gb;mhZe(+(nq{|w1arpA z*!ux}hUTMnoX`Z{kG6cHVPsLyh-&jPTvpu6L9v)#!Cu(*HG4)yDgd4)Vv(d9-6FMa z>Zi7tYVY;>kUMPgU@~{I47JC-xM_ALLLWPI^IdKsMyem8WvXgcHij}eA>57VR*vAQ z)^(XY>iu57BP?dV4Bcx^aNdM_srGf5{6(E>VaHfDe<+upUW-vu^llIzxhCbW;_rk` z(K40sHtA2C3LJraM0@hL6^N<_nuetY2qbYI!8F7iY4m~IIH=CXBP#P~)~x1F1R|<W z(WJx^>cNg-H2yF=CxysWwHGI{kQyhf<#84?fB!8v`~&F>F`O3i;thL3Xupfa1D{A+ zk=yA-+EmqW^U(v}pyshuUDx6&b)@thZZNY1pKI(TJ-qIl>wY9Ks(hsw7_<GXCEaCw zNUP;5YZ$Ry%cZr@N~y(_ez7O7KEgD3lyFYqNhs32(JiSK_$o(TM@kow$s($4VV=Ud z8N_14Q1jj&<kuTn8KhJwWB%q%FQfF^C%let|J<6w7i7@baqsLqq{>2)_zASHG-7rP zb8<zmUAj8`$na}v*`|XZi-*F-O*&&-TECb)J?$?=7%pq%Ar{n`{HKCk$jq(lfw`tm z%g3qL!klkcNDcSIn^S^6@9Ya-HLuZpB;D`x^U8fBx_w}EL&z^;h()VGm${8?6E3;o zL;qvS8iBbV2i5j)<J9kvQZ4i4I*`_bf9-Jwj%trJQA~EW$gOYifc485!~;|0-}_pX zcl~_qiL1i5@ILv^G0Lz9i<c!biLz8-W-`C%m-`PkX>=Bb1@q(_{P8s=eNHX)9iU0- zMLPf89u<H(I1whRxAHy=JWaY+bl>{ZrM61acFV=4kb@nU!>_KsCLlhT!3qLa`qRF= zx=ZUn9_>2;=VyE&`0vZAI#FHJB68_=lmuN;%zhy=he{U<osDaoV$3)x&K58GYsuFZ zsI!Tcl$rkclJ}K*<cO!0eesi<jvkkPb|Xb*{ysi#mnlR2ygU`aL4ubHK22f{h+Ght z*6%@|yFh-QX~LV;d{q^MzF3j?yWACD4Z|rD+3OkSq_f81oNVESF5VwPrta9l`K#WO zd+_ZZSRldo=4<*roI+yPRXpP8aGeY_>&R7dVcf|r7Jtd`+VYpP^YG}@@foThn-Sjp z4NrK>C&-Mow+`#lX#%2*>M%PdEEFo#MZ%i{h|M$idEx#IT-j=Vm((y?>5(^AK@{+h zWBj4OFmZ3#<>4Mz8L#zVV9!fV!oAI-kKvbTh3ho3p8M9MeUTZelDD)HuW0VX!d*!6 zvYf7foKM#MDg9-Eb|*SE99k|r;%<((iQ*B|ow#RDj!2#;LVH^ec7KY0qqb&5^|u8n zC4lX7nqBa^TYkdt|JtU~)JgTOawA5~1U0&~DY{=gzpKQalD|UeZY8kg3<>z@RtB{b zQxY3e6<T8zAL%6ZNOuUo5TkU=+ao--M(Eb&%tJe@mCe;FR(*cr$d0rTXsfo3)=lwb zk-@xiE19O}S@Wy+i{8CJwJaF2lijTNKZU7X0o`?XZ>0^oj;eoXIO5E0qHIfT<+ptZ z4@vTGCahS2?(uam8){YDM0h$b^$jL~^Z36M#~F&tsuBg+h97UA!#cF&dlP_ZznXqB z^{nwS{>Om&oc3$IZL@vQADV&k3h#^2`Rnef9Jz`SJsw(k8GdSUJNA1U|5ZSOe|_mf zcI|HmL8Ak!a+Sj*hoYHX39N~ST9oMIJ#P|`w$Qyo#y!0F-@B&kyK9ds%WR~+3iqp< z6q&6ij<=isl49n&px|Vi1<Q}OjxUp$`Z)}7FbzFkUt8#5{^RNnc^H!YFGzXi+IC*s z$B|LLi(;(V8-6dX9_n2`x#K8}rtDHZ6}@>-cs<b$Cz+kl-SBAcxy(ouXMxCZv{E|2 z*%b)wU-6*YL<87>Jv-^o#%!|r@z%bXuG{+$90RyNK{fi7SLeP2MyEKs48GRD#mC{l zWeE2l6P)*Ev$0XKAU)2QtcySC#5EgR)6Rdh9^tic-*+a-mc7z+^_Gysi&rCKuANrg zxT!Wz@z!sfF9hx3&^H(j$9?L8k?x{p^e-3m4~A==*YNlt)805@mNxYMlt>!N?$d>u ztXIH(-CMV4b{Ul;RB|Bm$;uKuS*@hq<dJP^UCf~^eB*_U=VrPv-Qs0Z_pd*?_VKAP ze_S-rg%>NuCbif0dPZnpn;DywZCy0rY-{+={bKa+Q%}Vil0e;XvRf+K(D3WYi{dky zPdY3brafTaj+=c->jYYo?H^KV-OelT<>ijX=Q34x^k;p3@UZAuFMA|nG=W}lEPmL> zR{8Z!MV#%CcakO?#*L8kRi>kPL}qOD;|*a$M806XZrNBEBn$2rZ|D=)qV^NthAisZ ze!bPd-6!?3r3v!vxaGr3Yqz4u5cvkF9JQ{kZ*Lwy$5BKE^KF_vl4|@V*+Y%1%3^5O zc6PRJ=O{KuOWvHzRZhIp_qE8+p^GZi*l!nR<+aJ&S8-Xm>P441=U<4AuT?lSI`C~r zGoaHOjBe|0m4C5P^fU&qx;_hk<JPabzKfbU+}~%=y(EMyHdW>C{Q=h=WsaAj6`h<t z`U)_{0n;*tVn)%KZ#h;yZYRjff&bdph4+*H7&!VK$nEhE3Rjt{-X#xklnmUEhVj*^ zR*JRu8>X~5IaSxuY+d`4<ZT+M+V-&&SIEUOe|01~R&3}LB&za=#2Y5+YC7PHTtkp< zQu9?-fCgD)3ORlZAvMqKH|A?d)dr6(&s0@R@(n0?vN^7$<~r_<)N^gBOWjKJBs-cd zO_Cg`2s&h#uV8@~x3&B(ZYTVdo+r7v7C5ZttdKZ597bHY-@d-vKR1}Tua~bMF4BKr zDs1`8PZGKFwIfT9{rbGeHdsanv)(DO)UBVGREceaYb+_bhQ4Pv@1rNiI9QTB9hZ0P zx4fseY`Ky@JBP8%f_>TDQD(VO1#uj2Y?FMMgLiFQo>N=*#Wk$zo7K4~bHf6k7eAlK zP^K}66RLyiyzdz*r2)5o#>u1}Z;80%P2zzqZ}JMZ|0Po8GQG9B2jacn*pLjYwtl;K zXvE79?yjp;>-~7%632^XEj+<5!#fAtI(zC)9K1diJyiND-iL(@HzrKEkgiu!M!D4G zV+P)7b!?mKFW7vA^-%z}HoK_6P`l}N(EcDaI;};PdLihdD2;j+J?WVg7>ZbR-}CxD zX?MoT@GJSlrypz+IQK^B{AE_z5S+f;;feaQ?Ne(CUad?}aohfO%+6WhW0SoZpO&!7 z17V$g`hJnEnd{KM02Zkk^mBwNt2o|kt%ksF`g?H1>t31Sh7Sh%`O%)%D;|Be?&tUV z{hA`IEXY!!>Q|;V`44~}?jvIHH|pbQt|gPr=6|uxoM<aVw^DbV;>D)^9dK}hN4AYZ zT&b*npo-ab?LGZ({OS*Uu;unh@oAZhF~YN4xe4>vu`b{4Y714bw@($TwwBToVxJ#y zt&65ruiVR|<QY6bK|d&IpRwt*q#`?xP<N_TUFr3cj+NWLh1b?oWf;Ay>lYxA6Qd5j zzQqz5K?(6vC_RWi{9$Z3`ve7N7ASf|c;AtvlCp1yPqN+{;_R0FRv1`0uy?onrlg-w z#G;5R&K%RO;i^G$W7>A0!CHibyV|=n)2NE2Z~5Bfi(-a(_nnRv0n7`dqnV6Lo6|>Z zfhRO|dVK5sdtN7AZ+bX^H$`5Rj*#D}E#Cpm{XGo5T#;CiLF3yu`lBl^6qpV^c3@bT z=sW?&`*fOa$Ui?`>5NDTrab3=KUSCQV`!vV@qL5i7E%ZxDhw5BX+*&ofn`I0>}2cl z3kUWQ#|zha*S~EJA8j~!tU{o~z?vxcZL6HxuwOCtyPd3PQsJ3sy{%H+oTNxyYsHn7 zFB=|pwPyDwOW$n><PSkdx9px>xVCKwmy(Ky29?wCQ9O6+^f!-bKctib-4^L7sW-{= zUWDAn4>)wE!@%5|nS4P_ddts1L4b-$3$KMCJ%rHdwct+twKh}V#U|`?nPy%7r}^cK z1~>9PMe_yVuiAKwaT8kOxD&D=sy&kDq7pvGZfvwOG5yKOj6e=Un5*n#>y`B@-;VdQ z2ecUkarM2#RL$9de0U{0@i&B2z4v?hsP&exw_P>tMgxa67a`e9&{k&*hg4Z;@4NXV zB$)$D;>wc`Rt2H<vNTIiq-6&6Lg;CkzoZUOyY+qiDxmidCIS1Q!fCG$asFbzhcGSj z`E^x++OKO}10(ob>LYb<zL12Rey8_cu-fE>$xxPyOo6}HJbu%Ea!6Z4{?a9XjWEyt zS2(+_BzGhkZ^pu)_EM0#j#&!L(poN2CqTU?iJD`g9X4)9#fJ+SmGEGhec_*Y?pf=x z#(|;mfeX!F{ygTD6-He6T?vn;eZM}G1iKtY?z@p!M?Ge2?NK`0QulE(sXr_<k$hL0 zv^!$FB>$gkWasFj%vxX~U?BP~c*cBsYSM=k_C(W?PWSIeRjKYWcHNq^tz+#ZzvICk z<?{QD-H-c(nKQyY`0OK(`fKaSYlZAhM!S$%I;lc6QX<CUsg62=@dKS=8oSm#Qnkl+ zz=F|LF5ObCUmz=rpo+5mq!g`^uz)f<Yocl;-7y}&xQAG`Pg~7;>XwaAm|Euksd9{1 zJhPCw3^%Wluv;sbpX7=EQ(xf3nZLR{dh+SWn+adi2gO4gYn4UXhZK%T1^9DEQQI-! z6{DL_l-C*WV&T7i?-w!gx1K@~!tQ_C@_ruG0vi?jl&&Q6thmY@yP1^q#Blp@rz|yh zJk8nMcI!;Yv)Skj%%jlCV|6`u2`=_U1cywN)v$0zn2=7O-flN^m%S!4n!!u=bu``_ zzkq%AYSfoeuRz~OmVdchoN_4HIi+#TctfV0D`y375mi&L+G5zP-~-p#tz!?NwZv__ zQlVq&;Mpy2t}ZC<8*1*Pp{M3Ytisxm`W99{c%lC7YU)GNn8BVF)7w_cW=9kXFXW1Y zR&6A@$W+_$Bg=+uG@Y=JYZPU6Gsl9Fx9#umx0(3IfBem$<M(`Wkm+1d@JNsyjLGrP z3|bp(EWY0?aSMfd>UGv=s`!{~uG-ribXG|P=OS@a-kdd4{L=3k=70s}II|3jD5~GZ zL4;P2Uqvz*Xfo65YFrUIN4w87VdnKOAo<?*CU0Yh-P6}X)~|E7abutH`{!(tH|04^ zsFWKKg;cr4M{2eDjvBZ3zJ0+*#UL(ckXS7w+PU$f56Kv*hfS5D&}9|l6SiXedpC1c zm&#eZQICUG8M5?UXU~d==T8{VC(Bp~7>=UxBN(XxY<0+`)y3|s$>1swTF{AZBnvZ7 zNV;>m)`8T2H`=%r$QoEUma7UP^6l_<UO)U%l|v*5TLmK;=3C#~Y)g3{dn&&0Nyczk ziJ;agIQS^CQOZpOG6ny?7&;GssQ);Q-`>aJoXwfp&fYp(R`yP)Bs(0+=s4tDC;i&n zXowUgJI)9#QC9Y7d^tn|5%=>yd>)_A`}2N1U$0jfPsnl>nK09^Grit<QX}Vtf+^^1 zgpggBf`OTx*av*1Ly4B(l1KvZS*7Hpq+ko@vkVBNzD{CDMH?v!1JB!tc~3^Qg1G4N z(e9EyGO7InLMEm^YrEr$i<G4xvm<TX;OJ7SW|+p?KM;)<1LEglE5Zu0JFa?~b}WIY zL&!+p`oQuq=%nBQSQGH?8+?=`d@n?Py#Whj%K(VKl#QHtaJBBjy%S;Wf)51cA@r;| zJ~T-3_sqFL2q!Rwzs_<If<3w@6C{{5_b;s4%UfSGOW~k5CYugxljIN;{~^h%B$d&p zBlhGTTVVM<Pe#jjl<O1a0^nG>ANiOjK5vJc2GjZCPs0?EFx+?qZ@j<;!OB=-(MI!O zhQAKz%FeW{TI@30O<vkAb;D35mabmhsVlr+xKZ#Xi5Iw1*Y7BxJZ0>kP(nh)G+WBF z&pEgxXQUj?`1DMv$3_4b@ttOYi0IaMqv7QX(rO-8>MlpwpQ=w%g+<K8ao#2&O=uyz z8DCgPH=e{;%pkEc#uB*wy&+_8p}jq|@O$C9gAfZMb>__Y?wQ@`g?Vmf)EgWW`{C5N z%_OK5SK_qyoJ6WS0_rXGa`a04wM3Vup!CF;`e_Wx_-DdEB$2lIXsJ`{^sIXnfL)_8 zqX#n|Nw0a&sHH#M`$Q#RqDq^AXULp4$&yg;nFpEeU>=#X(CBbZ4h{c^;}u)1I{Y4F zB7O^cM%3S2`<br&{?*3-|9lnlhpd0^_Hr-Ym8n*r8~?N~FxaU8apwrM@r$Eoq0zy5 zqI8nZVtim%ellN>fC8|ku<JRAGPWWl5k6*Z&D;;LESj9Pu%5=Of1CcZk>@H3IIUmM z^{eb5{*E=Z_G7>+kD1D>`D)NRU#X+Oem37RjsjYH(hX-6?h~jDoadW}hO)9$8-Lti zxl`PB@Ox)&5AE=n;*%vKW5;`#EOleZY)=3@Ow^MrpLLoT&ttfy|M{APP8YCb{3X+# z0k#FlRx2T~v@2oN3&Og8RPI0>mN{^P{}hZbCqi$;e8ktym^$Kg9b(-mwy)}JvanFc z3W5JpYbqzjF8_JYcQ~D~%F@T$l_s}j4aXjPwp*GBp%INsC9<}Y!j|g6iQ~bIkpgiN z+ewzyXS>3%j*h#c^6jf^=Tq3ffGJ>U0ix)6y26gH5Mtd0=B;5a{JF2vSmWT#+D&es z9npOKig$Gk@++c-g?8*vsR$&}*R41Vta1D!CCm}azVa2zn<AV;SminHpW%fk{wJZ- zhBrXkM$&}Lz%)jzZ-Jo#BYQan+U5+~pkqzDOn`OJk|dhEdOc$5&6+R;LeY-~Dz?%a zI0^@>ftN99#Ol>imq>gT@41|DRQq>>;CJpT52o~cj_7xctl`T11fSCK<8*~X5Q`nV zT@GEa-ka2d4#6s`h*qxDTEC2WOgXUj%ZJq?3X03$q%BO9wAgfF@pU1cG-)pY*rBDk zl@MLyrQkhK0(Jz1U&T+n`-O>}VUj?>yv3!qb!mysmB7C$1bC7O=Snq5-{6Xy!{NdD zSoJ$R{($`<3}Hnf7GeLGs03aoY|q{zW9D8e?E5xoxO1?s2I-8DP;&H78I*jvbxP2x zVfqx5_Ys6Fo9$c};C1FPUttg#qoWNDHLw3DxzX|BI=|~9j?7jQZ{Nnv)!u$_2<Wi& z_UNe|@>QNyow^!G2Ij{8XiV5cynX_luYAZ*l(qE;(qL?Sc@R;dFp03)^_fSBpm0wu zkNmu-t)4&VGgZKdNl6q51*9d|c8X(fNikNnf<I**=$s#VLVu>PMo6;(&1qFfy-RlU z)h9<neE`=c-_i%X9_hAyAHa{u(abGQP8KL#_;%le0lXvURCMCo-}a78iV8dN&-M7? zbP2muNux*4FZPR@Oo;K<gIg#3;mu!K6K!^?@mWS)hIM4NlfvQGxv6?N)7ZLKA?QbK zfe%Ij*SD3`IZ(OYGm@^oMYoHUOOJ`VI&2(qP_|1Y-yxY^ZpX_M6+FD4;Z}NC{m<R0 zB6<F$GgmuT>vk%WQ8FDUkT)yBxVa<OCH9=cc{x@#qx;rWVdM*V%jracWzjC5GND|b z`Uzi7C*SWa9ZTIy^H5gfY*Xn0_m#?ej~`hhj%d-HIu4)AFhBK&mGOj(yd2wa3E253 z02U=`4pjNb*!@1L4d<Cm*c{WD*5aTRZcf2XMwOekO{#qxH<4ePc~v`aR+h{vXa}pk zk=``>YH&CC;?8a_ZGX*Q30*bm>0QJNq_h09?P}->?%Cg!XK~{{>bD^Osv#@Q&NVy5 zOS((t;N*JXBW?XcBjHNZj>ysh?`q;elk{fED{f(1Ga%R|Vge>kSp}+-SDMVdqR$Yq zM))8=oB(s${3wgrulJG6LN^QF$0gk~L#sHx<q&_!40X82hrC}h42UFlE&k_cOKGu$ zRosKO=Ksn7X%YtuQ&C^0f7wJgNK_tU>E{<)dP<x#mo*_zN+OKI>`qx<yIJhE!AV6Q zFr6<A7Jb^)A$XC{FIuQPuH2OhRcz-^u(=#qD(qHIkPqnAoH}mYO&fFh^--Rq@2-SI z*r`S5yM8_Jy8_T}TzP16U%oREME=C@Mn`$5eG82#v%K#0A#&t#6Z`&@t$>Zt05%T0 zug9!cKB%C59zypBT=E1io@*?(Nc|D3xXow`jEw{XW4;3WUs>wB?Ga#pi!`J^$MylC z+8Q32$T(`r5go4Vc-WQ<vz&v6cYfpY{g+&3H4s_z9=#=)jmXXZJ9EoC^!ZQMS>To< zvGjhXO}k3_0qCf#_|)Z3i}F!Ifg7wae@5Cb8ABT^>}8r)aMRHnGx6nzwh>%UQSc}T zM>I?Ex$NhcwQ|TFe0J0VSmKH(uU<4(J`)$1F7h^+AQO8cT81{mrf}+#jO~0NQNNFL zX5XCO=H9%Rx8J9RA9b1l1nf4aa(rO3n*?Jea$cH=@?TlVakAO*Ns`L_gMC(AtKyLY zSeS>JMOGcZ=_5NZSHb5C>E}#=(ZH=e|LtRziq7lf!aO~N2!3M?<a%{3vCdut7O3u& z<E%p_itFxBii^A9slm30jUAukrzg2e%pa|S_d(;J7E5nIScIrCAwr13M*IPW`f6~J zdN5#ToHpE`tF$#}%TMT2ZZHL|2hC(s(oI;{Cac-F-em#QS6_FJ-_pit;z}A__`0NR zlhgIFh?*Y9U7#Oxha<65kxJVqNKsSHK-Gc9Jzk*XSCiVS3J;Y&mGA%e+lkTmM2Ca; zfZ+2@oz?`&=&}?Fh(-;m55`BuaZo<orH^#wswhG<4&|i*hO<)QhJaZ#xZ8fhcsl)c z;}u-N%{XQ!+IP}+ZYe_RIV$FHgr;4zpb~>%%V;YE&#KKyJlppLf29b|EF!L=mZR^< zH@mF%Lo9TEUeo9=U6No3{jt9$s)qC+a6r-6Ls*5#!!8hS2fvunq)*tJ$CkbZ=8Eef zp2TG->@b9^u8A-I$C5B!ts=-`u9f(9&`1Z1-}C-0DGzJ3kxn-Z`*pHYMKjv*e4&4w z(Qje>K5v^;x%@3Mv-NzDN9H^!-N-J}fCS4dj}}oyHKQ9>^aS~_pzDW2&3$6A)L>?B zV31bdStiP;IcjKd*0b1n3tCE>al)Sq>BzJWh==8_A0(c&KJRt##BjhhJ;4O4X-tZE zd6a^$rcnQo;!5@zwyHl(y!p}wnkO_y&{~utIinJO6an!>&!LYar4wYqZf1}-km^sQ z-0<Ww+DU7iQcvyiQdStO;K-KCZro<w7jAMsOxpTJ0mMurNz}|FiI`*RSUr>EyOwhj z07GNz6Ye3bn6lh%Ar1->|7(7nFGXfGq_@=V;$99?yQxRZST6zgwk-*1G!N$xvahK8 z^(AG6cuPLo747PG{rwjPR7FCXkZv_}^}*Xm&bt(7y_y5cxbtrKNZ2_!1JR>_E)^mH zPIixGUI_Iu0gY$*AKp``=wdM4EnQknRebB%JYO{8?f0kl?gE{^arc1v^@C1_kP@HK zKR@wvM*<8(@(NIxf==dtZn)8&v+k=UjKk0N<m>qNtb1#!Ms`QI_Mqmz@=?_fh;bOj z&NM#oahwcIs!3an5h~%H@B-@ukk!v#W({~VA+ZSuIFKC@g1Pbi#bxo;4m@s%KL~FS zK}6U1D{xiC21G}v@xrxpLpRRvcY1N*?LH3V)y1aj_ua)>Z%k4T|M;wBY_EFl44Apn zWb({*g#1DBmF*{KkyYy5OyJutj~S+{yk?7W`t-fDQQ5VVl6s0rb7K}8y>4HZ@2KB0 zThPHSB41h0qpriT`r=vxnoab-n&|7z74QKfSDtFxT4NW{I9Lw7DS8_v&R<7!oL1;; zxhwwS?o<DSnbr?#$!#DpL9Q~3^jaFe?}hMF^KP7+)xLGs+<)TkT@dzW=zmJ6MA4B6 zW}mA=H}&%#Y4&jD>Xq|ui8H=Ue-1?+4GH~7-~CmD6I?)8pU-6-0{*KQPZhcH;sxBO z@qmxC{}u)%TG~@GvDof&V5JRik~^;=F5Y;3RUa}YQi{?Sp>HYt`Bnk=Ev6wy)d^k^ zjNObRoOOW^bN(|zsMcCc|L%3K<w)DTR{_dtFUda?^1eXUEB)v(z(n(wFyZTg?nyVF zAJW;KnoIvy?X5k1eEabMJrM@i*nAZyE28Iq>x#;{e!p9I3h703lzOTyKVqpPT?=+x zyh1h#b9iybBS)YZ>U>Ok$0PK>!BiY`%{=~JOLB=4RC*!lAO9<a8TwAq5D*SJ1%sH- zv7%g+seX=Lf6R&UZzSX(QR2epeaf#sF3y9aVh#tFoz_XtA&qgo(|`-{Ws9!@ZEoX% zub!hJ%>$1Z>;#Bg@`#m9sLE;UAE+c%3TKs7N9AOYccFlV=%3Eh@GscIj6iT+d+vDV ziLLEKp7f*5c{q@G5&^9KK)6(ZBtjMfgK_FH63ZH`OixMYN5O@5exV}Lsxn9aMEN2$ zvBfA3ov4wMkB-eiOjrTgoBPArQLn9yeh&-90;j*aBzYk9m<tzXQ@C^RlA$%&T;9~_ z`p{b_G7}PSt(-cpR=o2z5QR1oQ}=^AwlN_TcG_nxJ2#vWh<DM(>1zcfu37=@R4X*B zvZ9Wf=^(MaHMr4S*l@A$+1v-{c!R9c%5CB&dXDa7l^2wJ4JH2a^!a1Er+)r5zyy>~ zOb!KhYVVGXhKapJodS9`A{zQp0Y7%WvSKXff6$pY<4M}I_VWG${!*E{Nl~Fj5YKA$ z-g%{^(ie;bHNP*iXp3%j4Zm2XgXrpuTpvpuDb+YUwH$ZvFI5_^HlC(-2M8W~RBzK8 zUtfBqItXwS>ab+Mbp)S68t~#5fm?;Vlws;%(1=H-6=yiXcHB=Cdf_b!js~~^3Y|nw z?P?tCtt2L25@ngA_J=Af=Xcb9c1t2AAIFr=CyH7hpa@JKAqf$*QOV7X61z}UBLtFW zN>9hDgr%{n0shu?<g*v`hi5!hs8$8292<Orxc|w(Eqv%(`uubfmou%<Uf@+f8N;4K zepKmK;VRHlg{NZ!JE@vR1GJwZLveSD<Y8DN0@YzJJ95MND%~}t3~X7tP@9y7aHJb2 z{ZYBlo7H@nj=g+TPqa(iT4mQKLkR1C;M|J#I&-z)SxG#!bNo7Uq&oM;3Fmuh(|jv2 z+g9HSV5a%q5QK%j5%TbuD(1Tf_wNB~;{m__WJl6r&&>ZmYuLW><-jd!<hnMe+}0jD z+GcQaK;Q9a`^hb@xv<CK`Bu>DZ=AXytu-g!@D}P8@uP5wiUwN%xl2Ya6*|3M3+xmg z=M`A}SJ6JT>L7eSNE^+yv5#bEEi1C)!C^k{BB3@NwoKpJiNW#`DHk{5_VVm{$F(L7 zb~6Kp_!_?*r}`q)OaYt;%@?xf9Vj43@HzKy)m;+vSCd6SUcnUB4bjl2;*w8xn?%9z zASZ);`GKJ-*WL^48Rb;@;JKvO5ssGIHSk@=mRR!PHe}s^)?3+rbg~#@GoA>ms9XQ3 znZ$oM3FCywEL(t0SaIR12Z^EI>gr=9^9)2xleA&xlJHGU&ReB+^cxATxEx~oLY44F zp0E}dDF}Xo{aTRpH(<Z{JSl>&4uR}De`gqJV0-3qKe$_^rvO@(dzfG8ahpG&vI!%| zQN%b@lN<Pf^{p!^bA|21C|=e!S7Zj(pi*#k!at%}e(Q8KxM8DTR#?Gc<np;5OfG?X zHMsO9S704|U6sL9j2IF$Y?v{OR~hZGk+Pqam|V{H@&GWm!SJIBl-)>k(DHwDg`DgS zhr^_(E$bvHeUAadJv3xCrYuZX*Nd-l0vyZkcWNp7n<#`*`Rr>Lez*%E(<AwxSY-^I zFRj|n+yl5}Y+tOaS<67}<1q<kPc<K3M|pi}5W4#cg{GTorA=GgKv`ASwg>(^2YcGq zKllI`+~d^eOI_kpa|^7&IdLz*`WN3mPK?t^Qi<}8Eir3X$2f{k_K_;E+9(ZzBuz+T zFl&_WZ&~$;Uj#x#*>RQT9xSZhRgI3}U2915pMW)ax_PAiDKS=zP#yV!OFdXEf-PI! zMURLmy)-_h0o3hzrGvobuEj2z@#;fkxI*tk22Ju0thb}=0_jJPGXBaxQkfTHNa|!7 z*tq}Dt%Siza{<pG2~gl8I;j*xTBs4upFo0Doq~6&_YGOD?YIBA<yPMe*S2aKe$@z( z!t+ru^E9{529K;h=On){drckal5)3gOevdk^dehzQ+dZ*FVZuaQRIb-QLK|x!aLVK zJ-YnKeaFvgun4ch#c;$r7(APM*IiV4kcl=04wOrtu3;RUe6Y-%YL+Zdm2JRFyttNI z^k(`{xMY$8^~2a7r{Yx!Ia|gKn)ad3akx`UGI}b4C%K2Oo~_G%me3JN0$*{jkmc)d zR1)=&LFhc#!^Cd1zHWUipGL*jGESpm6mnUUTG&ib1aoGrAa9g&Qt15>c`YAu{ihxb zvkLoX1mJcmZIEGUx?*SI5XxLh6$J~C+z0K-cp;MV+MVnt-!UyPd`v3UNsJn37&F0A z^4@2uUec^ZRgeFfhaZL_@}}QTwz@Uuy=M^!?QdW$r|vvVOXc^4@!@e;1I_w2D#ne! ze%%K;?)lpN!`CSLf7yhH{NY^)2c^l_&}+br>GfqNf4TRO3VW@qN1?XeT#yVvuOk{T zK}J|1p0yC>w9tE`?JHZ5nY^m_RiF%FWJb9@yi2?;6AiWH&TC4g%7>NpQ4q;|J$bw0 z0mF57n_yi2C}`_@<8lnYrt*kw1iS8mBFC{Z8e!#ZlCaWkcDlT&QPtM4J0$SmH>T_n zng~0kKqUKROaqs>p|87;+H005&N5^Sz-!8m+{!%;6D(bAhFdQj5|5`@<`y5Ra(LJ6 z8o3#mwLQaMKo^rP&PVV+eggx)v|*gwLHE<@A#D*GT$P^ye>eF3OC~_EGCk?QOJDQn zCw1MwpW3mD*`*w-tL~>vSIK_+DdLyF&~WX_9XL-mY-0%7-uVqSLndQb5%tSHCB85- zR6qM*17%gCw$1#*^Mak>x~dml83>`Gc63o)VA2OBhCe^^asP$IxYb982hi=bS+dG% zw`(`TR<C-NLN!%S|ML%L80M{hCrfp(*DtPRd@<jSrwNhe#+jXPH9Jb%cp6*d5gV=j zx@cpx2Auo@S;`!8HMzd=_krz``Q`#Bql1!9YWemYDOTNQ5TTJo<_e!99TMr&vC%Ps z4FgK8b_FEQAGQU?NXylMT=?gmAQ))cy&#EIZt8$bMCdaNRM$W#JWAL!>=f4iWYJP- zcNuTn4LBuifPtp*IUPu1X<{C%jE#{%=fN?eB8L0N0v8^dcCns~p&fQ8cK@<xR*ZHK zonm2?2e<*ln=0jLmQ|qy_3lOv-&0ZmIV&5qx*-1M#Z)6G_R>*ULQ3EO$ob3A<k!=0 zIi3_=uEiK{WI9Dg)aBW_^j^~O+DqBj<4J-#?8fRN3zfCotq)CMuKx3Ko$6Oy%P7<1 z8xY<nd|_YuheQL7ycgXv5zoMCTW@*40%H`W6^F!H3^P{h2Bs*-^gfRnaFNw8X!2;# z5M5%wuSlxEExqp>7QZSfV!^P6BVtm5YqFs?c;aghf!M%A><MOv@H@Rh%T9n8c)0cL zn?a4onN^Xzay=>bgFU|7!INK=J`b^f+oSK*Uo=-Tn48A3&WMjP0v<2eIMz_1+kJYt zTM@9y2Wr#VS(a7bv?H>gj{jUecvkxJ+a*<L!KcFYZ0C?c(F-<;cbzy=#L5@%n*Jo_ z%2|m_e_C5Fk(d?qUHkY8<^1y(f9Ut1btI{3%x3uG^=dlo-QkjUdi!pJstFi$Oj07X ztk}|657IhFebiRgfn|}xjjeEkv!(@D{;b`hgyn@Z;M1n=cSUiuMDTO{ACfx>5$e!z zQ(MVop#o2sNo30Yac>!{r!}0FW@5?5-&<XzmaT%y$@7r^K4<epF(UVtN@rWIk5kV3 z`xdHy6pZ6wV)@3hf^nb?BHJEizD5LAeil!XTlMj+<Sd@UByG@cOx#fkLQ=pP5HqZ5 zCV%sH%eUF``0K_nH%iWaIa&q>O<9%QpCwcw-8{W|9P9RtXL5FEjx6D>%sgoOj8gSE zTTJS@6_XeX6E_feaktnB#<n{Vy+?|9tStvQ!9$>db`{=bE<;yRveHg<joVh=4EYCw zB>Aw{@s4a91*(_xE6Z($&MQFXA?zyVHn%55-Jc@d8GhzIGp5#w6qmE!aB%<LCFn_K zoQTGnsWWE)hTveQNDhpTGWGL|Y^NUwC+K`}s%mvPuDOm&HfGR7jn$m}W`&ICF3l?? zYtA>M{Slqpqg;vKBFo;&qYAFBXRcVw6i>Bx9f@fOl5Zp4n`s<C7~b9OTc{3Qz-5DO zyIEKv%R<J(9Pc?jam{V2S&ebz`pD$FS$H30x|tKBuR^@}aPVyKM~!69Mvf5^h-6u( zjwbF$0f1Zlec?c^oD3N-QA-onW5ygsMoP5q`;-}ftU_=IE5nO-mIC|)s8~CJw{Huo z+{m>b7eFGnL4xlG&hTu!ydJ=~@!SMU77Bd!kKozQ4o2)$UgF<KV#7N9?@mfGX%~yd zlRA2cLu!+$<yKwYRI>w^cTTp2rk2KBop*i|c>S_RfBTQy>FP;hS20L+y70-bS#$Lf z%BPiBon=ty(6SROWSv&nd}HS$w$1J0{mv#gR5HBr*iO00meWper-S*<?x`z-*`VK; zXXN_nY%)n+mt_Q=mNaCu>W)8)tysVa9V9~Q)dL^kh=dpg?Z<~wa$cYH`$>B(oh|K! z4Rsi<QT8~r3EXs$sH%w+dIo%YFU_xHAv^}|aPy8a{w(mXJaG9lqXRa0y`wJpaMyVL z(X)q`E)`(wUOW2BM_J+|4QznX6&uKW;MubD501Pq9Si5dGkiD8M9IntO>$MPDDg)B zH>c*)>PB4-I4h9LL@Zxv?dGNB#@^ghj(`G!qkUk>hTtyzA2y*`W6B>Kg){6zT@p<? z0i9`9PbGs+ks|9&j!dXLmyq<Z<|#no6j8`hygcDgT`r{d6!j0$BKAXnc-Ffc+uVbR zYB$xAUrOJCdb*UM4!AqnOo@>z{+z7}YyNHu-eCR8-tHS{ewIQ2rOLA$Hu~ZvYH!Iy zP4tsr!!>TXa~II6YnsKL3fHl0GZjeFiqtGy&k%YFYX5gI1zxRm$<z~-=qF%+@wjo% zg&)D-CjZVSz>Pdm^_<TVEk?^q93Jm`D)}1F7AQndhk(H;{Ib~l`Sx9gm2VHq$od5} z(;jo*1_SRm4|R&|mVTVM)3Gro+ph|aw0!*_w^$@nJvyH4#|$_r;H2NLIy&L*oJ;a) zkFCW1@xi+N^K6ScJ%oFh<*C66AgFXQZY&!vZsSun?*5zSN?Y(TCCp$~lN}J{m_WBf z-<yKZA0QYRu!t;du2VDB#R?`)lZPQKGnrGE9w;QZ;O)$rd`l?!^09Fg1P+5jlE;g0 zEbRnzb{fjgm8=K><$R*Tr&6ba+&>_kTU`A<#YE6kJMY3hU@$z#>;n`6cI@6$xV4R% zjE&`{w94-*G~nnOLC-v&d#Pw__A6pyQVNg1vyAs`e>5rYhc|;{su$WgE?gaApEhgM z;ZGC#g0?<w(g?w*HZBjZUnF!}sY0P@D+v(cwC2ev(tQvg2?7-%^6zVeQffPj_#utN zK`8c6t;Fr{o~3Y?O<Tncjas7(cgtOjuyO8tjRr6r!h;_Lt1jC;%2hIkw5VDM8X~IP zvF`5KF7H1Fh;&K$vrT`7K#kB%jp+fSKNll8PrPzag>Un6MrWkka#0;a^T&C)vFfjF z2jxbYE)(pGFO5@h{u0<L+b?tN$0kr5Udb3{2FRGfW=t@6Y8~G0rOfGBWLT7l!e5qA z!=O-~_dk5aL2e*3W0hSPC;Ia_ed4k)^H_g7hMH49r?{Bhd)*X&((ZC`V2T7Ighk;B zz<8&!6ui<SX=i9z|Gt(tx7Jd(=G{FE<@e`PTkL%_rO#dA2usLFq)vpv{_(S~v^*0; z@!F(F85rtuhvJ6ty=SVq<c{|_;6O%qL%bkTKffL@$GY`-?Q1Aw;d9qVs^R%AB3vss z)S2fHag(u$VLgj4&RsO6`|)d+cf}&|x^o54Oz&`%>kw&+X~Y`A+YLB;pz_bS7x-MD zZ{AkdpEv$o`HUMM8DA1z?V$2g&HpOxk@v`{=c%~p6JvNetrhSOJMf6a#N1W69W@7> z%3Hlmyh?(bQ;v+@rFIQ6DLx0^wIEV%=r3q&i8AxYnTpeB%;`XSH9G6B80}jjERRsL z^|Ab&5-XIVwJasB;k={4(!JN5jC06kedY~}`>|4J%wH^nS6<_qgEgPeCnFcIk<VM~ zecQ4-Ji$#f>G#Gy7$o2yq>FS;i=&!?$6xotf|w{r`@|2z&X6A=*HkCiGOAonT-F?_ zI9!JK@&rxHbbGl~N0BgNE<r;H^A44u%>Kffh-zc04+;uFtE}jS2GL@rnU{LqP$$MP z2(g3?mVyo9>#OWkW4~n*Cq+woJvrO7gZl6u#4>hSr_PNsQ-Y00^boQuQAe=)rzb)r za1oUg#H;U!2l6+s(DoLPJpai99CSKG^UWm(rx)x27S*;>mw24Xxp1yx+WCGU;X&}x zCEM;E3$;UM3L<V!Lc&V|{!)Rd?y2xHgdj`~MP+Ri^b7;R|MIQTYc~49X}W4LfZQCb z*&4U-Njkef%*Q;`c(n}Nl{u4S+5hq^wS;(b-D+hsvOKoMNqZ|dg#S_^ak1=lX}XZ^ zz}T?d(mjy*U(9j0C*u;F!lnq+4yNtLzY)va@}7ldu9ac{n{sC8$iLXoh?2h*f+THk z=d|qyceQ}=#yH!&_wBFq-e=98-Dlg<U6LQB-hsr3ls@q#3S<R(4!Re(r8J#G)le2b zX5{|v@?{7bY8;<;b{}x&uaC{I+gbL(9XDZo=WqXxbvzS6PiVg9NI)D?xGGm?h;l^d zV--tP21aRt%<z%4aB-!0$wqUq`dW1+mg|feIoUu0H)V@H6s$6VBJIxS;}i~F$O_Br z%J0EEF@WY{{<-*CM!-n3lziNOk=mp55K_cN|779>=5}7BcO4DcZl`AaZne)~v}v5$ z<qbi7tNw=GO@P1T%G>c7ck`b`S+{R=M=Q~n)u%~M3*eRzt>1sz-B<auB_K0uPTsx) zb^32~u<CDO4bxxz6A|14ofvbzbCAkM!}5iG!d?zl>iF9TKU|QT7+!w4{Lp&1T1xoS z;HiW1c)VA`VIUsEEA=vzy8%u71JLhJ6E<uS`+1!%XU%=KgnmywV<E#$QDp+nm!}J{ z_OOiHY-}Ys{tp!Q`0v2WkwH?{G@?-EYZV)mK0rIjwv)G(dp_hK5y|udzj^Ft-jB$? zUH-KG=8d7&<wGad?T}<&ozsWqgl@`e!W??^1vo>x>(&DjQGi~LW>idkS=<6j<;?aE zqsdFe7LXiME^;(ND_)VeUwn&vK6gFk(Uxy`82~cr31{^-h$+{tB0GB<Cd5M$OwoY8 z^OIjI(oXt|nZ(tqy_0Mvp$^)>maTVk5Ut=__LS$D5PLn=hRAuaJ)!9+Ad1Eb#BFmz zg>@W!jpWR5r_n-fWiW0C)?SafkqdnV4mUy!**_`Od$(ld(w=1=F(N^HOb|ZV4r}{v zi@rk{n3+A1q(@Djl?I}@kB$||Y|ZPP>qf<e1lHTUKuQ>%a)bA?dwUV+nTX`kJKMJ+ zg2t9C(dOi9pz8j2$J&)18My@&d$nF2S~P_R5>QzF1iNtr|FxkAa)h_aqR8)~Oz}`2 z{on2|Yp&Cg<)+N@z;$v948{;g<BoEYD)Xx@MD+(MgFUAGg)cnb;ZbO^ndNsZ1qlWW zr*8;G{1IzO;R$=sSIRjre^?Xu%nldx;DkpEG`wC|De1e2VyAOW%`0oSuAMV(A~NS1 za|<A74*nxIure<0xW9sNFb!_(*@-)_Rx%Xf=~-S)`&#VJr2KxJpH!Ku>5WXZT75*Q zvFgfweU%kiVH?(lJGPmYFAd`g_qSY}19}~(hR2)~HaY{#B^u)Q_cQx|XTq1e8JW=< zd^(qq*X%FeYJHW46ELprMAh<gI*W5_1n9@kp-jWGeYDpTk?c!S)H{%(GQ}C4yg)z- zMjmGA4~@}8suUJ5-1z#a-S)$&Y2I#{hgg|xyQ9WENuE^^g3}uZSt2a^A1Z*5R<?KF zJLXn?zyNIJ+x@vCzQq+>h0~ZMpe&w9xVV#)CyqXdO$(Fjc-$-Cc*B^=52565Egaj+ z7tdNe>d&J_b1ATRc6?GS_76{c+}L?EiH6|WjHc?P!%Z`*hJ3~*VA4eE+KLx_0^74p zz8<^JTBVkd)d=g_)c%LboYW}gsfJH(L8pU^$C7V{#j^!U0{^B(GOa{q#zDl-j3aKl zTD$K3<@rVI#2~Ixey&D)NZIeSv1DDU1%dWM_$YblS)qvP&m_rO(VRx*V=z5Q%C5+y zec`LNb}Gs<gzXu`Bw4Im2lgnL3?kJxMnat;e;Rf;fHQma|MKA?JpKS*cVEnGHF@8C z&pNH%(eSUsRsbvL^)S~$+2EGV3_3o(4e-?u54BA@&fMhWD9PiyAJetmJgY=gX;VC2 zn<DaF)jQXhK)V|Hkj<?iMP5l2B6LMDk;quG!7{f1`|;S{Iv`E!*0*)^RNG*Ta@^18 z!_c~wC@xB><rpr{Ef=W6;2(Bi)D;%3K_iW-w_6geNo(&OjE%a&jdV@mEiGdwrmjfL zvz<hbsx!9Qt_FjfmA`Qf=L2oY(!#G&DthWV<)iC)lV7-El-ECAS4XuAytd35)8E~c z%1Iq!0>$v9$=@6#P1a5}eY3D2tHmk}YISGhYtK8#-0-;SP!|)jRP>ItjbEq0`)?Kv zV&UQE2NOr>QuHnm$S|2SE;}Ou{~|E~r`L@Hefc7hDGbnSEVYNG<5@Y0s4t|Qd)tp% zP3<Io`}G$12Nynl<ndDLp=up{N3*!f&G7>DUJ6YwGUPvjUa0yka=I`ku^CjEIP%{R zd<5l@zM!Hw>%7@EH>l~0?vIbAEMLh=+{;%!_GCZSL1GH?jirYC4|!y&yokLpJQ;q1 zv?z<5w0U*0fhx79OK}Cp$?q23J4?4x{KphU%(6rL#kNJR#ppgXO-meO#B0Vk3eBB= zGX;Ja!{Bb4@1~=|u``;dfzTs@s+ETEK9F=nWInf(>wb?uDa7<(?uARi5+$_sPbEha z%2M(N+80ExLb<`Vp1#Tag?sCcObR*h)!p?^orv-jp%~=S4`8}Ev9}hy!T}Z&51|ga z#*0Wy40Nb@n>q<4SnWrXQHKI}){+BADH!`maX4}+V93+0_7_q1mSlV0(A5rSXsj{a z?$qHgZoTGQ-^IyKFMVm{E5Ml`LjC(lOVs`StRkaP4+Wo4(NLDBRpQVt1>wj<R^=RQ z!E<=+D^Qi6D!l{1f7UoZo7<pR<@Fwm{CYJVVF8(vutVy@7Vw@L>^pU!pPA6yr3zq@ zroMl!Svj3a;1FOqL<)7asRsF;@HVlVBLK;+B_`sE1z#}?KWy}S`9);;9hYH=`-2yK zD%|%fe}vY+yW^>Y&##+mAgqnI6DFstO#0PSKphQ23osXLMzbHe87xe87TCJWplgMh zTG05Up+2@|E}-AS6MT^hQ;((r<EFy3@Qidsdk1de4Rh*Pv+d>7ZF#N;-N*?w07u(v zJa(@dFbXXHYy}FQ<uzJ0lj1$@MFx>=c|SwRkiu0R=2zzTM)HkFl-Io5I=u9Nam1O= zp)7nU@BM-wAy{^1zPm)LcZbYro%MiSmkw_tbM>g<+n@~*6f{{Xyi8pMChb`GL!flD z-Y~p`6h0AqTCrfH4C{w4A>NPDut+1^us#2MP1|AUAGZ)^{_WEqT?SVuK^-567$EOQ z2*4)Z2w!`KO!=|iS@kW~33l!;gU63)9#IpxUa=r^PpY@NCVn-Xi%1b_v(2L`xdIF> zsbBJ)SSyqT9g1j{vVvd&A;_R~<kMQ=!w{jX*(yL@2-_Be<9hph)lJu#+S<a~EyMYw zi~CIyAMtBv_$&?`0Y8y+oD5*Im-ktXZYUA=MyDjO@nzoVO!S0k;FmHVXy(sM{?hva zkT0lX?T9D!JWdZ+{cP(9@xg>*y3KB=UVyyv)m!3+ZIcL2+TZVXy4@S=!1Eeb0?kXw z&)ji$gI*R<_!pj1WxQ9|V$Q&l_%PL0uzVcn3?(>!s;_d5d1?9n=c)H6QInq?+MAr; z{6|4!u9w;s8gRqJkHj-mH0Ka$W-J$~|E80BUe$gb@0&j$fg_7>$!4UbNPp?W0=SqY z$XmZtJ9zXTOQ_r0FyYQyh<mN?u-8&kPt){~Ua397%^H*~{;Cfa;=5Mx=38U0_jbou zV(XTEANN#GZzqH!s!L=`9_D0cfxe*3HbI46S*wo{`DYPj0sAE_Ck0;>dI<S}9G@!h zRBm-1*is4G0+@CD^<N<Li^PMtiuHo&GMM)I-`fyZFCD)ZgUR`=Esje`R>Q=T{$fMr z0_UqB;;S}5{sj}V(fUIO%Cd=U`cr+_lA+}s^}grsuQ@S9^TWV%&G8DNQW-<i!rF2c z7`87&BVW@dYT^cpHup%>mY|Gln&~+kGUo%#60MCmcmr9mmx#Wy(MOr<B{MwU>b04E z$bhwtN8|w%3Z&fte>eNh2U3%!mOk7jU)Bh(SMGQ~a3eH%c4?-SEe`T{U58k<JZDe> z+g8t9({Nz&P{tmRk4Q8$hto8<J89OhG|l%XiI`tPpv^CUeP)XXNg@-id-Tz-b+Lvn zL@QTtXM=mc$Ce5PQL;h_<k~A!8BJ?cD1&NLh%vP`yW4u6&vY}3O}N_Ldn^p8(ZR0$ zh<4Aag*o5qq$zhxWXOf2VcK>L=KUMoa6abXr237v3<Y{z_^-Z&_T7vtAkb}2miG$> zMY|(0@|<XLPn>w*(?ls)jh}cv6Y^-qi8!Y&d>JH0Av+Zd$8ri03`jl2(pci;P)?HG zoD`y-a^I{*KS4u`Ps9moRu1+(w@)qTUUK(cRB()NzmJeQP|#uP%<#tJdC#lHAJr7( zetd(dBt9;Tr^zX6goyTt3j;rPD@nyK<+%|yd%om$$c~eZp=pAyB=>~M0NBY4xmF0i z@?tVv`{dthH`=;&VuW$Rk)?>kY>&ufKaIN9GjZjq-k;OWz;?K7r*laHXOb43s9Su? zU`^r)qi5o|%3sMfqlJ04)w6lpJV(lNihAT$cblN^_mufyVR2Clw%>#fQ$b?pBT3ES zh0Btc?P`Q(q)b*1;+R%i#b!Z_%pwcJ2=cJyt|lqLVzvdqY&)=FKfIyJj)Jn(=?Fsu zZlSGf4|Kh<BL9<iu90xNI_okc6~U3-FR2ORT^baAW;+3F=|TEmPduy^IW`zrhj44q z3Htue+;`Dh=?lyDi;&si4<G)jXFOgF4eM6Q5W3T_^@yfcN@abEkn_dHSc7Q&5c@Yv zEw<S+88a4q$*CZlSp$vkwEImeFk?a6&LD<lCb=qXyWYyqc+}n31OCM_q@((!Dc`-U zo=>I8ZE~MUPycxz8>~v{{10;wIMsTi{*4}~t3QM2Z&F_@dfCSDw42%3%M#*L@D`4S zLo^Z}&VVy+^ItMM9Y73(NkOZnz#F-nY`Q4;;rWnz5PP>bUKg7WXM{xRtcKUq??dlJ zZj><U0CPEQPSC(Ok#n(u5MY$Eg*ZpYfkA!)#R`Ml`xxSGevkD5-cO+<k%K8a6r<%b z?@qcA<%L>-gT!R)8kqjqPxcHFVMWUl6qpo`Muh3YQfUQkrCJG)g`3It3mGY1g4rv% zw|=%T0{jQ@vR{}Z7cj9f#=431QRg+pq%2_axv9ug$#*B~GtTBHf9_fS#gy_h)^7Q> zzu4ZtuF9;KDZesF6?ASS1|d3<E}&kDfBJO0eJa+yk)Ya%d;^MZDF0-wR7;IIG6V}9 zgT~j{#gsHQ+^lVMkIt=(7k#MIG!r}{1+;eE{^^9waxx{8^7=bhSC<{eAxG}Uf9u<a zNW8PJbDV?6aebR^(}4G){r?HjyCl1t_LmB1H5HpmR_oJ3&|W=05HQCMHT2<z_bPLw zT|ML+3VtlcymBmTzsFI(Nz;id6Hu40hy}CL^u9Etp>uwGnu8Yo9gZnPXqoqz0f^V~ zZFJq7QT<vR0os~2M*t;IPd`9<_rB(Ne7TZAi{x!=M{cq+J1R=-lIeY{+?dGIyNPJZ zDV7)CXe5$kEFpoKjC0BNwBZRAi)G8&KGoIldjv{>T?RBy2A=v-V|5*A1V~c>Qh`|= z(Sr}^03fud4vJjct&Thj>~(7{fWsyMu3!&FixI5Uzi$H=CKmKnBgFq$kX1OsJ;l~d zQumT_IS7q^suOTsT+7UI;CohJ{~nXl&$fC_EgmziHruCi0Sf6fN&>~LZSg(N+3Nn2 zwVU?1-1DauySa#zDrNPek>bbrU|AlIxrnaRusU;-+0EDoH~v$NzgH1balu^AW4ZjI z6ywqui=z4bTJ$sIrdji?(p05legWZ|N7L^aJnnEA)}jhM#uwFpm0o3DtZ4<)NpHZM zYWc^aKKiiKi0O!#0tw55>r`{_=mU$@B=d%f18LN)hWi+j9OZ*U@p@ziEOQ0MOEglC zc<Q?33rGoS4e)hM2CiG18`(4ow@XO=Hr>oMhyZ;vHw-Ml`Gomz3`{1#lI*==Vrp5= z@j8Oja&<*IU!wJZ!~{_8j&SPno#WI9p7XJlvEHXFYiCrFZGyyG$3AO&cWd&Mo$_Wt z)j=oJa5TydENbR>bV*<xN=VX)1c4*8jgH~#Zi6>g)jv?J(=V)Xe7hS+0Ignx{3%q( zdKkgzE!{`%rsoTXj7sZ;O3q64oDt=Z5n=C>rzA-+Bq@A3LX7<H<uc`=mbpXy<uwmy zsq{_N4P3H76Qh}vD~%w_$)r~+0|`~ZMEk+!-~Zeeb|=N@A`zAQu8xJ5#Mj|d1rUf> zyx0>9$FWj@RB0fl?x4v60SP8%!5OJHI}r<HP}073K~Xv@ltDHptL0r3&LfDokM32p z$S(9K*-2vU6!i9$3Kzh3I;6^k{<OE;N_f<Pf~P-9#qZz{=OQcNzh_3WId96RW=r;6 zk^9w4XB)UZGCj@I%L;(g_$E&?;FwzG?tyvk(L)uP;12qh32m8S$MrKLV@8wPUcV0U zE(p<e5-9k?=z%@1{3i626^m%WT{BwXUt(B>(Dhyt-7_q$865W#&n5$F+_{HBHFKm| zuq=$_vO9P%H}YK)g*jlr=W#a}(5eqG>!|@Zurs8J_Uf7-(nZNVsCn?+B+RD}uY-|u z|4xwuH|y%M=*!JLS1#q%EmvyuEfw2c9#ebRKB|i`1xC@t$j(K3+jkFZ`Hi1>XT7h% z-TH~^7qH|uh)RJgH3$_okH60pNmhbu8m<=~yjX)RIbKa5_g6}IT~g*WG+*e;RAe&X zz07y;qOxkHMKb@*ej^{njh%m9I6?gJMQRf<p<3R(H?UJQ-&OwNEi;=Y1uK0AGo9D3 zoAgv9ottckMi*}ppr<4gmPp!3LE?Wp0F>n?&v|vu=5&`+!aAYpp8UYO<Sb3+f_Vk3 zmAUk0GG@yMxE1|cSQ1EmBoi&X5B!};<yw6p73=2KTIV%}dGyy%kV!Y5o!MA_7rOlI zoq)BU5&843QOB7yZm<IX<qm|iK{>mkogc-+#!l{oJlwr)X)Z<qZF~;i!#O%TxfGny z?oBas3kPd?FFzWI&6+OFVUhAqeCUG0viwA9yxtojNS~e^LcYYWqB@(?Y!Zn`!B>Ym zQqM2McMge^OFON?UO|--9+8gGaX`_-)JWNgBpXIBC6?Hpo$bAJ<!dQk93E=SFh5MG zgCA$gwzZplLuqnZj8P}Wb?Geb9X!-*{=TAu*@q@N#p^XxMw@r!<_b;nrvKVqUzUiP zH=gWK6>mwXz??W%4Mx0)CI5p>#r>VctAn4*foT^}rWXxgwN_!An+JOK%i5U>REnkO ze3bRh_;QcOE2N)Ik)`5bPjeMO7~2p=>yDUf@u<axkSo7APC~!QU-ZP-*UVaByVR8O zAf8t90F3|aq!mb{I2cDKTAT-ML_v1ju1zCE$2n(P)!VAl7tX3)%6p&Upw|i`bGXOU zXPRFXT|M7+p6JGZtE640_o0mL2GSr}YX7q&`Ms`%<_o`UQqVi8!mNw65UU@W?&s<P z?`0i%4hp2tpfla>Q}VD>{Jvx1T=Jn212a}KiP@3lzpeC~Q|Awtu_y7CQuAL{z`L(~ z{tW%1Q8)f_johTXyfALZF1jqJ5n_f|Tj=eJGnT53J}x=;Z0m#;T+)OD>t{6=<~+y~ z#uu|Bka7-|mmLc5{dG}y-#lJ<@IDL*wR!kW*h$7`&=Tz?I>aW5us(tT0CGiHHTcV^ zC(-%Nshj>73kSHm6xe~#nXf<N^7N05$}4Kc)<WAm9`D+pbD1LHsi`bF5xhXXpIsGV zRzb|TOFY90dt5U`GEPgS@oU2*+6z9aUN4QisEi)H<CLzTcSO=5+IjU_zUtD)_^=Sc z`@F$PTaJu;66K7DVNMp*fT(QNC+jVpVF$Sz6TOXBB(0*fNhc+s7s#8$hZU>&kBgt= ziwX0}GwmZiGM8BdG)@6N-j4d`->yk5VYZoDIune0lMiy^7T-(L5o!?&t?zGh3WkRS zWsnR^00+TA$zLnBbN8WIXV0X$C(;-4aYHeaf<5GZ&LZRn;6WgjRDhL2MoRPJ7LuFd zsf8f?WLd#Q=jazk^Ll8%r`cX>Pr5pac|7=V(eVrC&@ixgaxX&kXt73~4-q0RC^IFr zj*uq&dXibd_!}Noc3BP!+c^5`40<lc3?rI?IH|-%n88wJFixvvF0oa$_0aps`OnTl zXn|L5pMnO*wQjfWNOdmkK&e^7s8sWQ-?=&)a*xp5LW9%{?QU$(ZS?fc&3!}Y!MN8M zf(v`?UqhEp=^KcLjHxKDcKrrj%p0!wO>`Okci8z*as1`$c;r%qP($`%5iUH}s6ER^ zzxc^^4dG7G;Gy562|j^X%nL=x@xt4*NtxD|0$y~>LNHha1<bydJE$ZzD+B6Ya0K(E zt?Z*uiHSTl22-@v15iE#gZJe}P9iTu+aeesaN0uqe^1NTJ79<DbC7L>Qohe8tnSC0 zgF=rkB@qiw1DeM9``%L#`y>NIdoAyLFCh$L-^a^6wX8FIxQvklH69QDCwqlG*mza< z-{D;!!aiXv6cmukoB4VHM~h!)+^{&VAlFoLQq`2}9nvBFG1@xafqAYj$J};WFz0eA z{>C9{&#DB0+N4A>h!lKt<0C!-=^<9}8FL%**b*Lt3R|><Wo6|KuZAPDtPjM2<E@HD z_FUdF<YdsA*<M7}wvQ1e81&t#x=w~`_)<S|S`!|gh0YTY-Qs!j@@6IcI~ow63-=`o zoTMon`itz*y1zyOYOk}dfQg@twu_pDoovn-CJPC?$d;9KiJNE0-P!(;SW2W1OarG0 zYC&v!Dv)06GO4=u=EsUU7N&rGI?2EB7q}M2{0o3Rm+r}wB*Y6vf}8a1*aF|8u>fwL zfk0YSovY=3U)yfUf&1eQ>UR#v{6XmnyS*|{#vvKVS&XJghE4TeGf#h%h#MBp^F?VV zdCzPv0@@<CO<3Z7Ycb&^SGQHS!Y2o=*;$rkuymLw(?f%k2dhd8`74v%A-%EV2Ej)W zu;;Va?A5x8<lZISNvUS@K~MSB1HO`o_VaQho_-~$dX4fi$brD%XPN7vXP9r<4$gCX zmGtUzY*z<@h4BJWM;PB@y<VD#4!6FF!d}SAQ_oMj0|!gILL!Xo5~1xiqX|FW>M^I4 zKT@zLJ!3b~3F=ob64Ddaqx5nBwRt4l^GNr#d~0w-$Xpe9wt)WlHo*~e2~wL}7g;E- zcSS>DiV;gx*$QF#tbHs@u%=5m{%E8kkGBh~K~w1Qiv1Qj4S0Unlg1qc(2J9Ve0NV9 zq^Cr_Xu8a;jRDXM-qkD4oqk5(>O)uYg?oY~JsP#ztFW`L_963U<V8zu5sPeEZ}D>S zwdDIEAQ%a>WDJTJB0ddUS;~!#$47SkZ8BqP-ga+pvzggMWh%C+eQ!k1qg8Xt_7dA9 z=0~51yahisUyZv(5|DEHcCUKMHEA5bpKd0Vb-Ij3q0^8XkUrRHM1vfE>s16fGu_nM zEnW1tr$hG8`amqgnJMs?g!HQBw}}qd$xl*Km+luy4M~?h8w5}uLUfWxCN-`7q9yRm zs318eAD%~dRR!EUu3WSaim4hScwL7F39ilm$amfgL2DXy16StkR?5i|9PVhATFb-( ztf{$O^u*D@((8*?uw~+Mn(zkO+Rq$-a45e>oAY0qb$?#bDk3&xum*<TI;Hb-2G!M% z^d1CivXzs}Zbz$H?09%(w6M=UmI%0YgyZ`kS@yrUjp^K$qGxVyAq4u~3eaBoXSLa- z3M*SrDd+<$a%_=Ws(igNI}aOS{_$WN@U6l`31nlQ*4&J-I?DF$2BxnQsDYbl?B~T+ zi4o-wCB#zULG`!RB%bSB66IzOXY*ut)>X6j?BCkx9z=engyjf}5B54STDBuU;$<ZB zSi}0a+2EBG&W<m$-TBn1N#U0<AjU2v*+h(uyF6Mjb8x}fr6pm*$SP2HdNkZL?dUS5 zPYaebUgTwQ*a`+Q-VzrM+D=#j_o^rw_s7?`whV*|L@<of*WmXz#||=b_%^o=>)^(# zxF|w@lY&QMJl!6J(_{lLZVOQ6bt}c1iUb6{UtRS7>0Jx-U(Mf-&`X&UZ`d0wn5!m4 z4fPqcY$PT!N)!{GU}s`UxK4zLSL?$>8($Ar^`}DKn1d|gRXDhdpodIi@Z0cWr+^h} zOWWJR<#~0`1rB;CAjY<7Af$_h>eqCW3j8%;FWE`0E%C{J0I!{MxK!|gV{E#kNyW?R z6873ewW3uSO>c#tFUaCT7($8|k3#rWjKv7>NvJ93BuM9fiq874>9>o+YsN-wu+cHP zJER#fIvgp|VeE^PI6@H^>4KryEg?!6Aky6!z>p9@C9J^&K@pJJ!}AY(e!5?u``qW8 z_jTo?zh4~7KSWHsT~%4cetqlWCzz7XRRH%)Dcm4y^l<9M^Or5pUINSC6>ILD-L96L zSIJspTU{^g#t?U%VDSZo%B7vyHvl5_;diy$RfOWip(_)rjX6V5vIigg0%R9u?&|h2 z#kSLy?6hR3x@!Niygsu(*LGa#$jk6k3Ea{bk%_@3jN&sv1x~KEJy(o9zc<?*{}W}1 z(@*%Bff44_nB@)Z@^!6ha5?dWSF~ix-{o{S=NaW>;7b0^FyrU<t$!n^3*RL3hW*}_ zZG1}U*GbgthC(hK>kuzjNvroylwsNis!#EL*{y-=@3;c(kkVEa+)b0ChwWE3d8BT< z()_xRsJp%xii+xqvmr-0kpP}~&$f_{;Y07&1T%<nJQEvyjRHpnv?_^B&~V1RzUJqQ z%wL)_=FbK0|4sWvih_oIjTSfeqwEax*F4wuYRXE1{_V^QA(ix>u)kM-PWExMWHXDI zNVb2C&bwgj2v43wzqLFrX&lxYm(iQpZ~ysZ;%BD&tj9a);)O$x)1uHi;U}3jDF+QR zXGevbS*?Hb%Z{cP-RWiG&rH<<0%-q~-A|tywi0l+FJtI%Kt0qvC{>`@whwl`U)hFG zG>QWGd$6l3vU%M0i4Q01mtAvH*9dfflvq4#3ZRYF$joR~bsC}a<g{Nyw1kZ!kdO5s zZ-l%(gY>cXUK);<l2%<WC-ZTWRKL6J7eH%N&K+mub<<$XEsU#3y2R)L5z9i)=)K|( zdde$anOm~^*ylIM_lc1}NXbQoOBG?74l=U>ja5t;;E4(XZM#^qK%n=1s~}42a+Z$* zO3<HnF-Jk<m5ZOxmT^*;dQqm@S!OmG604PwvQFl=ORqsxhiI)Q^F7+){nKP{X0XGq z;bwx6J6{FnGQV$p5>jP#L+7SeSa#y0D~4Gqno`j@C5T+Nqp|zlEAM6BLj65En}T4? zif^*|DpR<nXlcokG5{zAGItdO+ldir;%zomdD>SNewqf*rBALcUA_P)F1)sCws8pf zb>P9u@5N#6onrDlzE$9HDfGTjlFr>2JL@~53`WWowb9dOpz3$sEB0I4G@QIj&?6_Z zEeTyM^m=UHy_K%}r{C`=F^q1<pqjO_*Q)nkx@Tn~{<8ZyVjm?Xn(at+<;)%;TkVKZ zm8-8RL@;+FjKa?nTXDB)q*NpQWBvlKo)aGc)X14CcBObyQJ~YnKY0CSKpEa?i4dk~ zwaxyWeJH9EQXL~X0{lXrN_2(1EcxWCB-)TZZ#SczsI{XyMwPfk57LHj#tBfx@Q!qG zDz9_b4fynDhH|><C>4>4iFeq)VjMGfUES`!1IYVIS6PvotG}m^pjfon!|N(&0DYgo zkEWNRdkLh_L%25~boojzUvLiN`jzYM358kI7!c+7hmO;wRFOHgRVQRJba6i`MmSOg zcAiA$Up?3<jBjdZj2|OE%PRYLy^zmtZI&W1%}`N4vYo2lH^bqFrDSnVN+253c9=(; z+8mwmh*k^>_m#}nc)$>twvk-SmFnyZn%A~D%Hhv^R1O)XKRNOk@$qvFe4}fE!}NU~ zlGV7%;i1E^w)obJzl?6)L-VMWkF*;yAZeUmf-K|0dDJe<FJ-3uMbiD9X71zzQ2pGL z)N2QbW`jm1Z#$g9-F<L-M=pZyisuN&eJ`pBhSNE`=U-XGN(Tph;(R^oGXBxb4^|(W z4{!EiqzMScUAXv(KXaiHBSM$xG~m!U*X9LhC|_PIOqq!%DvWN#gL%~H!9Xrj#aoNo zg5|fhk>`e>nA;h@IDLa!Vb@*z)4SiHrucC#v{EAc+*)Zuix7hQ&ytLKE_mCdLMux% zYyY-UbnZ@~xJWt@E__{H#LS3vL4LyaN*zFeFLM>BDoqRJ4cv|FyB~CFUed~T_woz} z-Mp{+Wj-C+`V1-9g2eF@<jP}ff8DXJrX9b8TUj733L5R5_MX7&_8etMpMThNN^E!= z((FUH{Hq4dyXiXmewyr{H)9=)_ZCfKv4dZK`0y;s5caqJLlDWE?Gt)AQFCtnZBJdq z@-Rkf5&X^i$X}P+tAp|dCvbsR-7ax8BSa#vLmT(+Eq}?=6oPWq<<MX84!ZaKu^F&Z zb7FilY{OF{BJ*|p@mV{-N>!0gXT|C*xHhWpjP512;vUb&qJl2~5YCMEO(y5OxR`%F zGH5@D7}<6+)uK&jF%+BSUnL5!pTXq;(9v9DXBiNgHj0tB!|db7bTIuD2hEzHf!#j& zYbt_}%YNDRnwBk^-Y6c>=wS0v>7N2e(`X-pEix`@+Tl`cpO;l-IM_ez-oFc<xNUl7 zMpN#0ww&yp+aQ^T6yKlt{(_=U4v5=~<m@oc%uy^<rQ^0b$8JKY+`o_PY4<W_uHUu5 z{_XwXw<fG?-%;S#i#KjH#ug{4>R`NHMdf(JRwFGj_AB<Q&Np$lsh|}B+H`nK1!yJQ z32^~)hU`O^wtxR^r0mq>!#eom*jhh~9800FEP(QnjA*v#hA!6>)tzR<<J^fsS+I&e zV1FlB(CIMKQ{CZ8JgU`^1YLZtdl^|1@N!c+z0NNzGireJwTE#8?Ui$?Wtw~`6%Uq@ zg(D<m%r=5SrztV;^dTdh*EDHG({JMZNF-2A3UU!HI<#^GB@eN71O?c?U?$+@jS^x` zQe*`=o)2{RhgAK4Ik$$}U4&+oSXc)}H$z%Kz2pXtw>;$HW$Q|vkaTE79pCJOc2h(^ z4@+&Qmdo98R#f=TA+zrfr=odE-`CO1dDZU|9#;K*K%*&3=t_?boj)~IFO~ak5XOVM z%Z|U*M$i~ZxR5mw`jB0a-#6V0HHp5qm|+g>{NQA9<E#UVB!;?DQ&93}4y8zJE2F6T zt)g1#mv&;aJ68T|*%Z?c3x{BQZLvH-R^R?SjUS*}o~x9YRF}w?1o-cA)X?cZVM^@} zb~P6`2Sob|WMi*whuC?WG`BC*V?xu4`iO$wxqYu!*Y@XEK2Nws!AaH3rdim$yl^rK z-xCF^NEn<Fh+)qN2)$*_N$G>ySQ20I$_C!&kHE=(Hxk$QPphef;cK_RNgf0KEstN@ zMpWOjp;GevI?SFA9V}oex6CX0uKhwa@fDibBYW_7EKl!@b;QFQ_#5%n%e6{kr8O6x zmcIdXBlw)xqwVxAtX=i`Ko^jUKWRP6lky{4j}IX;V{y4SE7Y<B)uE=a`-BREGS7%P zpI9z@Sn@(TrHD^E+Ske=DHTP}>V^>Pq>6WTSk2b#r;oJegA;3ffsF9nNBdgF5_iX< zuJ2{<0R{8ysBt#ZV{Y#Rb4*-`^9sLHG&2*A_Mqu}f1=Ml5kd-5&~uWH%Tey|h?y)N zKd50FusV^e3V@LXp<t;$K$f+UR@=LDKBlJ5v6A8<n`H8j;yNm+#Bcay8W$AXQDnda zG&fW{<B$0b-#&v1#}Ht^hKgm6DpOdpx#KKH(O^*2C|u`JN{#Ov!)ryD;n#Y%Pi{`g z$k;P+qBPy-V~M#y!j&3t!)l74_@me7|1D+pNXP!CEs7!w4D%_Bt4J;y=)pfyjzFF= zdH7c&pxuh*{2gMvMY(&)JqW)zLT-R*ck62%Mrw)3r@m-MA}I5Rm66Du8N(BqB4VK~ zY-$PiYNP{DI4$s0tX`k#P?Ac#+j>%Qa+4XYSn&Bs4<w&dd_aReM#W*!k09;M5yIl5 zO3!sZ`8<*^p1sU2-!jJuXA3E4m~^{WmR^kPx7j`ueIl`XUNW=){QHf_!rb|SU?Hy) zSdQybW@grN_^?G-CRMvr{s?+5w_c=!EOcPvz_RMz9aawzooVic?S1CLwo1&!L<I?Q zPX?W$o0D-f5!$q^P`q7iG->bRj#EN!cw69N^4@IFTcJavMI+|$CPSSsU}y>;MdQEb z69ZZ>)&=2*-r)*t`_M6-Z7GR^&hv`lv||iek!XJE29%g@dw{<dtx(v;+sC~~Ru6;w zvn}o>%-8$*cM^ZIFj|Y}hse*(q@3D$2<Qli96bt@E*y=*-k1TsJBc8D^792-$=Hq% zp0Oa`{Fc3|vZOIzO-B!2)Y~xx2UFG=M0VFm*68e`7#dHBKCtgjZv@^bF<Le&*A-B> zKZ*;=v%y1Bj#;5lYV+;{FO)9)d^decM+LYf=Pq+DH)C%JO$mf!8Nb-}`nnY3o7>Ux zdBx>o@IGZKsxuVk&K`hLLT%0k6H4b^7zx%>-<J>ueVPFlVLAOzUfn=QAeFa*U!|=& z`D3=!HfhIKHGZxF`cg%(mRSz0nFHluKjd;TdQ!RtMF*Bjta6k3A^rwJUF^QqRRsb6 zwY&?0S;^cle%^Dq!^3;TURq?aWWXxujlJn!_d*qe%~lbTI<@ExlIY;~ZpZisv~BHJ zDF)N9ITO++o3wfnL7qQ78v8tfk-4>Z$;Tx)MNVt}Dr~Kk_Yr{<<1jO;K96@Sk>?7i zV#3*Cx@R=6g~Y38J2|3_>0GX5lSF^GImBP#CQz?c43JclC5ExhKo<p}E}AAo$$g(Y zlKnFDd8{F^@RwO7i+yJwH6UOr4^nhtcYz1xgtHt=W=xQhK3jI8?BVz3k4nQ1Qzb`> zpJOrO9(YHOxI`fVG#^0ZfvdhEft8=J2X_rXKOei49``Jr!<QA)cY_~b`X-55mQ|pb z@y#!<2*WySq^s=dS@}gzRNL-a1@}@an7hp7sF@#zB;d?-5~SdK2~hJR@MIyz0YLKU zPjj`;<I5rdV@W~0i@8z4sCFj3BR74wDYN&|R1@<?GvFg<WQ-52(qWT3nE=UjYcY>^ zOO*9zJJ+8Ogn1+iCitsEg8+Dj5XV)#lBpv#sMy5^$fck{uOJWGl<C_qRd?8M@vNP9 zH;MjSFL*dc7nEaSF%O8SxM1?1K4J=x=f!6Y;*;+5&;DEj>&$oX@yw^>K6wv4Jws5) zos7wR-HfQAl<`Ju+CP!vK_=1i%%#sV{Un_r7M0Hgq#L`#3L}EoAgXs<Og0p<YSx;a z7YLhAuaxr;8@Bh75bZ0G(6zC}*#@^RHVT&AHQel>2@j~%?rI=plY9nOwxPof4RFyr zQdB#ic9aLI7BHZ7f}RUc7l4&idd55&&~wW0(=I{|z@u97K#0HIgmU7yhS~09(7s~& z;0Xag2_7%#i7r<pYGw({E9=^O7GykKg0iyoo-aS-6%KDmY0!wR2vV4Yc}v06->XJF zO1TQ)k18u9t(;PY#;|<cU1%U+kNTV;<S;dBf-Ls5te=gd4ch!lE-DZZ*4OUu0YK&b z3O;Cj@4~Gvsx}^Tpl1q*fulHD!byB|QEPCuPw}=X{95`}Px)NavBR`eew%%~vQTUL zM2Qdq-9#Ssk5REQ$2m8lYe)0}XPt+{K8ORH5FvX8K~M~!X__GF3z`qoUGQP>tVROA zL{65UQ8<fqkFR0@?ahHpPFzS%*5TZDlp$?$qLB4`Fz@~sTM;A{-N1U~6q;PIU^=MP z@JgJoWQ)1-<cy>We{~Z-<?zs0-<)hRdRYWHmJQX;De2`5Pln@#%bCFAIJVV<r>M@w z%hNVsbyK}oa{ipqOXpk8wD(fID`0FEA4AB6PZa@-5kNQsOW6gQe-g%+e5Jn<!hBzm z&1fSHIzCZ=i|aF~@H3Ra2bI_=8p0J0+-Ex&E+0f-x@G@NxD_>*{$xY$W{Rm_hqCqZ z?D(Zw1AiT^JsuZ;#Y{D~w)dGce^E+=q6WbK**bWW>I<^Yv;e`ndLt({ne}%1LI9`< z(X7ZqkTBed0-6&i`;|*9@yEchx$UugNxIo3p(16>>_-4SKX=Nh)*7cXFM>hYjTlVO zUEei}k--C-p{GS@{94^D<~yjy)@jU%emDq;d1S(|iGi9=#f95#o{^Gb;7-tFg7`0% zSpNkFWB9WxcvX5IcS}uX68&9d4g+r1LImmlkRlKdRq+Y66NpD5hr<UVvhQo2OXU2E z{A;sH&93L)-ZI(pd@{%N6O-O$IA(D~;7GAN0H1TSU|{Je*wfw1h2Iz0Ri*`YZ@zM! zj`O^Ex85lp@%hTrIx&OAsYI35{A@JPPl(4@1PfGS2OjqeXSRp{|54Ol>wP`mh;GNW z(XPk?rEsvAiymm+j9lgX{IsphxhC9f)q`jvHu^BS)`X$&8{<oVWhs`_7Q@K~$8OkL zE$AfZW;uVVc%h7cCGUOf-d)WZS7Cyg^`YbDGlPc928JM<({b~!FRTJ3gv8y#6pLzY z%^=0A$ZEo+&&6(f#1e8UgABKY-v{%ewEmkRQ8sY9I9|o#z)Q6&J>p6NaLC5O1L8~k z^hL~~$3eF(293#|SUD?4xdOD#Kg;#X1qi&CetWRr)|IEd%}!9V!|;+`Wd7%%8S=@g zv;JyT;^Z=@XLZoG`iE?sNP{#;%0&%!RIq$2SM@z@g-KfXulDp+4xO%~XeG#MvN6tL z$QbaU>=yoOt~GW`Vm?0-N(Y__J*|XC`z-kvRXpWu3^I-9-Tc^gFz*D8pg(y7lC;@$ z+M7nIGf@A+#^eLy_=OL&0EE8)Z4LFkJQax);)rXhvxKIZ8}1016Fl#oETF0ZQ@Dd- zL23}-k3XMIRX8$8P{k=~$cGU%4V2_Xx)!tAaum8?xeF`js%b-Ex&^+4OXr+;z;f4@ zZeMIjyA?U4IDXzs*dZUK**O=hqRVS|7qx313)m$&SX>Ytqa_h?e+~FO%vN=xf!szc zjKj`oJ+eQeXxZJB70Z7%xiBty1OKMnEF$L*;H5cy@e!-|%7I^|GJDY>32c!h@Pv+A z_yB18_0K4HKnZ08T(68Dp98ZS+Qy+RdyAbCJBdRS96+-Js+C);Nm7*{s2w%bi9oZu ztHuUgZ7Gb-XH!osvnd^~=h+mG6ewVd;-ECal7|D_`ET0SK*ymrx9XqHtwY={2{<_V zRnzUJBD+RdPt>NKZqo)2FeH598SysNc%66r8zqO!!Eg?KT1(82t<KA^F)IlpU_yU1 zc6zCJx{D~d0lRQv`4aN0z}4Gx(i}`5S1@ZtzI_P8er^>jvCGB0F#$XD$X&+FBEDq0 zu?JH6Z!8c^<c0dbjSM+x=K~~LaVR7|3$^xEX9}0qqAr8Z{p0O~E&3>X)sK$}-?kH{ z@Mp$qW<J#OiWWF5Y}jjZ#QqCWg=lF5Ff)eXWka@NZCCU8@Fs~+iFABi{*DdqM07WX z@aauaWYd#ec0j@nw-)iHk4PQ~E6&uj+NPgK0q$p}|KK=t;!yubcG!a&ox@L~JFn~4 z>8?BPjsT%mb2A7W9I`vJ_-{L3in#_cW{@9AhSg`?u9#j@PL_h0fiSmUk`dngtLGhl z^L;YQa3IhCNVm`><boICBfQKMA1_^C2jAYDUVOx@>G=$h=(h#Kub10010wBWl$_Qh zpHwW2m?b;=&U&suLippzXv(%$RVOj}j!?u&O+}5R(U>=1!16~S3evr~?Vij3fa0%I zxWag`A{fxS^G2mJ`~~HlU?3(u3Y^nq9)W80)bb3PS!7;{24F5*U#28bg0b3n(%7bg zO5CE1F0`7>(aI3o@i|Oa9Q1^qjgZnVa4N5eQX;YAuXtbe^R%(4!g%I)d*M_3xX%cT zF!#2f+_o*`QFNR;+;pv_GD)sujVV!d>V#*VDBwx}LcdW_xmUD%G|>MhWDe5@c=j$% zZ3vF?6e~ol4uBx$-_0*T3Lm!H+J57`xy%Q)m0}6V?n57yNnAT>_Z09HaHMz7aY9uK z=55vVKJI1sj^1mzZZJ)jC09R68;q#eJp~uE<rORp09N(v-wHgBmHY=OOigwLC>vwd zF$}%aKrk!7JN(%xKCC3gMKGxApUtzS(7#Nnp(joaq1a&e#g|(Qq!f4l2IVv6lgM{C z7*bbsO&cSXJ8Ae*@Og>UEPTKj3ViK6xl!L#D|1D#pvXpU%>7X;g1zM+nZ1v<9$OA= zjCOS!;9O?J12wWc!K6(fh;bQc+AxA^w0{N!!+Qn<KCg>3D%hXgpj8e1Qg|6>zqbFe z`Q~Dhk3I@UZ$Zd76952!&C`zjMkiwSy!E<zbX~Qe0J^{35uFkq2&zu8*?*JWg=YZ^ z5h>t_B~crGF_Vw9t_gLvqA77(k`Op73peyJm7ahcn(JDUKE?EgJah&u@ALhleJ%sg zW}SRG@$%`7C{OC^6<+H$$>7RTx?1;Zy)N&}<O8R&u&YlWkp?y0^DzAh@{dY-%-Z1u z``igo)jYe%MID31)Wg%FOo1y(NYR(e5ViQdX48fNxQzXb`nO07UthSofFrc|)NH^! zXx}>dqtkx&x6T#0(-15JQnXmBx9+#fyk(%qYDPJ8cub+70Il!*op}&44`e-IjZ=ii z9-QTnT&YQVrvhRR>67ibMdT(xNOLy5EoDoxIot3kJc$bVMN5+UcPqG&Px?@nq!}q> zzUi$l`^yEwUq>JS@N|yYG<CppT$=p3nl$L@x`&P*)iPa8leJh;=zWx(F~fLqgml-= zE_-{jB`LULU-pZYBpZaX8fs{=5@M@X<<-df_^U>|m<yn7-5wJQTG$I|`Wm~QndDWD zJ7E&Qlur0Csmrzu`0v94Moge(g7AnPi`6=5Oj|m#m@LlDm?_}zsU^!3#yiE%&-$M( zv3h?q{?ynfguFS=hyB&(iLhR$lzwkJqZF;%Ju+E#ezpA1W~_M$3OB5U?mcsmfkrn@ z*`1cq2feM~mzCsM3?|%!DaN0#NV}dHe^>*5+EjYWA(!1X27_F;rO}bT&%t+-l0n{% z4}YS#r&E3k9lJ4M$B;FhPK3&$5Ahr-X0gSpCudJI_Q@`caU^^+M29TV@vtTu98}tl zlfcZ)ly?2m(p)qBz3c1r$6UmUWP^tL*opa$7&v3}92*POofdK8LxsA=JQHLIY(a`y z{)L67SqAz%NkanYXt@IxTyxNhmc;HeBs)}OL_S^*QK4doDz8~#^Dv;<t2^_aO`18; z<R8+Y_wk_f2zNzmwH<I~B8Rpb7*b{W_0km+wOFAIaZiiML=R1lHy6!@cK#RGxHcd8 zMfPuZ_->Q$?(OS88}K7Dm`1htXZ|xaGHgO0FlDfq>y~e8wWCid4j(CT%x{^{x|*jq z#r%2o%zKv!Dq(i<l0C-AR#W>Ho1J~#ej<YHS)wGyd*ZJXWv&6;Fiqu+iWY+&R#%Br zio0azp-oh@Vno`BO$3c&Nwf#xCg^y=PTuuvN}jsTcnJNdFqT>Y4LW}Eo*KJ7!IbD9 zX()c{>x=9jbemCj6c6D(?ZcDLo{46eseiHTKih*1#Bb>W4^pJV3A>r|cClRU%h-Xu z61~S8RZ7l^`DwEkW2#7nf-{D}f*${<tUnFzOTJ{0hk_d-2@GjA0`$8W|K!u``6N=1 zJ+Ay})s@OdtmgozrfZ5n=ZGKY-D$s~N1N3S9NNP2Rm_60k(%Y5(7ddvF8WKh<a_&@ zaT;xzk%Y^hG4aTA|HbHhn0miA)$^&5Qjs?(D|m9mKtJho{)wrvb?7+O)5jSc_$$}> z(6Nuhff6lY$%-x?xLh$;MWBJj(Ue2)t}4R&Z*In?i|2%i_FFtrga83H7K-W@;og>2 z()k-pJZd>kXQk4SvBGgC{}!5V&P85<&H5@sbtgG|-o6l<i{b6UhaEC|6-hW35v??c zC}bt@&co4j=O?qFy?LS{(i%N?Yi-Jp#8;PkPXof_(%&*kk&^lG9p7dn)dQi~E%xj| z!Gf7vJeji>wlYaS>AjcVu(!1#eDuUD?A(D!PpSVK-t^we?J(VA>B8U9Yt4!!kZ6x+ zc41<+P4CmsJb-h*{BHetfk1&iD`(w4sVNM8&Fq`?)ifnwqGS$czJNi4q&wCh`uU_N zz?PYaK~zqKR3pT<eNkrPNgN3TK>a|H6oYea{e%lU$&l*BXXsM*NkYj-1636-xFrb4 zD!Wf!`{*GAjsPp=pljgMLd@2+7)assH|0-kN&I!HEdCb7o!0?`AQQ5*zqrzIgKw3e zyYnkFGWeWpCOT0vlAV?t!TNydGnTe6Vazgf`<*16gE8G)-sDK}@J9uDF8va`<C#iX zMzw@_t&eXtuN*1z3|WgL-@hRtlXMyQ6Ty3wH^jgPd29deOrlL?(y%4~5!|@;Elp4C zB8tU6mZl~JlluV9Ta*4sfG3pp$r?SH1H8?*q#7Ul&8w&OI({)XD%ZT8qFxZvdY2gx zgCCz0%KU=O`<Q5`>Ob0be6b+C9@Zt#uhuo{Y2^ht=~fme>`jU(k%|>MHzs^r8cw`Y z98z#JPF{Xhvr**W<^n}r&O<`x4Bmd=IDXK<1=IRJ=d7;fak<8I1By6ZCrfpUvY~2( zm1mk>=b*i*`nh4##Z6F8R=PFvs2}QFhNm9U6xejwhd${6c-jA0V7%NDhSu&^6<QS; z@NW{--?6<`yc^E3rfmux#om=})YfAh$)<#^Fi?sM&AP<s?%>MQUNYEfSg6S+G8B6v z0FSO_Zl@irypsi)kdY65KFPyyTh}x(!6a?@w=T=pKq8PKg$g0VO^u8{T*(KnnF}Zo zMdd+4*5S+)t=_P|s3s@iQQC7B@;V7pt_c1K>#Zzt7$8B_1A6)9TD7sGowdL?@pmNr z@T$V<IdcbpB0Ih(UHb?kNi9XJQJ6DT_IZt?V#>)+M{$!o$SyjgQ`+jq2gV^(d+A1t zKn6<t2+DNIv^#OAqqXV+;H3u{#$F=7bX*n9v|`#_b?<=odI|SfreheP@W3bZ2)D=T z+|J|gfiE%oj6`!-1hC#|^pVd;$SSI{)MBYpy`&1OeAl857wfBY4DAJFL9l0X9dzV$ zZa<llp-qL11v<)~bHa_n5ZQwRW(X<Yo@vp*#Ux8GTbu^~(6AE}NEYt%Q$PGhFgH3? zf%-n-4`-S!a0f2@Ao)*o;ishL@gKLdIvs#S2d<3qI^Tw#w7DH5K}IN^(Lq>4ZLopA z&AlN95@#{wg82<sKBMX82>2v;`lS>02I93~;x6u7vFh$SHU@HCUd9oUEja9Vr}QSz z2i>Q4WLkg<x{>pZgolSw+K2~mzf-}!k`YeEK$4+_n!rsB9T*YBg{No950-{3mI(kP z-v-B}@UGBrUb-zY@T1B9KaDW`Q@`O}uL-||yJlW0ifb>atMj?%yvzRAJliPz%zsA? z!|PE2DUzV7<p%nY71r*Y2>>Ib!mV*6@`zGWm1G~#gaLh&12Kor3MrF@g)hlpVRiw- zpefL*Sjk^cPZ%`olH&EGT@F~xPj>!ug@XDVSD!@JZZ8pSkZpkjqzk&@;yJ@<;JiSN zTw{x%q>s<9<a%B2DY;F<UcN&mCo{eP#orZz1v}p9y$W82d@uNk>^PM;Axg?V6doVd z-=<RoO#TpEKd4hCx+Azwc=<weim29Y+r^ip%607N)+n;?;?L<(b-<-mELLs%m)P?^ zcMmj7sCZ3&EQCKTFP-n3xW(U@F$;lDd$PzL7jy63yGyua2v9~oio(2<6!ST~$-j^p z^v&roTrlg3W`lUqfVtscH(kV4^PCSOCuXFC`y{f#K~hQJi%Ab8U)TKFcNk~=dmUB8 z<`LwCho&IiSg53AJ+-WwZ~@bQyZ$@82%f&`{f1i*$NSLje-6y?;k4ju*bX7^Wz)@n z#(W9p6>#O<;qt}U?g+;@<&*^QF6N1um)8*R{x-T*Nl_4`_im%1T3D`J(UyG`=;pNb zMN+Mi!lnRw@(EH&^B`Ui<y&ah0&!{1zB-k2jky@%{ebBm`;m&%6f}oNn-jycm2u^c z%1i^mrxjZhu%q=us)>1}n4Eg8S&uzD{_ZF7ALq5?3DWCo=jz)b)BZh|S-PFq;r2(c zP{zG^f@tt)E~tOE>z`hw36n?3t*WHn=gS-xKX}Lsa=bmJ!q4k0`mp--MR3~hReg5K zW;UuTqVy~{Y>sC^=sxd&7}pM>2Lc*I9*%dy%ofp$I0AaFG<j`ibp^ntXE5aD=r<tM zNt45$u{UC{TPW?>lB!<+YH)!v+ve3Uycc3Hd>a>3KKNU!Nr?Caez{iCCe!##&Chk1 zYQoG+GWJc+37XB<$~<82jnlc`eSm5)mqrE@c6gE{8B!96(Lh2CM474A8Hg*f42#ia zI2An0ezsza0TYe54ajT4w@P9iJjEWkXkyy%sPAHl3fH743|<J*y)vx}keMl!$Tz@4 zhe}lx(d_yFr^Dq!ketO^FuC%u$MYB)u}TqRcMgG4)h+7}DJ|JqCqw+$>wbW_I0dOQ zQsz!##RaT0qD2l2v0K;Uc`2~_njCQFIPSzsXIoK0B2qDpbNyoWNG>a<aB!RvL-;D; z&D`a6WK%o&5hU-PO;7C1$9HlfJiO2($I|jZGbHb88Vc|gfRj}x!c~uSLPnn?YKhC9 zFqiUxmVl}%0r3oyf~;2#w7tvX-i&|g!P~!8YT##T{5xeOAKo7HXt<sk(~JL-G-y`T z32W~XzxEh+0xuGGV~=F(ZQ~zs7G-WG)veb#FdX7B+r$sCDArw}3H!dUVB;WJG*@qc zw_!cB&Fs|8^Hx{0IqP;fJH?~DIoo!cuha*#QX<6_nYJG*#$4CWsM@NnHYr8NwPNu8 z{A$C)o0DBpK5>8dW#xw5)mZpkJbEUpho-9AOe=Az8f^?Mptv#vZTcZDXK41i7;sgp zmEU+X=+*}H2RiO#i+-cJE{D(eCvdtP8XC3~byKWlbO*#QHtJX1JBiB~vWseg*Q*Nk zcCS7djnULPBfPkWbZ3J>R{p0{Le&cQ4)&P!@^U^xD*Ko)A*N-QI&4-5CIn)!{n8<n zZm6!YV*M6q>9iJ0<@3pU;{}cG#e3c)IWwM`Q%7j*1&c=6SMm~Hjb&y%Pm9=y_wQk( zqpoheWe=Q6{;4&o)QUPP&dA|qU-Q<UZ#VYRZi)4HMf-x+vdKSfMF`i3kGx}j2m&yc zd)wgq!&=2596;{%k~x;sL+!a9B6+0S69zxWg9Lj7)!jhjFD+$FUR4){YIU>ZJ)n<T z^hd{InwHo2|4Y{ZyzGFl_vbFd6XlCerHU%Y;YBN5GCWYBS~7bDF(h|tTb530nxiNr zS>=LkW1q}!+xMN=FLCU5F>-f0FbYc{sC746g5-|a8eG)$tSH-7GmC5NSS^|Le0K2^ zx_EEl`MIEMb`%;Da8x8@XZE=~ho_}ac6W>;PB0bfvIk%Ir)q$_Yq9VXqF-(F6?!9u z@FJ5AZQpCZFv$9GddYY<6A|psLAJ#5$?vZ4A1!rko|!7lx=OwuwXA*&h7vzTaZ<=+ z7W7!mXe>C0E4>7$-h5unDRvWlSbU{c6c?!1oa5qs+cdQvgFBt=@+{4->-z`c!nly& zohZ72%N*`l-!ZVe{G~1}h)Cb^-M1c}r6J7&v4!wvlpPp02}BA^go_%#%)!g~OQAsg z^vD*bgPpOIpannzaCf;s2~h*V@*!XvSl}LT?mD9I3-ju5XBXA!Df?!I5J;vx75{7L zdviTJ@#bc^K~T;CgCM6U=TQhrSaXypMXfaWv4#n?;6(f~vlpWkDz<JG7YT~{QcAwV z-`3jE_X0Sv%)7QK#}0+|T)Hhv38jshNw91Jbmy582B!sB4hqM}<WphQzDjIg)$3n{ z&^(J^^Qm2P`AB=7v6=U5NtkW!qfLI8skFktaC)Sn+ZLBI=jVN|u>H2M93P16!E4@M z1^l^X`Hi%2EhpnY+A0%<y71kLdN~Z({K>&t;=c^TwZC6M5jMLL3oSq2J(Kr+Jhsy+ zKLiYhg9O-eB8M=`9ZYERO|#H6fRTA2Kv>%Dc-Gsoz@z+mWj!0%;;DZP{Mzs~`>qiG zE3(;KABkqn>i6tUQ;Zcc;(P~Z+u*~DW0vW!gioX+=mF|$%eN08?SllLu<vi~^M<uc zlCKKtlm1h?Cy(>2)(wDZXvWhQe0_@l7?Zx6r>G?6ob|!Z!f&6~4YXt%h3Dm>8*zV} znCM<-=>74GBW679VX|xM9GS!X4vF-Gucf~tU9;8qe2Mm9#3g*0lHXiiu#OTJOZ~bD zg8&_7&;Q{&w$qRZ%q0A=?NK}8OS(<ak&jqkPP2fO(B4#j*cH>bR4g!_`NkmM&Jb4Z z8Xq0q9NdYDZF^zq@6q;jr=t85qQiy&>4bLF33@7J-TrX1Ll-L@#wXC{syTX)(0d`} z1%(zpKmg-%?jd7fs>GVsLUmO2t-xbG3t{awHFvP@x#Bi(;WQ1jT68nUW$8dTcj{C2 zy=F1N3`h9>+#+&O;mQ^ETWww5tV^0nZx+&ZeCM3g{YX+)f6hx)sZ`uuymUB|8~-N; zX(Nk?HNd^&k1#~A8RnC38-UMjv8_3af3#TCDmy21rIIiP`bsOy1Gf=l<|A}NF@h21 zRK6t>ILR(LgO|_akb50P8V0gE@3LPLebrUrA%E5gb$Gk<VEjFiEGH1IYOVtD9xoW8 zy2eKJO3LxRqnef!D+S2JBt@W9lTrz?69XxkML<8&*n24epq72e2`?b$BKyPLQ@NSf zgBLi&U7!%VeBnR{fGv*KV{h;$WdjW}LBHGOg`ttpgs#bLW5K77wS{zN^Ah;ZzQdr! zqdg>xd;NV*D$b9>2mS4&6BCsJu?xnyD}1YO(=_;a>G=3{NfWQn>{ZmM0ih-~*aSmG z5o3ACg6=mHWkLo<aQ@}Fq0rvM75B3qhU^={vY%=>=(F4s*OqcSXyb!V>+)vBulQ6U zt>eegQc|p(gjeDg`iKBHrcWdfp~Q3GW3N=#Gdp;cbIRna>*6EM`x)Zx`lx>{alfVS zyw}0z$}YWGod3yZ&b%6jX|;k-x5B@K`THn{^fg0uMk#eT)2;+);!Lc(9Vixze3Sg3 zNUO+&{^N#JAB)WcX(U+wFvyaurirf7U_DNNtJI};7mp~1Rkh1x|9xJfr25uQx6;1X z;i<?kaz$v-6`I9sW-93XYbGFq@X=HR(2{&y7>qX$N|=r-C<~j>mH|FS{`(8X9Ka19 zGX&_~K=?Qe;HpZ_>sBIhL8T0sBh7@v3o}Hs_zw^<#~7*y9rUc+GlF%^{6YlV02krE z%=%Ztj&D6TA5^f2a~?LH<FASTB(QEZDQv~FFO?dbWBOcc!8kl&6D|yhUG=Tr;>&1B z`zhA;RlyL{_<K_*jW=t+P*?92^M>SQLDAn_uD!5<nZF{gNafd>>Y@J2#eb-Zal8wi z@b6EW1iGn_U3%}nOsw8Vns9y@>u(&~%SNM~<1HBu{^n;6oEI2=7q#DQ#PM~>k0%cp zL6Zqe@>yDo-Z}ryxOZOIcVzQ8_ls(5LZ_vx_sjPY$@~0?P;9YOYYZonS5hF!>7~Nw zu%)E1%>9%^#QkLj0O_d{2ZOdn+r+>Sq?0bzpIxfOZ&;ZZX6`@FprH;GZ804lSctz| z!2uA<3RI?Fhq>w{bcXgRGVQYd47+|!F9$B45dN^T_#i|7^vu=bl3vz<V;2#$Dm>LG zNi3@-!_LaCMR?zfeR@YVc}-=>2*TJm)J0LIu!|P}Q8CDrWHwa(XecLTS5U~cmGU_1 z<L~pTY+s}N-gFzXq1?B7@kni;WjZ7gdvXX>OkY;?cWfcQu!y$W!fja?b!k^V=egQF zh)!w|>}?+PfS3rgFPj}bEH504594H;8~nVU0J(B86&8>ntAKcaRhO|GH|z5=>}n>* zJ&DXhvGdZhTH^V|Eor~^UTr7<;vF(HpEEDp@Y!wJiBZCMZaut;{Byy6{IH7eQ7-pz z59;)jO7A94v;ql~v?W4&X16jcb6zZ-mz}tnxJ%`7iOPrIIuk-_7$tePC{*kwQ|rf^ zWQul^<WYZ{cBqU`u6hRMAz;<~RKV0N4@v(ep>h>iejtre0<*_S(zA)<%IC?zY-W`3 z-{%bn$^Ni-vf7&ElX^&wN)N{+rlH7o4VnV+H6a8g_^!$)>z)k6KD~`ff}@h8A=f_h zG{ZhW73OW<LndozDw+-@AmD04rhCkA&FNF`fB&PJmJ!Adw<bKv{N<!JLi?zc$na%) zpUEh8RlExJ2laX~aLF78b))k&{Fnj?47)GeHwm%_7JP6O)jfBk$m%ChTHz<<KFa5< z8Y_Gt=%Fm$;5)?b5r}W1)2}QgKWt;hlFQX9Y6MVoidM{c>h{>p;E}`kV>w&8Y)oTW z_IJv3B{EOxL=P{}#%>OBVvyc_vF$_G7gzw;60mFCN6@Dfl!F@Hm6Zkgz-ItWIhSlb zpQ+k4fmF|nN<iexnzPGmm{Nir@#4Bab*bmY4lU0r9S|URnu#{<%{5aFO}H`zK7CDW zMbRv&y><;W`hHGcD&+ElrEX2-^-A6^4U($Upo_`KHp+q&IX?^dDZ8!r*-oJ9Sn=8H zMv50ucYbOr^M&+fs8|XLeh^)VBimr&JMcAH_qr92e@hHwh%s!hWlI=!rxbPDbe?-| zWK}X-2}TJ!LBfc~4mDes3k;G)7`^7iM1Dne%N=uncp_YaBbsmD%mR)sW2&;dcqt=R zGpHLp$;d9x$O{s=FNA>sEx?#b(Pv0|Z{8U=;Zwdn>Vy3)yc^NT*IGhu)|js(5QdT- zcq)ug^^x+;sqE*|P!Kz0yM`0Vk|bhLRD_m<@d;?*`UxKpD?qSFOcSOL(DLk1mW}o_ zK-l@9ZCKs7dCWda1bc(pd>#f@u7glzvVS(1`p?8dq!a_lhmV`rP7Gltx<pOKkid_= zUbCrx`Ov95MI;wv0Q6vv;TvX8hEdHU@ayxW!R-wIU`=JVz=-q~^{p`)0sts-aCv86 z#0v(kO#71f`z4@*q1Av#c55+?#c(iEUZA0me=>VO6<G%OK$@3@`f_K_4Kxz0VWS1- zY#lE$<1x(x)u-T5BI`Or3~!}DPad-{O#ICh2Z*z@>TzCAccK*z8vsTe!U^f~#T;Un zxbg0G^x2JJ1ON#BeJ5!_zl!+wOBoCyOr6g-kOeM}HN+JH7dsKTl|22;7Ztf5^hf?2 z6GJt@uYdQk*Tt!r0~bb&9oQ0l<p<J0f)>;qd8pIpG>(`LCMt{qh%GAf!T>EXNz!P5 zy(Mm&&fTYIO|1k~{#)Sa4Ev_!8Xxg&5*Tfq0jAln{N7q?wlqLYb?r^*-OXC4s}GY~ z-wy2zmg_w#;qo*UM_5kov7gDb)Wc+#&w>->T$pde@G3>`^h&aQGZ}kFco7a0kGu*1 z4akJ2@V3LjE_B(>hTLF-oNRXIn`^a;Q{4NX!W=T5o%XUg>hx6JMfmG}Ym;?p32#H< z;Q=U~!qQ&){PP=4n!wxqxzPs;#cjHl_z8sh@7T6<cyhT<RYhEZPaUV@1VqmNH2+$R zwG;s}><AR11;u}+^l%Gb?bhPM8h1l)J8v*aSJ2nZ?`kpCH}>4IN;i!3vW???NXK|w z-W$Q^V>FPacPRk;$-UX>ca%<+L}qG0!NTzsEL*Ga9QjwMn-q15*4?1r7U=ur{f80t zdj=VD;U~vr#jXH9qu;9q*;gI$>2M#v^-QR-L@}7Fbl@h6KwU{aG|tKVd9*q+MHitu zu}z7(c!;E{H%-;IaCm3na2MaVz5kpXDg+%^>IM#jKoKyq8M%F>+Mah1yA}_0$PWpt zqU5npvq$}UH6D*!$O6noyW!q=JI(1q>>eXkm2paQRDXn7kI(!p{aoQor&k@IV8h-r z-qUjdHg?z<u=QwVFtZl`@(F-S{mg#DeU|9Y2V^UWq<-eL&iryxuEaBEkf-}(a;g&V zj)%VmuN)B1bnT&#I9$*60MBzX_&yg{6(15)@1;6!TPKh85viizSQ3q$*&MqiFrjps zHl?TA<2ee0pKkE#E6BP`yF`b8M<)qgI{yipfJU_`j<n5w2m3(RAVZz@{)a`dq?qz- zoh7!>H_<@JFa668AJGNS7IMNTEMuU=B5aQ$W<18T7}|C~ca(ivC+~akt2k~yAixl| zebq0J)8{2evb$fj51<SY6&+Q4SBtjIiAZUo&LK#w$=*5+K$*W<*iU$Ca}qM{#Kr2` z$ft;1X5WU?M_esYwQ8(GkY4H`l^TTY#H<69`qdgUcbdGwXZx3LT*%`n#xp=Ajfw0j zGcb!@MW(cGfzdUH3&Bf~X{!^NLuZOJg-l5}!IFBW`H$e;m6RvWK1KAejc%^=1&t1Z zw5L31_1y3xH|<vLST5w2u16Zmhn=O8dPX!SO8Dh)DuwlLU*JQnMBO7G7d5=wsSmV^ zV+Zu2CKvn&VBd!&B5kP84PRA#4^WSAbRy(#$=lHBg}CbKXD%i6YV#SU!^vPA@gS)g zeZQurW_3Zi*#t|?MzfS2ox#QGtBE7&c&<CJrH$q`8b)_e3rNRVrE*ih&=FKQ7c+ie zvJG8`isc=DI&NuuR+w>=z9dLjh7fOm^8PbGy*EVHXmYzpMN7`YVTSL$ai;I1%wb$D zM93kkA8zq82mr97>yHY5UVOtSdZvDzIb1IP_1u8g>$K!SvfKV(?*FNy1;;JG<amq3 z+)DI1Op0^X!j7PY-c^;euqg$+Cyq~A+Dab(@{X^&Hf_cc6YS-LA--=iO;S9!zFBAl z5>VL-TK{FPEU$IV&S_CanWssz^|wTm5zKJepQr0G55Js=)5ydYf0o4_p6Z~~buMxy z)_$6I5TQ6F_xi)R2BZUf8mRlxTcq>R$?d_UuB9L8z#*1jschq7LsY6J^^#PjFZCg% zy!W}bgH#z{V}@PHFRUwf4Om!WM;M7oU5T>PQt;_wP}Qdq_v>8vU9?!I^-mELxtVd? z_GS5La<T|B86}_!!2b*xmz;s~$bdiI&vI);h`!P-jVui5q!Bi+Q=jAggT#6y?m|`- zJ~VO<r$U62+|LT$ytLudn}<uPWu}5d3@Vha)0yCe`<Q$Fxb0ZGXhou(Gfu8+&a`s+ z4fVjMgT5!1#i#exC#?LS>q$h-0pi~a$~Twje%TnA-ivX(ufcIqc_H(uT^^^YgWZGK z(B?rtK$&jM#0`RBZ@sFv^Ny|zN+&Ee3gzM~%=%=Dae+!F!>>j?hY}=ec@)TsfcqC+ z+Gq>1C}VrPhNUMH!o$|0+5*n)L7w6B8WZ8Jo;Df@TLEY+oQ_ZS$`zIP@3&f}#}ViC zC~+gVx9y_>S?)Q-EOF>~lmpQ_H&=dzs^cHZQi~4CQM`GnTmrm?%1vQ@wv96~3^WwB zp*+rHMdf$(FyYEJjO%cCH^dsHtoM%ROy9GRmd$B}x-kteF!AH-+!XssjXA4Ie#uP^ zh)aMx<8ueOeIM1Y$G5@w66!i>u{6771TJ;)woA&qT#<>u&K50a=ckZL>v4|6t?U)J z0S;zpJ|Mo6=+g*u=+w|Px1Iq|W$s-y8&l%|g)A~F|6Eq$#>_%mSAl(MQj4Y&s-}O= z@X#O~z^vIXe9W_4;C}7nazx0DC*}o|+74+K4!^lT5+klwYbug)`7R@#cb9>!0TNO= z<MQvmjCr}t`#ioaFy8facI6a*qafp@sEKj+q^%6Az4QeC^{`Tm-s_?0&?!|w8Tr$- zH>;Nd#q7yX0N#4A*iOIgnm6*$nK?LpTxtE-EKx{Z_1>&6yc7RUcvedrbIaeamZYw} zok<lg{Ig(Bsec&OOVxVy=O{8#W0hnw-04hgRJMa~wJCh>Bv7`d(+OLuPRbts6TE@d zbpHR;O#LUGm{y0H66!9E%>HySjnY-83K=9|Y8W^6m?WSo!qVm<LjK;(PtYzA5TbdB z?HT4$-ihn4jhB2?t}HY`Gy)V={D3-P)kz5tcjPaNPiPdmE}o)G+COI19Yi#cI^gD& zFP|I$^%NK_FEIcFXgHt-##2JK6wLZL;=(WoBFP1mvr|kv!uH9}grSp1U7KbSzg!p% zUjh$zEr4|t4Z-JI+Pu4dflYi&CO>6=<4MXTLH?>Oj={grT?~lh`N6xLQ9-|a*Y!q{ zD1$1J4LgWU3~>6j758Uhmi!w%Jc;Z5Fn|*ubjg11hf<6DIo&My{p>C<0D-(VOLu<n zIn}J)%cZ1{7Kv5Q19XE`Za31gQ>u`?2+BW8j~_|IoR$z-gk$z3F_+8JIomCicI>~# ze72RpfN*QJ)ekMfH#RSAGBc-j*XFbO+uOAJ#`Xf>5Ru05!SvUAI>@m(I6(whzfFhZ zhgpF2hc6Q!zQRfx)|1_C1KYq`3e*eIw4QJ5g(JQiB5=#8!$}<xcK0~~0au(6;Qlkl zd__mp8hcx^<@K2UK+(@7MfOrk2ZYbc7^Kx}=%LX&vf4mBV8%&Et-s9;b!Xb(YlX;` zm{jN>7_8j>y$I9W&#OD@@U|wBRn)jp!QHy0ELZY#V}b|J{HbwVw(BkP9P}47u8SsG zF3H5~8?k?x#z=us=T@JH+S*7Guf@g}&wVPfhuoC2?^Hk*{g&=Unfe3x>BiEk#>W6_ zyfVgIu9>*$t3#XmwttP_xB|X+CzltDN`--ZDP0n<F#V&J4ZKR;#xHPS&r1UTf;PG_ z0B>5gQRF#W0b2_uakH_GMBxz?mb~_nEm%GmyLv}})?MrEi0Ii53`Y6`QilH6N+Xn< z;3OjJ$}r%j>eK;!4i8d=*RgVFPxt<VfKMrb7@_HEbUVuqbCPb7jBrw2`HdsPTOH9u zqc>XiCpdD(&Z1GDnn>u2IsTepyRc@@Hp_qPCV61$q?}EkTY0Nt?2F12Q=_k1$XydZ zz;dH%9o_^O=Is09wpU-UZ@!r@u=k2wmGDDf^_LaTj<9xZU>jl)ZY8ppCa;)h!ncoN z-|(@&8Ybps*&Y24`_|?;QuXM#ZL6R%q#gS5;UO-!+nr(oS)sBQ4Z80dsN+`6mwF^F z7<7+^Vy!)@ehy*Ts}g)+Qyc7O3Ri(+RM!?RVut*KO_Nhw{h094BI{gZ(&eb)M}v45 zk3-%UJ$nOTfn<4uWZqLiBh{@91e2_Li~p~v%j%P^?{MZ_*k{he%0jw8P~Ha-KAEsL z!$;P8eqKAEFN|RBmj|CyOPbP8qi=J^7)|i>??{-gWOsLH&l{T@Fw_0URetJ0Rik8J zJXFH=tjz@CoFD<W<57ZIg2PX6``3%E_rG3iMzEhr@D=uV^wA7U2V>Nq!8Opb4FRAn z3q`QOkrpu9$iuI*%cyqtA1^hR?(!~tRo+HQGu}seEs%H(&;(dc0t>H`)tHV;9ah{> z78CJNSp5-~->9n|pyVXtYRJtFBd!+#D_`<u-Lax!KT0lk>bp-tqjeiD_MZ!CeVU<+ zlH$&8eQR8z&+}BqvI353v9+wb2jEsOILhK|Ar&6M=EMPbeVFEYW(ilWF}4vnXnY=> zbTk4<vWQCBgfjyCX$#6=o@Z69jE(3*icU5DuS_D(sm@~|V-2Q1sLonzLoIc8b`B)Z zDWofRJ`2%9dS-u3u>-C$w8}E~9t-9~{K4eKzKD9M7ARR^7Uey8x=Zp2ea8~`?4F4A zHIIvd7q#e@dk2<^8`65_LMIau?0<{mrF=>2hk8SyEe}UO-`d>yj}@eym1;NJ#fSLs zl}G7+o$f4wyOA@}HJS+sXq8|FfAOdCuje4=Cx=9OB+q|AjWGIcp+H$gpq@DJTc{`= zT=Kv6uCuMlE!ZY`)5sf0r~yI=y#_+>(h_>_ReBHQkOWYqMkIjPP*Jc@1W~$$s?r6; z0*Z<v3LHf+fN)eqQFFP!;(odFdG?;?nJ=^V%$l{tp+&{WvF@|wxS!-qB)y@q=riv{ zdqjeK8m)EwX3#)>kEa6BL0s2C67-$>!f{g8b}$xDJr&z^wJGG7{^UN<oRW47iPxyH zZNs1P;$6m4&p398E2B}s6)Re|Ye*gI;o*C|5rfDL_OO`AnxgqUywFIz4uT!nqgG(l zZ2x%4Ugq<rf43^N)#Ty#AaV3L-c!CEzD<q|MpPXE9)-ovbs?}I8NvSoAvyc2%<W)R zqR?;NEO3L*WD{*8Smtb87OY=xBX%$hBLLu!DDZd>I{oIz-@G*M2>!jJX<V9qtlg9- z1xt(i8m?q*rRIRY5V%>`e9z5g<pEQ2#GX?AQ^W(<#L7D3DKt=I-Bw3k8E#<rale;! z|4fhebAEj<e0S3x`1*lQR{f&IhZg%BT=$Ppc!><e7YAloRMEUM9c!Vgz}g6x@4>+a zuQK6hbtkx)HlmH{*70wLOkqI+iT6|s`RS1Dkb!Io_Cm6jMU`lR<d-C<XxHAuTe3+w z9(<7TkNGFkrExs{s$`l#&zu-P%wL^)mZz~~`=a2fWUhl{Q#|svT|hU=GQ&DJYGwYs zy?!gYt26XDUzzk<ZZ_kP21n@+Rx2CLB6yfntkGhF<)W<7PR9qhyZDG2!?bS&yUcKr zqw6y#^y>;dJLI%Zz=H6I&Rpa=7U!3Ne;4q*VtpY8y^<Yj6{RB-KT`9E<dG{UHac7u z|AiKJe@Lhy-h0xK+R%!28qqEX68S`f4{Namg-a9X|9MTFmULGi?lCy4FVZoQ{T+iE z>blJ}#rulO6}EaDw1Jh<6w_WiXhH-v_c+uta2PHATq+{TAI{0ULW=NUj}d))TQZ>{ z8q^J|6kZJkxW;=+*?H#L6mk4xC)c!Zs3@7G;{T^n!Or};ko3`|a8aqnHc}|aQ=@Ld z7UIZvwr=L{`?%u5<lS7|gYp|%>wNf2Gz)-hkF5kJow_%s=!Nr4e14-1n*?`FHn2Gv zqhtn=_f2+yFVl}WgjAC#Rd8u7{au%r(h^9xqGXQlv==x8My|H9E)0F)>shUzJk~lc zLY1$HDdXIf<*!Abvem~M4~iXEni9XCd@R`Nv~DA&R@|fL7^n1$Wb90Lk#o3%?5N8c zapi`rct{o)?V=7j{(Dkj#gCqNdSwTX7L#oChVAZX60VoG#W)0K1!5B=Yb2?&s{#%* zJ=pIvRy9i#67nWIl-v%phgvM4U1Z5C41n`fDbBK@pfd2uUxSa+=MP=xJ}L}GTwq}f z7GKtF){gwd=iQKqYQPQlH{>r71qQ_%n$Q?GeSHz8X_*1-xZx0*`{wl0<CD275 zXAS#|2lqepPjmM@Qj`K+%;1aYzbRe*vf&wzD-uv#ZWdAh!sZ(5^HEdP0cwlYvE$a; zFgR1V13zETS7oQ%-_LQPDl`g=HUbFcBb|AkX+m2&EB+eR(5;e*a->9h&pr+Cb2P$* zZEX6blVl3lLKmzqZyo7>S1^o_ivKTD+cKEPYv3q)hA4@oWo5x$o@nN)3)Ih19KVSx zJlokBbm~-pH%a)~Z>ioIO%s#LAP8?80)I|zaj&+L3(bp-8~*V^fXUN9T7jqECMQ)M zkj|4W88TV%u~Z1KS=FwP=J9UdUy@55hMyhGM_M0#82rNiOW_3nm4fRlQmYK0qz3mM z<}?LYFta~*T)a=W3i(=U-|=5gVRp*iMYWc{FLbWVZhxNSdI}u8l!g8tmfqdgEiEEo zgFdJHSBl4*{ZJFjDHt>jv8Y;O+els%U!!~o_nemsx&AAX8ru-|xA60@Zrar!Y@RFR zy!yYtH^;mT1fk$iY=Gf0YXH@UT{gK6CmLnt?<>$9Ntf<Y(}Y0O7fK2n3lYa)7kzD| zSC2sYRziJWq^O{edF~Oz>Z|q7+&Eb`by7Xv1SarS+jHB4TCfE5s`tD*?OB4K^Rc*v z$Wg)?#vw<B3&R7>Z8<#Pi~bIGa>Ts(C%w|b=<SSAzC+Qv`pVVqfUMd}_ibY{feZoG z^Q}(OO5fXcie16qtF1NrOjwH*AL74jqq}gotQNoj<_Z=38sW2g`|MMRzg3Trg)kng zQU4NIR1(c)nzAIIf6`2*n0S2!8BmB7U^i|#Te7K+btc`{XpdhkH;pgTcpbk0nI<7d z{9urVBf%G)8|s$TKL(nzYrIOZtVNfmQ3C6w<S=OijbB$6gKj2S%Xy>f2?y*%=WM+6 z<GJ!WdsB0>kSNxbLM%EyT%`EOU%yQ^bi9jMyhp|fzJa1)s?yaa3pg`|v)MT_9X=5> znkBf0k}XUZ&l2Ll?NapgjGU9`fI;aKyU$#p+;>w|m2BiP+PVns@%Wnv6-ChrH9kWs zDtru0`mF})c6_@y<|O|5j<b(E+nEa08T6K>bWAj!TJX{K(3iYxOT89nb}Q^_@;ILy z(!q)!pG-)zNrTp*ysot=+qg`;QZ9=m#g}8wcI6+*LMK7Ma?QdT(^-&u_wx2A%);Bn zW`Mube)>6hyPA6K(&#pO0$PG7aU|DRlWQhkS6lgP`klO@U;K2haqi}u{~33s!qp2; z2!q1(EE<Yn@*@BF$aV#MaS%oHAz=p|cW%;f2U*mlsWBz>pv}4A67mv%tgjxxgodQ> zH|BdRxWaF&9)R{(lm@;oOf<AzB8-N%DLoW?ArxA?ClcLbA<t=Yj4K(UO{a7)Ba)IV zG}NEJ_Xmc)zzTSftT!bqu>HuyrgRbq?#Ue*21P|5hA@E7A)p77p0j-y_S&YXtDN(D z>OKMn82&ISh5l;=L)_vb&k${FX`S-NuE5YX|9t6%J%i=WZ@i(w&;Wq3M$eyUsm5B- zzC>fqODWcbyq+^nw7^pWZdiE5dV$nqZxI)LC$B7Foj2>n*Hx|8V)^A`_nCAkT~Bfe z2uOuaYpLH|=J;Z#g*^L9M>sUCkkarHVI`QI-{COc?ctThgugVrQ?^}0-LQvNmmToo z{;vmp-$K)$%Gyo|!49&c@VnK%DsWsFrT^PAr7qpOyL4fC`Bu|Dfb)9g-5-ii2W`VQ ztKh}6sbTBN?_c1~k>1i>f8dJ7u&HO0<8KsdItyn{Jm<17d`6|iY`bT$F=KJvo*J~8 zo!H`GvopqJfC!r3gIt<CLMz020Q{ZSZhrAU*LFX~OTgZuavgr{!;|YPf6c_#t9{ON zoSwM&L+ROJ!A#A6?m!@VwC}r9GcWVcT~dTPzE7zx#tkC2<Zz=t(CN%!m=MhSeUU$9 zM#6U92Iicvdng!M0%M-!dX5em_KR*Lsz3)b_+m$3q!l#^|M2Ed4IPQ2L#@iJ(Kx|I zU-?PMB~iT(ek|o0@k7{p?9kpu+jk9Z9*;W^55IW*{#x7#xzB~IA`=iX%2t+e<UXl_ zQdon@(BV0b2-V8q7a<Mm?b}3KO`y@Go!^*T$WYm!sLpmCDEsadx3pF^74h~`i==ce zTQS($(~3r{gNUGt65x1OFX+)RpA#6>AuBe7Wm{ZkEl?%(<3r6-sUyFd^>F6}-|kW~ z*jgQF6YV4hJa57+*zvg9A3<exL!S;eRY&)dEay3?d~tA;54lCBl6~c;uDq)0`6EPx zLLZv>IHgZw>_1ADmF)9_WFdMpoWu<737-sSLA~?dG)0bzTi#g_9R&x{2Y4dmt3C}u z#p`pTd$<^pL}Q>%RSugS)En+j>SYR>3ir&VD~QS%1lyf8O9~ixoNPh;y&Z?M6J-gc ztcjd1c`6B07#{QzeMh@}+o-VNOh|tQ(gAD^!Z=AAg)9xds*?<_q80>vHs~nFpP;!& zTh_w|DLEymQ|#1Wb2BZ51{Wd4m*NewkJ)|SyikYx-Dlo00InY5=Hk;@GI7pVwaT0W zZhuzuyq-3o?;UbLru4sdtI;{HM?-&qL7$!mmfH3ho>sH+Mg(?tW*23v(`vj$q~3kE z9a?p8*eT(~?{GX*t+lG|re$Fqux43P&`q^0WZA>7Tvuo>C+wWA{6hCU_a3p#`@2cW zU$vLYA&a51$6Gcc<vJOVnfTN89((j~2kX;@pQ!zEM6E!28~Wn2xR0mBuD8x(hL8`T zeRo5cRx4*)Q2fq@-r+M2(zO)Bl3_nL@^2yj(;sI{p?}R7>3SZJ!(#1eb5Q%0yf?fb zm($F)_Cxv8m}oDns&WG#m3YDqR!MO5eVZnkXMtqN7o?t6TN#O6>07{G=1`)*k0F<3 zAVM&N3H5~^|6RO@Qyy(AyJUX}dKgxR>R5pJ=<oYs0tu+oT#>{R7PNd1jl-;ctb5=j zNEb&{bm;~3j>ip5zv0s!P0WHLUJofJ3Lbh=DKb!Y(tg862E7dT7s1yK``jw=a=Vd+ zSC?6tknXrAtpqmV;yTsYEv12o8hJ;Kdpb)xVej$4PU+SDie3qne(TQXpy<#14<g5Q zQ*V^QFF72csk6oXsbh6VJVQ8*l1VO}rQ7*H&I9-bqSUyx>a_7D$muQ1|4~Y$6kN9P z$jTAzJglV*6MgJ4t!TXvWn5N>BUFBzRyw6_N4g*EOH=W<+o4t`OY2@J0s}R6=ZWn{ zOWEKFVqV!`pRRhYWHvExY)Dr9Qtp#%{S{}~B`fi>&E3WeMYKvIGmT}c|KOsHda}=u z{#d*3+?6EsUr`XMV@$VG!|VGT&B4|SG76|&FpS`NjtlWt0|fauj=!xy3*+|KRk5g~ z^cd8<*lO|q_CtRCl>l0fRW@c}VxighE`NBf|MkxpGPetnD^zM%0l@h{L3d>2v4wIg zxC84dsn5sVBTrCDv{mRoF)82uRz&A08u{m|1-^Stw<XStT&lC*xoBv<qNW;%S4;mO zhs_XG4dyqd>%_$`D3<mYmqPDreqTBE*NWV893Kr17myY18;bQF0$GVx&9!M?vA~IV zYL9x-q@IjtHD^kC<=v8v760*CO&NYHa_WJFljLMwZM^@aR7R83imN+%Wt4wQpq#1G z1MO(`O@G3_{;UoTS9~XZ46(owNGTJ|zbCO13@DG4@$-251Q9LwP;859zxuaGJfR-c z%6_Dgu%Nwoaih)yKpj)`I)<hw5}QOL*fXHt1=sTTy&E-oIUmIS42%3vNz2@C*QLzd zbRq|`THxj5Ty@Z6@mo<-Gg$kJo$-#VnIC-3Bk~MQ&#Xx~F}R&2W@{w%BWkWl(7ODJ znJ)uv#=nVD#$L}%=k(0wV5f!;LpXxQg$*@Uce17rdBSUTexO?looP*2#SG5|M`@i0 zPIWq(5dWutPS<v+KMw$wObf5p_^yooE-97FV~<a%Z9-Q{1ZvK|eK{^Vh4v9ri02QW zK$CB=X~E$U`Zb5j%NP7a*oZvz>Ti!l834%lT#?6Kk7z(1Q|v)#7TO7p)W9GoS6Z~2 zZzUpl2N&49{h5NBu4l?>Xx}As)E4~GxTy_HpFC+RzQ|@|o-Z^NdYkGL^MGZ+{gY9j zPrt~Fgd@441;0M7hl)fogYs|!Ak!!{+g|h`OOor&=ODh7+~1{#%00^zLD}InO(~+x zr_|52==k`@HJ(-~4<o%;zdxP-8>Fz`7ahq~a{jZsp+GYeaNwf(OePp`E0YltXRztj zS+qK|&mmZKLX@)lR&C)(z@*42W1YcP^;~^y)errWS0v1qUZcqhLy((Fyu+{C<0uB& zx|#f)0qUkRw?c&a^7w>}xd84SoU+nFw5xd%VQHBDLF+t)f_d{J^V*C;9YVj_cc4yO zWJuVWC{lZn>^v^c$w>=1QvUa_SQf$+_EwyXwU!>`obzeD%2|T!$lzsXBX6N4hX3-T zwLF8*;H7YfOX{fSXH4Royc829NYleG!3r_!p75hfC<Eou<3^fQk3~hoE1k3BuYXbA z4p=>6GvQutAf$OKdujr1g?>j0Y37yDN3?dv&76TU&5<W4Tyb<HW6IC!X~_EEULuFC z>4Xk{nj>STh$f5dWm75_{bTeiypwvX(??*Xk3+-9eST=MV=Y~3`E(V3$nv-PZV$%K z2E#k*msNiVf!z1Uiv7ud9d<8fvK78t{-QF{OxV7JptQTPBwh$i<NJ5N^}f0uP`0}x zh&B$Y+Y+*0ELo*l_dz1b?ohHFbK%*lBiZNgKzmS64{7@k8#8VlX~v1NEEtw4SQ3wf zCAUIEvBuAitz3<XW%urfW(p9lH!clbNv$#K5$#kp6rmVD<{Vy8p~^0-2uw23G}O0# zVcR#_&9?OhLN}y}A8=4T)W8!>wJn?|yxthLyfe=VUsjI$QSeDYB`T_{=Zek!<(wxe zQR3-WY_ODxo(bQF@6M_^hUEjQ$o>ji58^6*Xhl49=iNKedBQ0;x)P3fMR{#{{SEpv z#t7^<YRFNSHhEaFB_D<!QvV0K@?p}mHjxqiLrlwR4}~~-ImN#->XljVH?tswu6afB zCGpPQ9bt)!sLuWo>v$^!*6i`ANQlV|qsi_{!PL4#;dy!Az7@3Hy?cG_(V=DT!RJ4} zT-rPgDe9H2UqUvUD~5SXQm?JJhOtV_fMtjn-|uXV5>-@0-%r)vre7;}O16<!COa|W z@v2V>mw?A&_l|!ziAG8FaAnvC7yJw|f5`in4erPfevZ_u{zK0TMlW>d+7>JBz@VIT zCVfcPq<@Il2|?+ZL_(rtV+{0+8<L~M^4=fG(a|C6@QKIJnGp(*h-jl+!frG(Jv9Z? zGBlwuv!WYgba}I>-4sYhmJFSq5ECsOo06$#NYU$0mPwM~Gp10Y=%z8`)L%Sj_>*A0 zT!=%kHN+#>2I3st#jD(J?HX+B9_#>d54M9?2J09|TLqqtd5ti#HnuT|3GB+S4NgQ* zb&9~T9+veHgnsVh7vY(^<ZZkMB@J9aLJ<H8LNS64<gkr~GvXrNrKF}O*Fj>kn2_$d zkL$@X$+*aaj&U)Sdb$DbuDgugOhgaQ<*{5;YO+uy)5hK1$F23Q=uRHZg$_|-kYHEQ zJKIGpfrQA^R5_0TT0raCyLZG`W}29(wl-WTdN0l*&oYvp#7H<8W1)0Vn(7#!!PC{! zgCta~|2v$LU=eNc#t=xqY&hANu<+N&s0J`rscsAuP|~_@YC>^+&I0{`$nN3LR~HSs ziF+g+fHt@<wQA#rsh$VWH>gB0rVm$hG3<KM!jF__60RTvn(vaz;v<fL{JDn?L6ntG z6Qkl&N!oYr8eDB*Fk%qF=8RuV7NaP5cWz%OhMW>g3f6*P+|wX7yWQYJlDvyNDLv*N zRsviiLi^5bPgr^!D=>wLkwdlglC6?t=rX=3b3qYFIz@4~s3WNw9Z&{}OeUK~g`}nw zlv`*^CM3sgPEBD75$8zB3Ac?>S~nEYairmlged#0-P!kdA;e%xG6o}`p`%5Ck_}8c z=kC8>k28vhiP2+XWOS0Hy1R0sh#F+ldD5AKByS_J6i_prMsgF+bV?#^cg-EM0Z4Y2 zlQXMh6g6|~|1JNT9M2TMCZuJ>Xd&W^yOiQm>|&_nM+{HDiPB?4rOP10QZjT>qzNg$ zjKij<NTjfTZM%}u-X$cOc2sh77~_2qyDc4XWX8v&FYuSQ-YuN?yMw3yj4#6BQcM#V ztZ`YJ4!Pa87?G5Ie8|WiZNF27S~M#6)t(4tTo6A?%FWl6=H)00%2u9HQZS(hXw5@{ z6}GeBT)x+mWYt?keGtC@0^|}SG<#_36RS8aLtnthc+RCW3ZY|&jBCvTTBqM^#~--K z67py2a9FLwDG~EHG>I?yKE_@(HbId;ot(xw^!_@x#@pJB#7}x`a4FO*CSBVjqT{u5 z@{lOT!t{_v8aqB^E*=LQs8njW)ECN$aU&i!wE`>^ZWqnR<FgDX`tT<~AzAqV#2j>S z(W%@?z3s%%H!w6ZHnFz(Mza&#PEI9QdwGcQ6infu{>UPP)-GQS&D`up<`zQpw_r7? zSqGxyqhz~kYvCUwU8A*N5JwNmws4At4QiJlAdSehV8qTal0s#<DfX;L3<;#h#73MX zZ6u2XE%tK`C|IuF2Avg>{>w~}hO5--ziy4XZEb58ImOKGTyM2OkQ}K)Uc(53a?kB# zD!__PgFtln*N4GtK0Y4q)~q+t2V1AR#EV32PWTc#)V8<mX+9(jNzs8H^XvoVPZQZX zZXkKTc5ksnvbg>aQ@u6!s8$>_Xm4fIB{eFL-rs6f1~ARYF7UXap-!W1TL)_oxTc$z zT<Ex=*JmcjjnBe8s`mk=&4-K<@cu5wZk@LCNyWJ#gk{TE1AVSB_oC(9!mKR}wmWAd zFm7TPFAGYRLNWG6sH1qatwZ<iN~Z<SbZP=~+@fNGZ>~$2dLjbv8j*FM*YYQsFKU`$ zp(EH$_tN#T2yCB|?1`~E)*d|(W0sssWEkjqQ8I8NakENpS%0AxHYU0<m07bzW9bYL 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 K|8M^%8TcRg_~}Lf literal 56320 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∋T z8_U8cY!tx?Wcyi4N&YT=Tky8KscADwYksiZuAqUL9qLPJbO7xTem~T+DuV1Uv|Dw# zQq(Ak7ULoDHmz8_PkjEF>M6F1zWaGf(E%%A5)<x-i-vvI5Y##yB3lif?*x}{e@YQ8 z&#>SnFNITQ4HY6vkhu{WJM-2-)^ANDzD?lDy^Z?)Ysc?Bs%WPz3dct<OuLQ%>t0F^ zC{2qUE%ZToBQE>vjJ(IK$ALmfA!#K-Lag%Kuq=IY5OY<EmXVSjpun9&Mn3Q}R1>kA zevkD*#MnLQ1GRY@v5o;=Jkos;+0_8>7hS=OW2G7lsSezEDmd_+XkgXrd13D1*zTnS zA}>5=-c<4?0yO~zy9rn3hMx9&mN@cx-caY^H5L1Ljcc8o_i8GftfJ;`?UfIT|4yIn zvsclTA<ftA9AY2~Lo*8uyAtyj9F7ixLhQ1F-TFh_NI!ouYu#}E)xzHI<BPhjc3*if zBI~ZzBwSgxTfE824X<YXmWg)QtOb=QRDoR5K-ZX7atY0uLVu{BTQ0|D`)Y*cofWKG zc$y17Ir2^~ogtDkVh4f4+0+4f5A)v1^U!%MeV(fH&v_h3J|OSh_Q3W&Yrlc10@4Q{ z;NtwA=JX<fC_Cb**7c6;8}T53r1~mvu-GVU1Z<t-m!lK^>iua!{-H{i%op@qj&lr- z?sY%tQ-ysAIwo}Rv$;%aqGaB@x7j977u}l41gFAy=yt7T{3o^1KW4XG?0A#^G2{=K zYaImlV$tfe3dKTlZY;9_&5yRO*4!*hY~$oX896W+httu9n@r@$9g~rht}aW#HHXQZ zL$P!11S;~JTklHVPYJ*=Z)8Y4KW4;K2OVo|FFaH;Xu~!n-hKS><&PW2YAP1NZi0QD zHI2XXurfu=jK#E*yyrNi3@*o&Z@9I)dl8gckaxcMle=m^0#m=I)nvs-fLHCG>Nq=7 z#|V)(i-$FC&&1)xbGmW{h>!@4f}Q^~(7WX~{B96)oo$M2RLu~yptON|?YIS+Z}L9D zc(WdmWnF*%0zbh_E3e|tQjlC4$_y#ecf?HR<#g&@N3(-M4S>5Rn9DZ`ZUcG?hySPI z?<H&DKEbez6ZG`P2yXlW9|C=rKFW_q)fSf+-;fD}lM`-}KX#)zSEa#%PcK1VSY#>C zj9ysc?xSf&_AhvegjUj`+;B9XM4=x}pvvSZc<zZP4;<=K70??D*75TkO(?xj1dLIW zPo{o-h?bV?=Y`Yt#TW*AM=9Xx&n3!EcGv_cFt?OwOC@nnw9R{lBnLLfgj*|2r>yf* z_2mU0#!6}MZ|P6lKghKx2>EA}nbu&mWo-{BGZg_?qNJIgyrwBhYOc_yA{Sgso;2@- zq#dAGnIbTn9$geAbu{KBcOJBkUJ15g_3^>K%GbMUKvCt4S(TeYbRO_7lEvzH-WdPw zFgc8MwC5O(bsT@z!USgvg2(`LXV=*%wm%{q@e;XbkHGrSp-(BhZfslEn{M80&B7@) z6JM1WA}3#L&63bG;`Zv@|4aJMB+R6CoLvm^yVb3}U?6?E8Q0QuxKr9vL3L5p2AGMM zRymKebhErY%U1lmtZ52-X&>;nEXhdqHS4?GSy{X6^O{hIQ@4rf7&Q!|F4&~{GSohz z-cJH21x{V`={98Pdp7GtF9;4w-WxbB$m_^;z-<Ap6uCt^`jt_oOZ-$4jQHiD2NX6| zmX|iD7PyOHHO;eGNKA7vY(UKpEoJK&xj>Ohy<3+452%i^KbAkSmJEF=<L2(MD@q1x z7Xg{-Rn7S(AA#@L>0@-LobdCZElJBK3_0mlbagsnfXT!Ec9{AIje9sf|3f{Xm<A}$ zc6*mE9R>s|JW$<?eM~<cGRrv#mM{h!hxNI|0t*xWTAu|Cuz>t;Tc&h;elboH5>r&x zD6^XC*k|*SZ)rO{=Pl+G&kh+iM<9RHhH4)t^3|kpY;?mV5cO*NLC^U78p)VlcRytI zH=$`l9d6Ie$Qn>{0{nMWYO<i{3fi4Dc++rSNzxpgKuvNYaKNowZI{D+DP)YV+E2&x zrR9u$$c!8TNRdO`nwQYIq>w%-X0Uy(*&AWL=|m0e>0vGpj8pLfM*S-Mw+c&uw;&K7 zhPOlk19o1HH<6@lpqllHWl>Jyq4<D*Z5npDy)fgQWUfvx#+)(va0|Q9D??uu1o&0K zQ}<WDZq@c4I@Jmpad-xA%feb24)6saZFzdvdqb7j08`Zp8(Z~^vUe8>smg_KDx`v& zgK|>vxlnfVoJ{)_!>+Q=m%qvDotxJml>RNkILVy_fpNJrGT)IPJ`C3|;03Y~Ng?;5 zwt&2cQwxQ{R_El8%&s?H+KiKV0p%n^m!S|+Ix9z#gU{DQ3u-s=3<N@(>8nFR35kGm zF;=1`{?;1a9N2`F>4P}gR2(>_ZfBUhVx*blu}W(4PD&GGV0~$AILa~yByp)rJHF~p zsfTRs>h4g=;IiTrb6Y_o`KyN_p!}n;Xb|gKSq!{)cVJC96-~&V)1AoG<{PW+Z7SGK z<U}EgdlJRDXACbtp#LYtJMxQXODcTp|1)OPvCx5G6y57Vy(=J+xFCld7Ifn|3A>!M zlr9xvi>*B;sdF4Ru<cfxxqrmcM50<@m60H<I)fqO933<;oK-45-i=PMIycQ0mCs7_ zI#VTF!#!2WXtW}ODr+1x@s4q47dxv|i@5M3?O-3Vkq1%FGp;F8Cl)d=4EP7~wJQZK z6RFZ>8i>+@`_FbpM+lwt6$O$YOQtk?@-W^eLc`_{eZbprfe2L7T>`>!fN^hWo_|(F zhMPIg=)Su)#cuE#O&1UeN;^Qw(>+yT!L>JQjxE3d2I6$rj=xRt3Yghv9kObhVUtYU z#1JJ4O+bYE-kX_AMfQ;ka|g+s3PT3znm&(&^TJg9cS3+sH7DELVSsSy>h?4mY-)*x zNt>_!0@B|f(Y8l?+x1jAR``(@@OrmEu4%+4en(FhbH+;VH(*3$trHEY-;bK>`*jE^ zwvac3zYS$L)t90b`l5l)+8cOMT66NyEanO0?W~X5XhDQknvkDvrxS+vPXkw7q!8<W z&r9Ax=8yNib~=8!joVsfrz|a0_?xF}dngIiT2uSp{SmOmXf8>NntBQ}F7lLg#2FY; z^lf8^yJg6sR+bMr0gqVDf<|CGE!m`xsuzM(h${Z+HziaU0V=3RUTUG4&`<6BtvK1? zSPlHs`wqtqJYeJTUN_OO`B3R%KiG4-)zV38z0jX{ggiLN23^Xv769Lo9hia=7w2g* zL>8$joeFN32HF&Xw?6AEgA#rKcDwllZ@g+DsP+Sd(up;oeQuT$ebdP6vzr`-qIs|J zxw6-t9w=_UO~q2KAwtB9Eh6k9=NXX)An+DA3diSW-d%WuoARYL+Mi2(329&sPHFk! zZj=cj=Js1Tq`2~8ch=uu_~++W;oux;2bN;w*KO(d5sZBobG;*h6ZpuFl1E=<D{Pt! zx21s9y{3yY7)J8W^Rf90?T_^3Pwl@0a_rLIrfpjdfYN2W;4GJ?=Y09f0W>*ZWb9{u z#gE;naElC4%M+N*f+o-yr(OiW*Wx{UyPO`N@;d#CB=5-zZ)YpQVMWLR%Tqk0e!TIA zw`+PD@2Z0FX7Z;1001|FB2Ej;_OfTG)JaHALtF8#p7F3CM@rpDQ*gE}GxsGTk&zC> zhyz6gVql4{lN%A%&j;`SUXEwreuz{V!V+&)m3@6?W=?krZVsr2!%=ynwl^6TgNljP zEOz{ODa`M*@-unU=_{C#g6vg~a|{zr8a~_=kPa%VL5m_t(9lvDcV?CCLdlRO4v!g^ z<x0OU&;?Hj|K{ISYbzfwjs)EBZZE@MU}|Pij|`0;@M=4gqr*BlZ~Q8IMrI4gC#b(s z;BG@M!!-kKk|gF`*g_dOHSv@dOmGr#4L~=whZ5~9uZWQ5nCL(A(`U@joJ4_EWTURA zYa(N8=T5Gw%$LqtF^o-Ue^%%3eJtIW&%eg;0Y)_fJJWz=3JfJ$+mx_qPR6<TB?@qT zUpW5@pCF0|a%s?<RA?jjLw#+#O-Hh?8Mc+?++u34In!~=ms<%+!eH$>-f2}a&QM7b zUpGs{#1(I75P#h`3Sm_+?>;p)fw8PC<8{05JA9QqZ2H^ax>s=&CD+6*p5s*eVu*_^ z78*C42Po@-^I4LBE4zdD4c+wNWA|2_6@Z@lAmEqwX<xXc$}~+y_@%=$5MkU$yExpX z!&?r++)1~3{$BBoU0C6|soH<ViC%fAc`pI~wtWAAzV+u4&*Z!KGMTtlFSdi;UBN-V zEt?Tb7B>4MrQM-9EUC)7w5hybK)_e8blbzh%LCTKPBRk$B0hdzZ&FQ>h5f<=qj->w z<~uANA7GC#>g^Gd#V2Xhk4l9XIU$WzOsyW(RtCGul`x{+fGG%D&OWqX+#xyp9_J%G z8I{X>Ah{+wPEOBM;d+*Vo~e#$&rGg}L`5NjU3t6+(|=8Lc45L_h>08j1|6bO@`+cA zw~(D(g4Yzch;N^zqm|kfGrkd^OC}bB6(v`Lal#~h=z#w1XN2rEd7OU6Vd2NTRZ~P~ zF)6y4BG?A$DRnswg+H&qxL~CY+Hk8s5R|FeE}3I`5^0tYQ06aWTa_{Meg=jned6ri z>4un<&Mk+XoBuV~R%@$lUW4#|#CR{;DaC992Z446M*3|P$7RzwY$-*)PHWv_TjxF_ zK3N_3<c=v{-#ukPKfjE7dkFy80ld818c;n{4c|nUN|QEA;TB`O@$Qc<Z|a1M$=80W z^B^aibBzb>rnX1BZ~A*n*03*o%%#t)D#j4!D?lKsWg1j8D8^QrXgK#5Iw_>N*2?7x zg7OJfVTT<h68-TesJ{blZSxDl`32M6mkzcdrd(}nU7=%a;`JZ~LR3f7{l-$@12>`n z+|a$UlC~A5rr1_Wq720fcqn-PDg3d;F?9v>ZIcwrTP@7$PT<x%EgWA*NZaHWswy|b z9XFGYC;+iR<9n0*hv8iH9&zZwDoVh8ML%oXKX3DG*J_~#eO5otc>UwWn>I++v(~63 zjp9Z<aY!?bz~)iKU2vwXFK~gkCDNARwru+6?Uq-Ark7KxjmG>NK*q$syp;pJ5DTlC zsvci$)%K4byDwKEy|xzDWf@sQyN}Bl$?Is2H9_d~(p4cd7Ox|1uZ3r0vp=4&;HBU9 zys;t{Nj)bL)5e?qF+dm)oc!~|w?o2^)OF{upIt}tch%`M>z5Ssv112*OFrPyUCkjh z6un6))sh#<=5If(460LIxcySWH3d;3F2rbOH~@L}|DK8}M%l>>!~iu0Z##tuS|t93 z!bIx%uAGF853*TeqYno|Rr_zHn{qVJt(wQ+*$|qDxA|BSqDTNo1U_N71oE<3UEFy$ zI%<@uTsf<1PFeu{^%wh3vOADonXEeNkdSV{$v9M;Rx$#tV`Is^U(q4ae0BEW7Xx5x zglcc4wwESXJWtqwWrffTw1&97EIn@MQ(7Fe?ej*A!5nAaAQ|<*;>1LN);d5o{ZmD{ z$@lqeiB>?+v9ev)=0fhgrU@O92nlf^`*2+pBsejvq6LM}*5TXx>OHWvtc~UEO4fLA z)W0-k_}|XNNTzgQydB~PiW}o0V>s<;&03&~{6#}vtJU4UJX6I>7x*x*iwNgnP#ht7 zNStzH#s}Ph8U~pYFb9@o${4r3H~Ja#>yty`NV9ZQ`^c0IU3B!*>@akQ+zvHMU$SZ6 z@nJ&+wa2$YQ=z#FV;PP4lfp=fAqR;~9QkRS2G*%Z3O@1&!A7H|ZTKUJ4Kl+y*d*}i zaQ!;f`#vYC#q1aOWe<TBe{WDC6WkDP0u|bqy8~`a`_k^#tVLI$>{mw)+n@9RChnaQ z>iH>jYKr^HD;n5@gRp|WfbwBykWN`K8LpDesB=dy{{$S}D*s$58zG{;`IYDXyrRzA zyj01dmJ?o|J9~aLF2kJ$Xl_Pi2-((4MF^&^w1w)%6^`qBNbOf$brYu6ffB@Oc%q)6 z2cmaRZ~`U+nA<_L2ds}4N8BV^b%qE}?j-d1EvDAZD~nE&Q_+RCh6Knvte>A0HBMAh z+Yw+4ty&oa;Sod@h-4!I(PbnR=!sh;07upb!kAd4;*(!xMZWqimCfoX^}!oh2p|bE zt}9jpI>CnleKh{Pk_~N>HTlK19~`7SsKHkCsJC6(Af>;L-;QISP!^X^@VF+%6Jt$` z86ZnOCSL6`@x9lyYdOt#0pZ~k<MHIpJS>cHQWgauorVW+oJ$G;orXONyyt4a#xy<x zq=gNE_FrNfsPq#1CM80;WQq<aQ8w5;q{_-Ox+00wsW(5MGJ-8pgW@<jhY$&XYTgCS zSLU1#O$cg{06S#=(Kq@P<9OKFRD4%cs|Uon>xVjTT?&|Wy70XqI0b_7+&6tVt8;d} z3-T*5XWC=6?J7jVct71Xwj@UcZXBUAQml4W)?OKLne2pv!XdjNamk;X|4prT@A%>J z$g1z|asPFi@AkEC%Db$0wpBSh@^z94yi@op`%#nLDVib)BKSn<nZdJ~Pdh3`FWcO} zfspCw?oy3Q1H3Tt+LjYfTwH0wFO&)tr~rX%VaSh~+7Z2%{U<=-5a>xs(W5PHPITqe z=V-Xx<*#g9X4At}<Q_qP;Q&OCeR)lca+K8{AmC_qMr-uKxzguV(=3f*!E{>}AE&d! z_H6K}q5gdjlC15RbqTZ{^0cMKa`U&TwT;C%qUIGvPf-^ob%sael23zB*05rRSf34k zuh7!-b8NUI(D>|XpS}%GkM})@m<YO*f)5B@)B@D271C{gFUiY2ygWCM&!-uvR&}<~ zjh%{~Dqb<F^`RDN25J~zEJw$I=xZ7H-ZhWW!{~j|zI%va9&?LKZ{iK8ra`f>^jlP| zmmJ4<2a8!=ZpIxe5E#KKr()Yd##SmREs(PeZTAM#m*3oVScfzDq3RkM?>ws{`0x*e z|7@TBx4yfp3W;E(7bLwg2!8PDC)3650hM#&1T?&4-tC{MvA5kKBDI_mqdI^w?t3nL zg`{bMQ8<Wg=y@P@pZuMai~$UO)Jgq>n<}<T3%x9m2Q&=$Z6IoJ7jORW;n$wWISH`3 z!+5TB9>UAtv_s*v;pw&k*K{0B5HQL?Cr&!#?rP6=G_8&0u2s4|ZPs&*{c{NQ?Tqb7 z@wfBmZ<G`}+RF71X8I^}7*Sl^4AH)xx1|j_rjfI*!x4Y^`LBRsA#OE`$4b~4$La&z zu*{uCIpbIj+V`g_>5q<8{I(~i;AAnP-cm*|J00^kcctuC^`BcqJ`HUA;Ur$Xn{&cZ zgDvimM5&n8;ETrbrltdELKPqA#((JFr#&4&zZjb~*qeTkjx*7JpfttE_Nn)+CqdI$ zSZE)R#JWd{pK&_TzZ6~m;Z#2REB6ZpBKl>9neOo38Z&<=klpVMw~Os|_+=<0E}nvL zlmb&a_5mFa1FXHK83*oXBj^zGbh6!YLD_#24~_taNW9PzT)gA?gF8-%O*yT_P?f=M z$b9>T0!qMrqXm#)bL(w$JFii!lba7KsQvx+g@p%@W7rjd>9eWXA|>g7h)Azh{_?*v zfH;|Fx8Fu#f)ZG0{OInNzcvaQ%!!!%v)rE^wzdDDH*IWpeCD=*hDjAVk-u*E?$)Tw z*$D*nz4#}#;5(R`x#WoZlR|d-(K#6d-rEwJNZ|IsP9v66@0tRCzkD+Et?~OiDV@!; zk_u%D=dI>jB!5_=OzgE;Z(V*X`g%j+tn7H5oz`(&9JFms@5mFyT<>N(+?>uBrDFg` zKBgYio#40jy?PEtx8+VcnsuOV>_uf{+p9T*w#5~DXwK6zVCc?2Ts;|oldM3sk$>%W zkw2sEs^ZPLe?wy31CndrULIXBwLcVIUvBdnneKO#$si{X4wP475@b^m7Ybx(=VAxq zgObL)JIQ;u34e#@<^JgTal2VprzBKZ*FqnZ1qgk2{KAcZ*8uJ0#nc}uh>d;_ZGIt> z5Hz1E_c1UIkm#txEBp=F;i|v9@$>KQZVx2166^VAal@YCkf845D0kRC>;WU5W%U`K zl-aElmm<VDWbLDKz9d&}O-I<c1raWDFF1C|XMn5x2GIJ?Y7uFj&)C>*-9(aJlu>=Q zPSQcOIT8jV8_V{`TDMWPxyvo`wH;X-9jY&v7tN~ZuC?B9Z@NP*aHpScSvN+EeEdgp zzq$>)Dd1C)n*3uW@G|D{pTYH=rRB$4pue@C<+{zbFr7v31@1!vlfK^T)bTr1@<WSQ zVfUdz#vFzAYppdG`mBv7-XX2I-smm0rB9}zniiJ)Izd6$Z}+f}+yk~u=g2!21E4d= zw{q(5etXzfbpKZXZJQqN(afN1q(eG>b)(N>;$1Af$sRY~yO((f32HxlhLh}W|J+UF z6UDpAefbHi%;T*NI1&eX2IVoDI@8=^HH5`iXQ;AY@J<Aqi2ZOke0BcB;3Vwop`oXZ zwjv*5)BL=m4(i50RP`F%gql&wCo!q&wp+d}-TiN2lV<=4tnZ4fKMyxRwW=EFnnzE- z+f)lvM;G|Ag@jF+9DA#Y`WMRTz-F(D9szj4&;pXzNtl)KhpgpY8RgF0EVoxPyz3(A zK|chG@jq0#+!@d?N~@F0lMkj9bHRn{Iw~%(?i}IM09;1I)0q<(li=2Vo4L^gsDp7R zHy@lKGc4?Mx`Vx+YGL`|nFj|{46EPA+yY)uIeE82X8v+(Ppq(pf)mHcW-2f@-V>DI zX9d~e-#GmH+!OI9xs({3HA_}QdPg%^vw0eUS{QZPYk3pTigpim&wKFfONHjT#oyX? z+CFM@jgnwZ&j}UaLqNfw&inA_c%k5Dvz5CpYTD3S^nLxYqCco0?aq&1A~f-yJckms z{|>;uIKfHN`#{uJ<Cp=tY4%%}mhc&6{7!lr>j;M86*~%9JAx=7=~HE)mtGB8n>8x^ zJM5C1oeUcXVr^Ep_8OOZ@(J~lBFMhh%M~7LIq6fyWunc{(ywTyq%FEs`>Y0#>j6xF z^0G)1_Ijg)&+5iIS$(J3#{xHRXdD2l_Qxh%Sas2>;t2)s?kb;Qo?d+GBI1wZNF4>A zcUc8z{58`BGt+Hc+<>{A^?GKq3=ih`-#0FMAvoH@Tld8dLlL^lKC<|@@F7-p*H^Yr zi_L3I8!{e9^E?3nm;LUsos`@3s*s-ME7C#7&UJ?%-a&%JAkNnI7kAw*=q~~YtY13s zcO`mHHSQcL;pfeIu#=NIp=;X31lwvofB5;*I{46OnLw|Fus%>ipG|VKOAq`r&)r`; zbB@u7@S3AeDYaG_6u~~G16yx#>=;3=eeljJcBdQmO%}r25wfuUzw`zV&uUDrR@gA# zVoxM6I}aonTYG=g)WUzu?ftY<Xq%00VDOALP{ri|Bc<a2zW?bYP6HWZ)#g5|UEx>r z5Vx`d38-H|e#8|$`7JPu+=GhYl!y^r{VezcsT#em97q5F(QXLgc6+7IA<Hb2Hl8s8 z(a0))DDtoYcG}u4Q-IKU+6`aSIeAd+Frqa?t>@e(aQkq8>d`QH$CAnMiBFe!z}$+y zJ+esTG(a>LsLBbI?@ILa-~>&3-sl~#BqgB~dXJ4V0y2HrE*7tXcvsc@P=3|AW8jGR zNL($2al8-VHK97QgIL0haf%1{g4s4ih6=i`4=*K3g<0%i;OELDMZr!Oc@Whv=_*=y z@A*a*P1vwo-Oyu15(c53-|17DFOJdiKI0YfgQ6u7KSr_ENeu%5JFe_<wc6a(Z0H}V znA>IsqFI}CiMH2#<T{-|+?`?RT%BCu!`T6tDqOJ=cQqb%#rDYccj;<e09+WTu8TM9 z)p^;-+29G*s|(d>7dna*;o#^g$V<kS30(~9dro3fsr0bw?s+s0)eQI~!|${CHHYA} z*1qd&=!YHzUj0((a#q}~eo+%?JrZvJv{mN<qsSLxxTyNW2X<B8Gj!~XV<#3NZL|VU z68&E1Aq)rdZu*pupOT3Dh7AGRJpVKp>aD+vBt};MIF#ofWrAh^5p{3X9UwK_u+GYy zXzy;$fmdBRAX)dOz7cq_tf2Q(-5t?`o-l6DPGFKBAS+{i*<BQnE+q8#L8WfLcD&~` z<VNW{#HvrxAEFdX{uyuy|6OIr%YG(%+P78u5vDofuSE8?G=}|FEi61zh<NSR9wAkW zd9$&BRywO~1VW+tJ$7HjG@e$%AOCvG$1t|4&r^k`sOsacUyIclmFu3a$VFR?^y2-P zIAfhtdq=g=r*qwbnfXKOAOn<c|ErwsZI;6llz00+jCU>=%wxfxdK<N}f-!geS<a+* zXDt4ry_in~3UF5EeO=9^Xx&ch9BXT&VusHe_a+8PkCHU_PCm_p=`8S&P!03Sg(lje zuNnbGjmVxdg*%+=lp4fsPzno_J&I#;N918kqDu(TV2Gf*%xty9)c-EY9H@tae0w(M zHoH}|zX)F}7fw<*IWLQNuKa`k-KAQCINiqfQ&7iU8Ts$XbesGa8baw8eUY!ANU)W! zGV#{=G>9o)$o1NbQ_Eyhk0y=XBk`ee3lNfD9)5ZhWFr5TI)DXzvh&CBMf5etv?w=^ zpgm0Eh-bHc05^4)bSFk>33#><A>#Qf11r`?l}xu3*k2(s?<J4_i;lhrbr5YMZeUWX z;COUb=HF*QP?Eu81l#0D=9Mm?>8{b5Hd}!}8@i~<$RlChJ$}H$*t=5+FNtUx^9y@K zBd&{TZ@F44Oj4Z@qW`IE`YY&mPBiqeUfv{pMfsgaH@Bj#^1YeDp;hfFHC1g_;xQ5g z5$gkztE}-tw4KewexP-C<0I9xTjm0CDD%EM#^JKvVqI!@blw{wM!AL5ic{A|%T0$> zKFG%UHMR(qC(LDZ+SmS=nWFK7ral!7JWp+koP`gm4zTzK=p$E}aqZody$pc<bD~o& z*u$sM=v&2H6OQ6&Jf5;K8uH-kKZ-*S<%yHpnrgolCluE_(p2afu!d_16R@Izogb=x zdEvahxVNu6fbuiB?uQH-2fch1Yo<WROYjSK;$io(R#bNlH{g8nA}=gJi6>}f)I~=a zzojn?PL8{)IooAqK@yg`d=QRZx=SF(S6>0MM&kkRJ~;-RD_yxr?_+9SGYK{xd@y`` z>6-=gA2|`*3n2o0n}$0_^5nps28EQs3-hh9fz8pS`M^OV*tqvO@cNH{ZqbR|5_^E0 z(Q#5eu_K82Z{F?5K=(g`QO>cx?YF<c0<1OO?t^;<LUFNXikuK2-M|wdN$+cj0gFlf zy9C7{ZH^(JzM&~6g=L@rA4PZK&xHTS0erWaVPj+NxpH6SzS=N1nL9^G(vmA}C}Irl zXx;ZYR9_TPZaL;GT~m@s79C@R4kYZ?@1OWQKA-pJ{d&Fv*E6Yals}o+ah<^<Vn}wF z@i6)U@r9~~8bAx;J}*)n=WZ%*^$r^n**Wk$mVyrKEH7LbwO~tGpECN+TIAFwkfAo0 z+uypa{1tl$c68RLWa@21@*hdvQio?^7;9$i)G(=<-4Sc%V@Y#%kJs{O`oZZT=bs+L zNR0kN0sD=5*s%w_>iRkwj3!yD6uo+zs*(hc_Z8I``6<{xLER7NmrOT?{0QU_CuGM+ z^Qu8hl(ucbF4D8%+tQ^JX7KyRL%4W&ros$gD`+cu5szZz*;kpQ8&})vgx3kHUdS*a zNE(z-p}D(A-?+!kd=k3C=+#zjx5(MknFt2@QwDIeFvn^<0{#6ptScuW;swmckB&c8 z8-5>_{3KB}5>MpdAIdnj=shJS;q60!Uk#h^RmZQJ?TOIzV~ygxfyn$R8;%}1@m+#- zmr{F{1x>C6AneAd*kiLt{Qf(&+Id6Zwv10F41tCf)POsSF0SpKx?H=Jy9?xOK{ax| zWO{@4;wu6NlJR<ChFXfg-KI`clxxujvp&*YIdJbf+qRBsnN;abdM-j@q24EW6l^r5 zhu)Zf9R^O`!^1e(gY)H0=_J9fu|vRkfN9Ev*~=;Y<Zhz1j71o0sj5^L1%36ZT-Tu= z|8i-mO6q7=O1Or*;hfUg8Y=&tbPnFcp*vHB6$_sb<SFI!(2oM|1|etoa}o1o#_pNc z?GB^u`g6RX)Q_FLuUbInCu*5Dtq+4r%+SF6+P#@&L$I2I|M9sa;hZ(y0guZ554+LU zg_jIlmCikSL@={S(#72m;?L1g9f2wZWs9GY81Z3!HaO=#PE)k`r&L`P>~-44IG!H| zp90tH+`5iX^^pO)uGboQ?nTn+qfdK~e0*5@n~RuPk~L;|wfDqqY=oG?5?&f2y4Mn3 zZsJJ>^Fv!sY|>_x)0~y{5v2Ra<w3sZ*+1(A9?6$l#p-5yT81PHMeR?h(m45X`N~h2 znoub6l^Ed)ZerVog{JPwO96eu-tdwaiF{Z?PzqWz`&kKlq$=pBh>>&8nsrQiB1k?M z(s<<Ne{!-&83IDJ>IG@B=_%O{JfKEyE|wd*t$JdEoeIzsfqbo-w{V^bksmEbUJZ4b z0<5Ynlr61M*Rd<(RP0qI2yom+a)^^ywFD*4tagCa1!pB+av*G=vu^0RGH>D;NG#`U zNktsbGmG?H(h*On#VQ#l6G5l)*Q8ojYJgRGKM(37xENG6Ydb#@X)vmfqOVat)ICm4 z@zIh>CW;Y9v!0uwpP;wtkM&=RuHZ)lFnehlhk?qMDxgx*-ZK{X(bVJG+J|ZCTB9WD zd5@`LUfZTM<y6W)8&xfx7U(#&3Y%4^vk3H(XVamU*uqX-PdpPQe}542qmrql79}k+ z&Gaj7G+KO;;c7`p`R>=C6d5kbT?&)Wc2fS8hTQD;+_aqe0`-`5mX!deB58*LwBJfk zV5BZ&046dKyd7O>!3Uq8thRbu)?lu!J}NcW@0TOJ$OIpq-n`ZRYjm4mKln)QZ^jo8 zHHYysGQBv;PMR4KY@xCsQ-2}nc|!Nv0h;HYS?E}y)ZeFeQY)jwoqyX4lRFS_zbh-7 zjBZP2%!tj>@1KT{2(x&6_e3{Ctj6>;w=ox^e@Bo9WBs9rlDfNkKG9}MUbBssb-Z*< zH}`7+ELm(K*5Yl}ijz0;FzhN51E=N`UPZzN(&F3Ht}vnK*Hc1}|1h*gbU8LA=>dPZ z!$B}LG*&yMG%N?eIZX9=(T|Qr&(scshf*P^A%B&}4J2VB0=LZ#$N*aFa82G-cs+RX z5jFJ<<OJc?D(#dRtS7UdPb<J-#JMLh&9W<34U?Xor@R1@nP+{Lv`eF96?t9F;i&we zyLRe!gVMX<E%h;RwagdA6{zVqFzmRQ4=4SKUrAA_gHRG)z8mwtCK7XaGD}P5z^etQ z>Cx`bJzKHTo(k6<u@+TJ<Y?YQm0Y61{TloVVLgI_<}I)SWKuPk_Thog=&acTSCYM{ zx57?ajh;OxgVI^?(NXW6xfaL2sqtfd`k%qNbzyo1zv^BXR{MhWtqtlwM0)k@=RL3F z9aq!KV5)VN>AbF3<|^xx;t43YpN_#&&V5eSo4N*1WL`UcNwz;}8e)1H3w4NoOepZ} z?vg?dPwH0{OpA;NIq=r#FOk^`fe6YK%y~y*mMkX_Zl;jFcNp}*^DxLvF|HI`+(&++ zrzDI5HV!uTmAS5(GTmfN(uY*bvO{3@qVj-8)|5~*O0!soZ0fQj_Sjz~t&_%MtqVSn zo;0U5TI9*hoX{XS)Um_#ig<o$Y0-Mk8@Qg$!RzV32T$~Yqf)x+1rL~QYA)xSf)~vp z@+-)$Ot=BN`xsfz|6t|6p`rr9>dyU2CXBApx*39g(B{wd*oG4&js$u9<&?mi*AA`Y zJQ&Qss&EDYDR&2<9)wkqDw}NVhFe4Xaa@QdoW2v#M0D{(TrBgLx$~#rU5@ij#;*@g z%~Zlc;yJuzs2&kNu62SkjsM{WqaV`)j1;+D8cW=BH@iaR=~kJh)N&Xh2c>eMdk_0v zlOZLOCEYDOIMFoWmd^~rvE32OdG=Rkc#OO38M+(=`5U6QkUHAv2@0<`vQwH(v|EIG zO1(6`A>_nb#!%m(c8@Rj&m%D{frrK%MN8w=be{v9FlCZ*P)nET^xiNbQk3s=^$x{{ zz+A=1C>Ihm+BWs3kFum<M@ovSwz3w>D65F>wwku%#htS^i&Yt4;qKVs-2lg7H^ir9 zcVwykCwd0JYe!V&-Y|zmhYgF-T_TV@+tkrhNk(7>D^15}n>dw?2Tvp`v@e7H#c}pb zjoI=?XYQCm_iR4Vs3V*x;}kMHod4DmJxnmEhPVI7)GcCa&*jEy{>7y&HfuoJRHOOd zr0v&3N;Vtaz|x+k=Xx14NQXa!m~7dGKdNFRIImK>ImNi|on<dD7Jv@>^g;GxBnh5) zAdv;Lx*C&g+T!`3Me+j6aw|3JH{!C5ZdYRogD|yKI~*}fu&$&)w_HC-0onfB#T+m0 zIx$r_dSWy$fNq#l%L<8YR_l8Nv+Va5wYqP=$CQ6AvcDyHG?P8!F3eP%DTO3Nsvj1@ zfZr`xuc;j?Amr`8QX=<B6(G=PRvkb=+v(`=^_yd^4}Spj-m%XDoRi!YGj9})1pAit zq_wGgg)DzG9*#oo^5%e&8x_&Db8bYnfQdYyP%MT;E}iTQ9xxQ%Fa>6@zNec0ehm%A zLAbHrF?H}aX&mQ$G!JgZvl~}++SVwgBP0wx+$>PWk8n+G?Blr8sG6QAPlwJVDrrY+ zl(OQtE{RprCq{HqsjAk9UDo~zS1C|BGWa6GA`YmP?)Xt3JrS+du06cXt-}pB^q6D2 zjN2iCSN!X>{{nw^O7L+MDUXFB%le6WnMUyqK*Ul9_AjksH_$lr@JtTqL$Iaxp8iwD zQ_{&dZ@zU`wTuH}+?ypx7HQHj`%a|59n^{UJB6UN$nWk`b!!j0M@QBiE|3@s!a_%t zGG>0&Nf0Nfyeo2Ve8~NB^s7CIVj?cmb^Ojmq%u3ildLA=?+%T7+R&-vNR*RrVjbj9 z+_={rjRVd?F&)oMl+O>&{``wHI{K8Le*!{N`=yj#DO6hVguh7cW4mHR7w3J}@ECJo za<BhZ+7KmcC?(bbtBc%&vjKKX-1sVek`DLfo7F9M3I}AP3vkXDt^hcg7qL{&+?5Ny zzfAKleX<L)u%cWD=1)Pn4_SnA#rZ_7)xkiBGOLj1?}_}7D*m|l245nPg@QwNVF9H> z@O1sZidAZOa}O*nrUn4I6P1!f1s~R)RbI*G6xyh=7T8iHFwd%~Ro@YQHw!aqof8;1 zk`kn23xp<wRO&$Ly96M?u0<H?_`lK$iG-kDuqRX5Q1G~@3r<j1sr)p#o1mR;*jX#q za>(++PWq-RJEVsP$Z@@P!ajlHg6G@^B#jVj)%Uj%%DTtA%GLtaxDi|0y5eRET&waH zn<M*Q1(CrO>bExUl|e7W>>TZ5D~&P<_??CguEgdaPI&eqTHLI$EDw1ySC0Hj(2Rs8 z-c;V5<|H0zz*L5y#;mzrf0f5oM+4+=2F_S>t8{2o4pu$-{r2Y6JqCl=Ew?1;-XyIm zxFyNY-Luw4m>+QO^(4ir99L)&52A*?$$EJSGcHr_LUjVZ+G!zJma4Gob>7I5lJinl ztM8l-0vU~DE96<vg5esn9$+5dQjj5|b_w}!$TzQ4P$@;*!59b&ym{G6Zf<)&@FiQ5 z>%PnLU3T^C{OeG9HFbx4kAsK->Vne6G%7j}peFe%Tku8V^Nzs>iNV_u1J%BMkQ$YJ z*@k?ElkYt6iB<e9yu<q~ipN50-uwORY&K2d>X27AVxF8f^d{^|F6q-dif8pD9e?{T zSTj8%6Kq}BI05TnVVfn6-EXA$%m2!x<{`IWMA<IR$#Le32oc^h<imU1$7e-m0=80O z%X@EseF`*nTXuxOIAIKG%j<?48}VnytC+F2Y(c@daZIPI{S_*s=aah1$=HpM1lnD( zwpDAk4pbJg9IZCS26=Zzg=nUYH@Zb-n@Zu^goK-L$Il_Dla_1Ihl<RO=uH3XwrhE! zxrJIu+P-(!#%73Z(N%c&yx&4gvrU!t&z^#B)qj5h%kvKyts1JogME-~1P41AXR3t^ zd9{A7Iv5243+!WAlRE}7H)!zGY?VH67~lptRfbD*bn)Ak1k{0WWLJWRmA7-P?Nu@n zuDy~WZ~)wh@344Ss#~145O8gql)ZRQ)W$P$5R5tT{rgL?Pa1HPJ;g*pt(p5J6v|Q1 zlJ&A?yF`+wRcP_+ut5Pm*Atk9PTG%R+~`?`G4a9@J+kclfcUnN?Jy$hi0JD(S?rFt z!#4*70F@jlNc9=cIym%it{osMdV>>%<Q^`{Ftz2IUS#~(Z{of>H~xU`<h~A0MOt+o zF%0^E$$H80<-abu8oB$4`uZc;Omy^}aE7cI@glizR>+5Oj=7S*7n{QxoKUwMIYOXN z72qArO;hH1F1K#D^mx;BvSm~6f&v!6pk2}9Bf+R2`3Yb+h$tM3$%2B@vknyHgL*{1 zggWfJ;c0VKott(rZ-R5^dXMvtENvk)7y<!<P?tbIff0DihHUDeul}BDOC{$FgqA|2 zp`HXyGTj_z1$^Kh`@A=H2+*yZ@|Z6vZSCFn;T}ntLKDi+J}^uHvZ75Bs(}t5wyQsU zb4hg=S=(`Jx=zB|A&xd*<c57#92U{WIzj^wK`#Vcf`a8J7<`!ZUVo(Z1wi%FFHblB z=qxp(PL8D*4Urrv&<BeKjtSYcf|zMp9YTNcG&$JtC|;pY*{ae7kPG@u)8q-mj_L8{ zC*`>pn}M^#I)w@=8qVReBdgx8o;7>v(k*QDMMaVQZgl9F+CQ?wKtcQrBKLXVYJqJ! zK<}?dNLbbyvO*1j6q)H3ozbRD8TO+;Uxx5Q5-ut3)n0MDB#*)!EF6NBil%$scn5pj zBzB4Ag|GZYGevMsUaiNQmsQ?;SX`v;uTCA{Btrtu^!b<uxN4}b`N0VgjmDtl9AKqe zR8?9)>*PGE1AjGGa!J_T$X0*!7W(e1p>+VEn(};6d{(*RtFP1Oi%$ZL52-wc0Mg!a zyY4jBRWH6bL9UE}I)dt7D2+QT9hPP`{2E)~!-3gwHPgkY1wP_8_%}-s1E7LdnXd{# z3Tf1*c{0#0(`-wN8ON#5%ve-x>WizbqX5@#tMcCyE@s?Y-jPG$bI;rj`_;0T37z)b zki%omID9u098M6{%G0K=&p=}PcYdms+K7o=y%rlY8o0iNQ<5&ZOKgRRr;B7dNISN0 zOLF7pOa^V*kHne8gcog5J+j7H1Q!eRQ)=z3%9r2t^uT)L19Vo)6VHi!1_p|CR3SH) z=|{z$`4rlWn}<GhmbkBi+1NWySaJ(>secM@hSj?;;-bEeG@t%0Q|$;;_P_B>${R*_ zAhXAV%uGz+@?b#~P4ktM9`FgJsNp){YL@Ax*EAck1|iX98w1cp?mMB!SaPi_73}@k z>XcZDb<PM|@*Iu)__)9vEnQl4PTnDiphS@Yu6{cqRDgXBER4*>9mJhC6@?ItO(Ks` z?nx3T3H_350Q-#J)T~(o(qmeqDFKX1@Z;{9V?EW-`IqQgmXb|I$Aa?bWX!M@h^_YS z@T5XyzIlJ>Tr>7Ruq<Xo4i%p}EnUqCKG7{Y>@tC|oW3*i9TGlS>m+UNEA+_Ps}Z&H zBsC6u?428hBj9LZ1x;O)wMyk*doIUu4%R{|>ntdnHT^Bv#*n@={#A@6i;VgTo#+!L zG`6T|vKHsmEsMJSW=|Wf?5N)wv?rv^i3rGUib<hez4p<Bod9&-(yy#mo1Oh?xQ?)8 z`qoe!(NKdE9$K(wG<;}E1KJAH2I~u|xVuardW^npNh3L~2(-IL^XTTG<rMgr{hmR> zyf1~5Uvq&|L_f1I`}9>O9cqxBT!N_6xUc+xsPOo5Y$B<QBrej4+HKfV9cH53a8Sd4 zCpx)`$H}}k$27w%ejNLaIz{L~!&4jvt)7HbPYizj9dmdd;#B>CfjD{U;@^Ka1W?)@ z5rjoj=wyf_$bPqVP(J|(fkW%XFh<^(8C%Vc>ds<_ZPl4x6HwM<%%?2t80>Wv6pRox z>h9zlac4C><B(OPN8W>Jjp0_}MR?A!01O2l<WI6Egu-JEbe*h={ckQ&M(3cXe+ap{ z?Q<l%%h)ePj8Ge5P9sq;S-e);DRxY!TmmPocphgTe$G*L7BT=JS(+Q*gIE+e|K*gH z800G&TQ&3cUgYdd4op^JrESHAs_uUMM6|d;Gu9*JTqy3J?u479`#YrvWhyDj<A(U1 z4_a|9($wAJ-5EQ9@-c>cM)Dkx9@VYrX(*DcJ@5h;Ut0d-YWTy0n1+C|_#oE((0Moy z{qf@TdVjwJI0)l^gG=XlU@1?{=*!i25sV!5DD6ESb(Bs9oe@`F=#9&M3}{75{hi%; zayHUq+@o^WLIirA7C0b1<L(WUF<O1i@jGC}&7oY|iXNt0esCmCUe&ER)ZAw;kxVcZ z+%Wu)FP7_+J21<=AX-|8zgyMUO^Jk;TA75n>+yj#Uunsq9N0RWIS!Q?6V>9&*UcB) zN*cXSXKkYZTp%%p3J@w!y4%y^Wh!fcSV4pqHol+#{piXJ&IO+62txa<Z#JJl!iH|V zv+w(~wMz-Zp<H?JrA~L)5~H4c#RH@)ZoS3xR@QR^sQb74`)6>){z@MBHu7d6j%aaU z8T~Mu8DD^89*fv|9h#y=T3gzx{fC~#U~RWww-_8f8%y3%<czE<V0U33^zoj1S;o0M z+4a}DnljBgS>`?H-Lw=u{im?)rRUTYX6x>gUv4v2m6{wqmdx)zkw5+*HrYgJGW3V& zm0jYk>k7Nd64S#$>OKT2su~X?Dova>EhCCfUyEu4F2H5+o^oU@H-a?VQ}&ats+yeC zt*cynOX9DjxmLHHWgpNru@M_owyItw0#UZ?SW+caQV#KFWFuq+*iYgQmaQgqzeQlT zQ)b2xk07=g0pe3$N{_;k`7f1Bnt`UnNI%m~iBz+EOwYhfvV3EK^x{@jN(E}q--kd3 zde}X449zc?!0%PGn<>4OR`ZOMuC{D*!hhKv$0_7`R$z-GvoP0rrD_R4z#V<tM5DUM zKL!2})B3w89f^!-Oq&KYMKco^BQ}TuXdfHJ6M`XBVlb3nIz^RREvOV!gA5LvR4TL) zWGX}V_5WVHkr&ii6aAo5W@fWE(gfildwc<K>`*Kei<cc~kURdVrh{z(TvQIoP9vWX z#C(ORtNs9n9G|;$^jeaXk>DEM$g+(F=%#|f)UtG0RLYq7Yr_%a;7IN3Bm7wQaZ>kl zPbV{-z%bmDWy6$=js_$lj?)(*u&G;gph9V+$W+6T|1#$lwy(%vntZeR5v!wN^xR7F zGHly~V|!w*5amM}uy*@k$8$<YcB;<~?q;o8m;ZYOKmUx)(2iP^88_74QFB@{_&Df5 zd8j6Kx2;%HjDL7tqaLN%0NWW@F&bxA|IX}&>w$XN((~>L4$z&R6{J0j^7qXd@(kKn zSv`<xZbMy}JuGNsjCfv^fW7Z@1(6Xz4O^_Zb39do{^9qoV^*JsIbQbiK7Kxl)%563 zl$7<r7>u>>5?}*Hf)LSwq#%|2&@p}XvAmt2tBDN$VYwth%{FoH9}@3M2iGYd+V4ED zW(<8KtBH``f+0gjU#MelYpRV8*Nv{~E4B(WUq_x6C11y&_@7tV6>sl0=b@Sber>t% zwu_6|RC{SKPu2ugnE()CdxFt)xo(b=XPkORQq{pbJ$-G%C{-ETazWcRy?8@h<yAO` z7$<F<dyR8syQ=q3u8WcB$+k-fnX~#a|IWX}Slx+jjwNFk%2M~hvYk;F^mDJ4)m&(~ zvKj`oz4b4gU8^iu{s#CiG>cyv-irJ19Ta}T+@tv{wsr2tMqIs9pSo4oEv}ol$g-;P z?$sh~?=9ZW3Nq&DGVbXj?zAFI%SU(Saew(cDF%a-bH1Z|@nu&4jvAPI>$<dDIAJ@N z;4HX!kH}g!#3?*`3`jrDWhmHN;^ush^<g*I#&VxO$I*RS&!4|%wMzPDbQEfUl!?Yu zi{Dex@)eAJ|NXIgc-W?&TIof9L1Ek(gMA4-I^VxbHy2voeoY1K^&f``Asvr>U>y7Z z-g5RrhTu;)d1ZJkChpmP1`=k+@H72&(fZS6M{Y81ZOpzNXoy1{K@8j?4{1Nu`teen zsfOk0Tkd!}h}6O~%YC;ung~;Q;zBfZbd`g+T;ZNu|8E~w!g$O7BF(u>h@0JwG7_^s z!rcxTA8j0*s-Q0|6%6oxShg&$JdItU3*>+I(>0+EADK`MU;`qL-g&fBySwzv?e`gY z4!%Rai7Z!8arVr8Oo2)c-2SRvL9N1xr>$qe_1B>U#TN;R^v76KFIfFPzPs}DjN_Rn z?M1st@!z=3b~`y|dK$YJYF!bMF(B-50f(Vym;GKnW5icVfsdkdJR3_y_;VpI80S8B z<#{p)EXFVcpM*|(<T_BG;Wxs-jWI5p{Jl~;+N?0o;I?%^WssgVcK|9}vgrNX%us-^ zdI9iMIt}9R83V*kQ$?N!#{iGF?93F|ogY9H6nUVI{&S#dR=+szN`~lp3&RYihD(E# zYlU!TGTb2?qZOz{>L@=4jXKfQ{(EP-(8X2(V8GJq$Qn0uQV^(t=nT>Hi$`z*PIu%B zcrN^%i^_H}d}T@qCaTxfNm<QvkS5QVQo=KU!$zw?3<}|N864bjQpmo!WBNlSD}Bs> zX>$_}wPSUb4fOXDSx~1Cnl?}aZV}^R<lKD^12mt3+IACkU4LXN5zg@z&u!INmOi@C zVkP=5_2bE2vqh;;(U(ZkMBop;bByRMbx5zf#dqQzL0pRt$@t|(kkGhAxX+e%C6c>I zcyjk@x}5^Cxx}~iwyTsu#omlFdR<E|JmuJ7>2d#%OI|ToUPj+xCWyL`9UgNC(@`Cx z8-H;}uPR|-j(crS3(82|&w|+EiG@{L(z5l5i)m0`HZ6mD3}o0AH1xfMZaO5y?z9>m z_O&4X6+0%<b=b0HSm<p;VB7cFb%+magw=g>eo{m)F#4HmkFlpp4-||CN{V~Q8)7Xl zdhRh02?o|G;C;<*E(q*e2-%auoR{Dqhx8&#f18Zy=m`|>H`l(ES^m+cA6r0c)c#PW zHlC!bCPPD2N|`iTvQ|qJjV%d>%5?1u+jP}9VWH=-EO_2{(I`em+GaHN7phm$ln_bZ z1}e^p4sWdw*cao@Hv_d!cB!a9AD=U>&_4-KqvU9)-9EhWsyDja`v_?i1O%AI;N$$& z94#Mmaz_#JT1OM43v8l5UC~&-<5We6*ulr0gS^`l44d1KE*xxVl1QHZ^x|8n?HF1W zk#*t-K_MO>BUq};-Ek?}V~pRr_i6fbxH%cVl9d;Ut?%dlM}O(B_(2t@#-kVnYR0`2 zsu2dzv?Z}a7ZV>>IA{WELPIv^<+BAy`Nj`d1hAIYJ<7OZ@trJB9P(T_IobF_)cgWf zfw}D2eMcT@tGg%6iZxeo2q-ekUncmJwbZmp!<89dp)HjNF5vmk{K(su6c$#&IgyNS zBB}ijNs@Ym?dAAgwtu`iszFX}hbS(4`P|pw_)%rrSJhb3qd^ye85(bS<2q@T?CK9X z>;rMvzCFA~1Y7B&8o1U$<x0t|<0BjU$KC1?xh6ORhk(VlNl#+sIj??qZ>L+|gK>eF z^Q4U7!++=O-Yaj_Pw`T>OodZZG`t#9!kXi}ap@lEZrHtsI2tBn=R=uBySTJ=jrVSf z)}Gro>)$7D=d>s5tiAKeKv6A{TGHif0YHjbfzo1}Ys5~QUL||I5_0{wU5^ZH=)Ip? zwz!)@(#xkph4LEA=A|-k^&18Xn|e1dpBP{)4XEnEWO4}r16^<ta6*QqcZgAAfUk@L zDoBN~j-oN21|l_Tv%j_CPrKtLK}e`EeDe2wW@FmYpk{}b^&!xpwmEPtX9Tc9k9>*j z;3h#R=3UaUc;Xd%25|&&Z;bbZjrajooR`8e9{3YjU?tq`!qj}6Ldv?HFpXxJ9i+Fw zdSnO$0C*9YE|#WgXtMMm2Y<p;)-XQWLGSd*R-z4o6Wl0Pp4$m<DJ`ZVT+lH}b^fUC z=*oECA6aw&&=L19V|aNz0FY;W$Sdx1f^a*amL(<JeKj8g0vNbX%7Vl_00E%u+a9?^ z8-h#ahxK!~HlZtP??amAaS`azMMiXOe82qmHqd95u{Uz>EmOA>4H%yCe6%z0m#e^$ zgO{$-C}*ag^?7Ezrh$22fO1&PifzZ041=92#J;?DQrP<AbO~I(5NugsqBgf1oATwA z3j|y|3druz=bQE+0KK56sRIvYG%Cj*mPk((oMbb;8GG#2n5HQ|y}rD9w%vlNyL()< z=s20pk=7fws85Mg(sP!((Cu3=wMiP9jM^-i1;xp#AOF!o|08n<`B6(fOU8Ed=_~m$ zSju>7AL5M?By2<4mY}87aPH4c$@R7`M3&`7?h(5knx9$(0E+ir&X-SqBcGU*Km4Op z(m<)=(p=8{gS_-~St%udq{$`qVIF7C4dyEHLV<`*y-8S#BHAQPbv?ii7swJ@N39e9 zFY13E9N4;v=QWfxF@9+9ay;LhE!uqd%XN<8Mx-A&wB1wj?E-{T&W1=a-QsE^j%&ZJ zQe-raenliJ;VT4RBl~fZII73Ye?`bkbd6gtRIR~oIPD)dTn^-<mDBQ;8H-|?Is2S- z`Ky!UAiUfFLGPIcZd~tK0B-feiG-ZKGfAuy3a9`nZMpN!(4TSA7_bn|E}kcNmEd<a z2V(RFYxly9SToU^&URIymcPcxkTIM1J}zOB(7}378X_9^;p+>qednBTtp2#LOQ*{o z7cy5Z!Yn+vVIOX?R2>Fsa$+^R48rG^QR(76ciCx#qt1@B?=niQ&<4htV3P3qQ>syf zUIEgNB=VTThhc9#*l$mDLVtlhMvkCb0YNqg*03PJWKBF~ZS2Vw^>E@XP2Y#C(dTbY zvfb*MO|f3~w<pbldph3(=n%iVGUa8HJismVr@3h^eb|-(9W6I!r@G$`7t3Fp^cRA^ zi^>`UY^OH!&-kxX9F$9`Zx-xX6BB0X(j1#)Xes3fV!q5tRdKJ<Zm|wnq@H3HG24D% zP3M^$f{0<uc0C}i8;NwK<!RR91ot#|U4e<|+<<oHo%r2-sCOUa;iLgykAxAiVU5}z zzLZsGirRIzI~nUz|IDcYH`GOrp-uzhV+AKEw>Y?KRpo$d<YSE-j9s^QTEML}mFV-p zYW=6J|JzPXFB_)t^tTXmleb4^NqdV2tJTvY02;Qsq~ccjnY!6o+fM38+pmC5T52s9 zK)-6^avQj~3$EA6)PScmvN!ch{?j}kc;2ZqL^<R#U31E9e0nH;x5iLg^r?4WBUm>} z5C?4`c>qWWZ<$#)j_oqw7KbR)JM^-5JGM+>ITw4gtl7(rd))SZUeG8=^v=f&|29dG z$KBUytixxxmvjfwLjwrUS<YZNi@yBpTsL^@9CAiifF?OB4WxC!x6hyi4{tQ+Uvg5P zI<a<hh}3&<8&r|=!1eZV-f_``KF+OAI5b)=w_sX+wSv3E^{N`vJKgWh*RWX9J;*s8 z9c0+R4la0ntWaS{=fNNPr$Zdf=_~oVRl*A?g_i><@V<HJoKgD#4d5=XaHMYkYS3=t z?@rOnGp6{J8JIz1d6gOI?m+6!31&97;5E0z7rMn&Ms!l!sP2yXTa>%UtQ=9@l#Q_; zAR0$ecE3!NT6W*)^ss!}?`_B?sxd*%s4Qr8g-p;%G0unS-l*_aLDiHQR?PZYUN>A@ zHd01Grqsg*c0{;u(Q#k6<I*aBFY+IbICR&73>r^l%BTOe{FJ2QWde9)ghyd3lPmD) zyH~h=k?OXMmsKNbAsXhDk=v5o0s7W3mLM(E9e*T~>+Rolg&t>d-^yU(YgvtlH)bo@ zaNDSX?10xduUL&F1v;iqsHh{-CRTHNVgX~ntu_~?EsDz9u(tsJrK3!)czRrkH&c(R zTIMaBhnOYM2QGV5uJPg%zf~-T?SN-9<}uy#2D9)*`Ci2&V5^Ouh2i@W5`C@}tx-#e zICCM)!p)_k+WmkDNKJ83mRbB&l@sf6G#ij?=%pNVTZ=Hyj0k~~m2?FL%Faif?w-dG zii?3YSI2ae)qu>02~e}b8t_W%<7d}^i}cikh1Id7J&-PbYv7;4CWzmOMoU<MD65*a zb%3O|w=iTchuCI}`t;^)i5}ZEPilz12nRDmK=d_CxXa!GTLYDg2t#+!5MUP%Rf@`l zMH~v@cAp!NQWu?w>1`v{a2bpXq~aXI?js6%cE~O}7ml>M2p;!H@sk}2ZksG$?8EAg zo02)cgaSx~oTsKrB=;)Ic7$<r((TnklJ^s9^U$XhRO$Xx92`2T{wP3B>}}w$E{Btb zEB=-azQ*eT5M43KrlEz7Yf9sF1X|@Ta=Eo^5-4N8h0>o^=QI0C=L@HrOjqG~`W;R! z(o*=MplWQ#qumheRud<qi2<vV^Nv!=pMVb(v0GFy34yIj=vr{tFJ^qao#<Fw`R`7e z6<q-gqDsM%1rzM8@*Ve_F634PeIg~uu~yS-FI2<)D=d}XpG<Kn^EI=kZ7~b21belI z#O10RUvI9pl{&LoEI9&guDj_Jm+?04KG1k!hYiIEqaT3^y|+3pyQ{L=NbplH6WRLN zg-#Y6mryq^Go&G9r1ViLz#(3>C`r$tpaS5q!}>P%P_)v$hot+4WggU%6-K&jrKi_z zAkHd(HjWL~L1cySUV)TlZrEDbumnL`XllH|OpxM$Wb2`QMZduNMPKed<i;y7Z+cOd z?|6OJLv46Py4>-?wPyMO+Y=@kHLh8B=22649CwG|clXdUkb5E%nuHRaj=SrTUeV!| zFmPNsYr%bS=-0(QkwJYQ&uo2>+jMy~i&DW*!!esG$3vD>=UW(^I6?|N+)^92+=JK! zMXaS(|E->?j-XFN$XUsZV_n+a_$SAbSo>;6Xn)DQ6MrSNuGZN)>-cec$FX`)ri(sk z^D!!4u}wm1R^@{o0_roie1wLU53Q-w6vS{f$b{17xhTlR7mp_?ZM_*k9h;4`sj1Jz z?HuA`R92!Fh4BF@-f@ib*VjsV6`lM@4Bs@vm!R~x5qiNbxh^DU2+z5!BJypI!MtYc zb;nh?S&<ztFzmi4vvfx8`&)SL5N`OT_V5$7s9GZNceM|Qee{ZjbB9>IE&^$5LGDKJ z_7L~z?1?I^BkQ{K5~1?~EjvCf^c$2GkTweymR<C87kdnW$}IoL6y4hj+m}ArTf&~8 z$~@(uaAG{Pndw<|K}TV(!u%<$)jg1GdVSxfNwgvvS+)@*;*>S<f6XX;Nf!idoS0mA zGy^>uM8$cS-3g9=_q;;a<0<8~iSCuN`*TkM+?z<`v+kAmT}MCpd*$T1Lk|ovEQ<V| z#_iySFf{+0^|?j%#kC4<zFoVg_8ZVg{dp@{7mzEs8h&Ej?O#FJz5Ho#Pjx&A#i?5$ zH@pf@J`!6r{iQ0d^eZ_ub2cFKaiTxXj~9Y3=w{Sz7@qXP?`gI){@t%y&Jk;ys+ruJ z5MVCET$5{E<$A4A0DFHk{=TlS(SiGiKeYi~H$Ix5Ifm(LyFfF~iibM=vEDtJO}pc% z=Vj>`*UUVd4D>G+!`dHx1B|^JE!+M2KOJ++ZBcm5qpZw(-82-4L82i0@l((W(W_NH zqS&PHcx%Mg34LC4Mst9RnI0slB3q%e1={+cW*v_<EwtJ_;R!P{mYb;&&bdkI;6IpQ z3*3N(Bv9Q0%lJ<!3D53_JGuS3)_ly9^t3oi&6Z1h$|Vi9n}t&GY5U#Vms(v?w*znP zKaaPk^^-pSrhQBbx%V-2veo{>?576<fvvX~m?X5to`gi2PqNGO`&L8U&>BRxjeW1i za&Z_wob`T7ebd*uZ3S`xBu$RRzddNSvCoAoZ+rV;xc(_T)LXGD0r1iDXm9tPkf3X! zwZitu!hl{s6AlFhy@a_t4>B+Q0ns}MLI{NPu9&{#)ac2wa0=<Ae9&m&+P`XV6EBY} zqA3}nwJEBo)5?kaYtGr_(GoS=pd}BSrKzxiUJ1fTg6Vtjkte;5rMu<J$ksPtF&=g3 zBICKlMOYmrRinu^(<sy#*zkyQn4;^L=+Z5F&*=Uft=}T}Inw5jD=6N_8Kf*yNR*B~ zeU74v0m~Ys%}HS%typxv*tCYkM=ww8%Qi*WOx0#*j;|V3Z01IGlW7P<ln2HWAvZec z?FFwWg86K-HCDEq?rY`+^O$5KOr;<lAix|RCa&|KmfxIG3$u$<7X-85aA-@DRWDc5 zUZm`Q+GMng7nyaPP|kFdcBRh~YgA0PW_koMW-k`Qr3kbNHmbp8a<$pY7B?J_1PI+F zr@|hKiU<SWPFrBKVtY>%sbhB-jXI1)d#pb>3}uDeD+o+HysBVw-{p{uJpJK{#e=fn zYwnr@H<%*Dw~Wf-;1v86>7Dk*<`CM-o178`*<*-bJPoeVY1{_pz7y=LxOB96Gk+a5 zm=*Fn6|^-p23n-YEVI?qd6#O3-@I1k<O|8rb8^hUk7r18x2%<LBAue(Sqd7tErm70 zUZd~1%Sd!xTe)jDO~6=hDfSxDwvK&sM(x-qzbjG0oRCWy!`$o-I-zgFQV^kEkqwB} zeLD+|Krwh+SR4)yG9xCudtkwr;txD1$U)SJE(v|!E~vT)r3z>o_)#V7s}Qv*^l5S8 zkVYdFxNt8OV%XACZ{iGKSG3tK_9$AP=<2?2epe@vq}u<vui|aFbs4HTj>o{X%uK(# z*+Flfz%+ZkQSJF1LX<BVo@|MGEz_q>W4~egk&m>7=U27_v%WLFN*!)dztC7*s13h9 z8ggZH=p{u*o%uj4vnQY>sWkpnvT=Vab5~_Nzikq3OoC>K%C}SvJ&zqqJh_-~zl}eO zg83T5KdZ0|t-^oucQg+t8r(YIJg9PjNvueH+=<#<gZ0B0NDa!JzsJ;2p{d`9DB9ch zTa1w<>?It8;EuWz=u^g8AZBXXhD0xK;I)V^LJ74xN`<g(I7$j06(Y*+v<?<X%a_O~ zgh_|=y32uiFMGYIFyAHAzs01}i@rg!He2<)g08T;&+vH8+&>Sh5U^ZIL$!_q0spW< z?p~Gk!_JDlkea^;@%DowNN}UM@2{lt%T94LoA=d*m)&6UzJal2LALrFP-;q*s&!b# z4NoUBD1N*$qnD4mQkXtOn&0!VaH{y0-?I4gds4xMDc*52px9(n!Q&%PO+D2?>U{_Q z6Vp*a(qc6~BeVJ8<F&nAunud?^qXrsdN^XP@}1_j&c82BZ$d2gJ{R8_{M5SlAH`B4 zT|>Y<>2{^cNEm}si4Fp)yw;!!@=gM7=teE@TC40MC0Y8{nfUewtt>QENoM=eXNcM8 z=$_<T_^^gbhc<j89C9k@B|^28Q}vVaM7V;98!$6od1&2+K#Zp3%LbqxS~Bt2U(PJ- z@Z_GRDLqLi=L;t=)H?KCC{D>f6=hK+t0`|ZbYS?w!6}p|YLjE^VnSU^c*I0^Wn2Jn z)eh0a<BLzb<9kc#y9m?`{OPkExpKMiclNz3cJW40wgufPB>!ZQy}WU1V?RuGj&=J9 z1EEN;dqufRzaDwA<Ra6tFv5!;1Ym3YJ$ypF;7?W;QYZDGnb=lx%CPaB*ArOwb1-VC z9q5A;%iYPYh!E->Vm;Bn)%Y@Kc-2aJ+2+6I($3GgoDp%;03gPH#!kZE?SSWWo_ezq zr$PcE69K0dC`6XJp4IuN4|Pm4jVlU}Jj}h~n>zLKn`V^-!BS*tuh*8cfn}6822xNK z9+k3ldhL_7;VvFOvENPm2HdR5_UNfE<NH3y-CffZ?c!-AV5v(OjI9Tao)Z99s7)~* zKut+q#g%H>LImFCNF?x>){l0>it(pHZz$Hi1<95MoW4&y&f%3$A0JYcb5YQ)QYGl= zHnu4~m{W_8e~=zcMS#gLg=gJzZl6S^aKJG_iJLi7&mue{!SL;-BfXTZDEXLeEZnv) zyQO3WU@=a*djxJAgJ2CrUI$3zy+SAFV2#lbnFo;xF<w7J8Sw=P#tD{&*G_*ui`SEn zh#S}LL`P4tzO@+kTk4mKjgh`CxI^kx!$_Mh*oH;4(l10W*Z3pd>ar|BB-l4x8vyut zy#M5)(9j-r-p3QZsdNuPTNr>POlJan9~oED@{2);_FXcb@Wi4_1Nj`)i>%R`b3l|- z<_VA*0AG%0@=s!GtTudXo}E-ryjJeX32j)`*E}%<KEoPZ0Ww|#baimUcdEmYOZF9_ zvV0u!Eyw~|CQ*$345w@>^i0940d6VbH>h{D?s<mZIg2X~?cC7+5JlLEYwgpTdu<j? zJIXy42Qlmrp;0btqqC4PH1>R4&}U^(Bp_ktvHm*5Ot%V%XEgF%A*+}zwz>loGH6*s zEp`@WS#h;ovTy&2?Y-7R-QxQJ@GI&x!hFTfl)^I3QF&llOjS4J8M>Y%G#`d2CtWx^ z_8j~s2+p(R<)O&9gn<I!Z>Qf&=OvOBRC1%fW1*c}iJSU(^Lt|43$0C6mZl-{T9hdS z<_@tV)k5MH?hD4f*cCQZt3mB<Fv|qJBx7VH(B@lZz_E{tcgp)q%l`%n6TV>d+Av&o zR&j*nzknKUEK%MPvyVihA#IbwkZv^O&A)(C7Nl!j<V2UI+TZ)Jc1s*1oCJdb``_sf zYX?Kx*Du@z*v0_tH{Ol=E4R7>XQ$*hHO|QK%5ri}t!v@mbb;-?g31uje~T^=A9t8< zAyEGXCr^P?%@R)8d3<pNd<25E6;bjKV3KnaQf^<9r$D9&s7vyDeD8&w@v7Pg0lxX6 z^|Enh=ur=7+14@vo|IdO_&>>hu|zp(4=rebOG7;_!@gCE=m*jLNEXRXN%q-Vo8w$> zLZt~iGDm%|QAy`ULyP^$ikx~7>N}M8mqqf1bCr085HAe_omRC54S8f3%JK>i58UHO zwXAR-(~R_tOde+dthT@4c#|SC3G2bPUNOFH@Azu8iF!;Bcz~av#~PN3<5&8~p$^|4 zpkDrFO`gm|09RQvAI1A)kyUqg5&quFmz`8jKMGaJ_qSj2Xc{kJ85{j(vYwTQwShU5 z@Y{Y}=Jja{%vre}0%HLr*`75Pq#ml_arLXZF5VrR_+!D}EmZ16KCh3i79_uHf6J;X zX+P5F?^eh`!QNVScxFV2K^1z|Ko%`itp|8&K?6T9{P2kc0fWo$HCihGoFFey8Xz{Y z&&1<1zz{n%5eQ-~RVO|Rz_^=S8QVd=;@&;Pwbma1H2=LT(2-`nKP<=9;8D)xpiYkC zFx3_ZHZZFLg|kYWyvJKfa3eJZzU0fR(Tj$Se%JiSC=kY-dlR6uOV_+O`z-+k2RpR^ zIzk2FL!s2rd=0}Os<b*a!ax~e%jE6H(Oh_w=5NKRr>O}Lm>65I#{02cQ%jA>mzR^F zI;6FQk#l{-Vbb2Xp(g7l8>u{qlBc{ml=x2RKTku#7DxgQ`F4{TB3lgg8C1K0Y5)qv zy5Ggja9%3<Fq|m6WZQg=;w^?t%R&eaz4C>L3GXPMu(gDM6!eb{CHm1G;j^7$`?^&V zCUgz^cMv$F>(NeBC1k2ah(a3<lMd;kDJ0pBabMAUIrpgL9(l(Ot*Tv!H(its<90w) z->h0>o`JE#Tkb@*C!OQ-Pv^0+*1S1OU#Q!u`bfRmIV^Z}0#;CtEG(9ceLMAYLQ~9f zF`$k|w@{+pqVE@Wq)|$w$^KD~%JS~TU1{SR4YdZj4M*D>_&?bO`brKm5=!!a?c%+D zcTrS2JE*HKMk$TAztGsWgNo4*L#_2-JS7BIC-W-c;|5uh0iirhNFq>jQ3(1*8$;NO zX-4*tDebC0g;|1y`@Jaf^iR^z4ahK~r4(p)Bk@eiH7GuUuEV#u-ETC)IWgzgWf9Zg zXT{IpC^B-Wi3GJW%JI`#yUIOC$~rl%Pe}!3S$r3?zb|<@2n-dIbA#w+&bk2mwv-Dh zFN_uyFo*83Va4+7f|<{o$H?MOmJUN13OZ`E#c@mq!q`D{_eDuhpZof2loKO^#VwKF zZ{)=v*W9^9Uv2^h<*r=U<EbpwA|h)UI}huHlL<XV>eV_yaR^>pY8R#}ZW>$267qRp z$3zJywcYx15`i|_<^KU(q3Ma7TZu;h+@ITTh}J@ghf0oZ)@v6h!&1kdW2{W7XlEuj za^WlebKG~g;TkYBp&~&<R7TVNf(SFw-G+$XX}U|775+@c>eV195?BPNXB2-e5nd_y zu@M%O6S6qXcY-#3DxAldCqh8wvbl1chG=zFKO#sb{ZgTH>EqDT&`*Y~srk|;Z3RF_ z-eBfT!%XmE1$Q?E_0$*Ad{&|Vm=rG35?+Aj+g_#}fKlj#cw*FAG2;nU!AJaA|1qI+ zhQXYPTbZjJ`kEm6{+#wIA3pgtPV_~B{s52nft>{_%P)M`4l&vP`K<mXT>S~?>se8Y z&Oz7?urjqNOt{Pa<rT_L8%np#a4l~jO1ydg7Qn-J--kA!NcYDlMJ0-&<%y#jk%%XR z@PMzzk)s#av{e&DG!tyyA#07E6e#p<@ZPt&xb>9Qg0hNKY%?H$qJjtH{%{SDZ|V{p z!+eSV5?^HOiX)jOHY-Ayo3J8ZO^AXhsn1XCjPg=)PbWp)lYE@;43`jnP6xMaORO7} zSqTVf#y4L!)}tBzI0!EuI6~?br<05WTr4ohjX~CdVdvqNz1I)t=bx%!w9`Xq3Z==6 z=Ij7fzrA~J-ES$9RX)O{*}<=t`KDs}h!~V#1KQiU#QrjGmlm5ty#ZT?hmL}Qie$*T z$9=vNr#J=zBgVCQcw{MTA{QA#&T8@2SMe;^03Dd=%#z_vDFx}*kWlS9qx~kNg9L?M zeI#JjXn@4aHB&-rY7FePfRvW|LI40=99e^tf>qZ|2La6Q8LG_oz#$s90C6q7h}N{* zIx*KcyhRV*{)bN#RZe`+(Xz!nqil&jnEfB{^Ao3*JDdtQ>{ncV{;zc=nx8Y=oR~PY zxjWJbvl67oCMz+6ws3q<@|qu0{IG^ld#vdU4JIJhftc&m<*eQI<#1(fMS2L-s_^>u zs+2J3jS*`Z5O7@f55qy)IQB29ESn|p0-9i@bqNA&7U--5a!;2@KM~os96jiP4lTAZ zku_?u$5{P~qw<V%Z>Bn(rWu^76~ISR7j+ka?K(^h-+VjBkrBdNU7PeKna$+<j@nOl z6G<B~T#KqVs}6B?*<CdnZH=Xj*9(5WEIKS73jzmJR{}2O$N<~2!P;e7BzIdpgC%%L zSFK%8zcA4Ej({6AXoG;e2@H|~vY(kA^!p`|UK0P@*UkZRLlo?sKUR63?an+dv#agy z6G(i-QU_`~>)b=Y^c$bREprlyt6`FFAnbH=Z#Uq|=g;;gPqH&VCk(%C&EDF6&ag{^ zm3IWA%9|R^x~mI<i@i$E$P*hw1RVoEv-fVNB>SF&z}ig0A6G=hI;x#Vbb0W>o#SuS z!~e!5atW<Cd0piKhvO#>UgELJWF<fZW6ZTke@ZemU%wE=JlBX7oG3ixrJX)>h7q{> zq8vy_W^77FES}%u-^u_0L&~;jmVP7w_}p_BlaQk4Cq4Yjp6r_GWcJi;A9$n#{DcQW zmBPkPkbJk$Cc2tr)wgdI<o?6W*}WPJ5+ZlovYRhcsy=kOa`x@~#nPk)zCmWTz|lyc zb4A>xU=KHx!FZ^WqmN$W?i(&yVux*@a^FZT*TyrCo+aozD#xh0;T;2CI?9p0FUrL4 zwA?nI_}Q)W_0%V^5|BM#iV74je^*kv+|JpD|5uyP5L37c?mKe?=plfM_JV>G4JjWg zch;N(WtVk4&)zonK>;IxdN9F{+5*T|^8ff2>76%{MU}FVF^JMd*Q#veL>I^Es^X+; z3pONbeOIxt$rOAUjMT0)6q@&e;fVAgN`ae}k;vi6gq?|X5(YbMnUNZ63MF~+{|V=P z%sy8D3mY1w0p=C_RLzHY3-()wol{U;Wfg_?sor=$;#7~Fo@<L`*}w;IfVH}i7Olw( zU8ZO7(5B-<v@q<L$rA8~vAycOBk%QT+C`Lxli!R=Vx?tkL(?68uPiWRkI@xgaF68H z6hid&s^uLoFbfr<4mh1hXQeF1eNW~jmur$%Ime`vI2s3S-g9JYi!R5HtM<-`TELKX z_A!jjdR&omXagY93W!9+qfLxVd$!H?bFX^<mExi2y9*hGQg?#qe<z(yDj%*e2?1X- z3}rUmqJ%AmLtjlnGrSu44u+m|RqGeap4k5eiDdp1+Ez5$@K`!n`kMO9SVDo%y8ZJ* zYYzI_%;2a}mrMtalf$lQxa}Lt!K;AOA6u_jl&gp0jJrd+zSvc1AyIA)W8TsW;0Na5 z@?rWQ!v%4N>5EBtkS|&ol}MC18qk*8L;rH9e-8NZm4$*B^XFp+UI(5zU^1fK*A?Iu zWYTzSuU{PkYM(D#3W?f}iiMikCqcU3+6Lbbn)D7l3Hm7at)Ls~3Hm5Cbo+r7RDRYB z-7wh60{M}T*}2%WK+YPUL%alN<>-_CZRAB$#LeiQW?03UveHEpW(qLxjsviUpZZ6J zx_FmEn-|;N-llZOY>X^`fRB@5nSDyRU1Ye9hSX}jp0SjLlmt`9-eNtvL+83l)&BAb zCq~s7HweMGp2`S*d$WBeOAk`9Ic0KHA{n>_&XeES%5m6gdwh)zE7M&PuQ+d1$8*A9 zGqcYeUS#=cXiqgFkDmWuZ&&^fW&i!}ahth^8-p23CJeHKVeGq%86<0#$TTr##+YW) zY-qJpD5XV-7M{{Vv{)-kMLk7IS(<2HE!9&Gp0@e={1e~z&*yrdbDdw#xz6=kwxa9W z0$<doH^6BhjbyuCSmy=b6aVw!IC4_Ob(vzhPP{t0dUjB^Y}bHaZ=TMR#`2nWv+t)k zQfoJrbSe1<sJY#TykQzK{-k_uDRKN!%tOx)oAX?EeZsE$cW&3h<Qf^?D}uVW^)LC( zQNphD91WY+C#a1<Ug^^_2xY4_%GJy3hq$xrw(0C6L^>LG+$H}GLdVFlAwK!z!|g(l zh+Nv^t_!kC#!3)xOHDJ?&guP__29Q_DudSM$Bsy6rllvfTY|P?q~}r3`zAj)96k9= zJ2f-DJpE}g>gS(be@`0|R6<Z`t~u&%d1=`&;@9V^(=NOEygtdFPupz@2GSeDoijzS zLlUm#!c;<1uBfz6C4}}387Vo9IGdTdbXgPcYrprC>U82zF5=tcH8S0ehHFfp0#@WV zzJ~K_@8+3L9WaaxZ?HMJ^2~|qT?+SSvL4r!pIQoxKRlXURa=*;`k*4BWW3EQBmt*= z&02rW=Dy%vlWNgVme@KkmUrYyv@K7K{!tCbKerw4{;(%G%xgMRVs!L(tZIbUHwj!S z3V1WM+tKiY&~(7RSoY)<iSBbOJaZ=J+d}M+x)g`flxm)Os`q67>1nHnn9dfqgG2dk z<0`k9AnW7HoKb}P6Jarl(;AlOs-m8*y}7pt2)xzJbFWrIomhwwLdGxZdR8>N*NH1= zAIP~dm^Zhtoe*2fE-!7@wFJ6@ALb3K50G&`$<yv3#N1bg`T?Bl4+h8@MzNWd*YSMc zJ5J?!01$Y`JZBrhlmo8a8IbcFk*QZ+(i{{Lp!u{JuNQwS=f~};?=3yle?xU%e0cR< zUH_NK`tGq^i#hUj-ROlP;6d)o4{9dPxutIUMXk86{p5WUaj#2@{oLJ;ybr8LDluJw z6P!~1sX&K2NA6e&&9(|c?pf#T%OSRQ{oeLU_0we-{YhP6;FCu|_L`OqoMI@tNa&C1 zD;IE3Be0p9%T-+`Hh*`cImJ!+f%1*@uTj12vl-r%<Q^tTy&AZt6&P|2{eF7O1<dOX z(_xQiSeqKI^O@w>h~%X4KA<lH+4v@W;ZhpE)^68V8z}`acKdunl|yz!4}CGf8fT~s zgKP9#w%oQL#2rq4E;7514A(x1^!tP91l~3jm9E-0Qc7*!U92DYOVPGHMVIIcs=y%R zYhlL8$YLAQ&jGD#O1|ux&txUbL8LX?ZVBD937e9ynJ6&GfF+R9BV|yYZMqE(Af#wV zlQOigJWthTp%6$A0u-Z@#;xIlX1Y6r!XF~6w;g4VbnL`}bFMit`?;N#>6mAkU`dU1 z^6u%gj|<x1aqyp?;bRZOKGDI`_{-2FyQ^smTn;-FxU2y?dzH^!?~(&4)S%#y)uC&` z!XqN1l*(>0JvJ_WT|(meBt|Ne#ZKd-b2st$f~7q|DHLUF7E7cud1hAj7Lt>*i>sTv zho_gFqY?n#Br(v44Jx2gxie(Ee$&{xwt)|d48n@Jq3gXDG28yN?Jo`y4KKOV29p{P z2ZMi)SLJXoE>KHbXtc2nyOuszn(I{XDmPdC-b2YgZHB%Qnrdk>A8<LKXKm6(t8)Xb zAC=v`O1ie=Xe^GZlKT$4^K<0=yTO-cqmakV;>9Ib5zQyxXK_hE$d9kjF4hH4sE9bb z!)=vHyoaIJkCOS##pa9}frjVX-_%bx>d!v-YboPYSV~yee8#oz8~r<~ZGKpv{8UK# z{1|CmqWQmih96J7J)(HGxb2iFd)<XwRP&YJ4=ZgcXDkk!_c~Ge>*i7j%8I@JzQ*3| z-#;rK(hCZsb~K1yytDs<qbyAsC8F-64mvV#N9=;zKi=279*x=V8!4KGG<5Vq!m0{W zq?#5^71lP;yB)9trH;}2#&8_I=Ks`^<)8wDMk`He>2lZO84!WNVu{%j2_R%kNu%56 z1q=xfCy}LM2-?)SsqX7f88W^GhaqKWGO}%g<AuELuL^^YnL@yuzB(>0+R;QNO&5uu z3l$3P7E7*3s2AwXW#U%>Awf#z_(B}PQi34ZI606s)#D{>F_Fw+3#FXK-@KJ|jwA;! zgn`ZK-B(ASi6jOP20<T~I&@+{+7vEgZU86(fkFUEy@}zf9O<NFwETDDST{8?7GMb> z0$r}srkHOb@d+$ZKi5^77U=ExvvIc7ait^4l4%qu1ycFE)4bNJ@-1wwhoDsb!yJt# z6wF=gdCvsmf_GeyU6lC<^vJ)nvXb4$n+@>1P=MOne8rwT%fx1&p8L~&h^2f_*b8#; zN<Ejxc5_iQi`qO*1WbJ=C!&*@Av;m=Mc~b_0FFq-pWrsy%Pt3ZFOoDX3++q-<XJrB zxX6Uh=dxMGX~Ikwcan>VnrfH8#FIo~^1aza(aRzOhb9R_;H^%GS63%T*!(J#vjqn# zq#{D9Nc2=4nMtFv2eKu4qUo#j<}p2-Gl@XEHJsY!_?S&sk5Uy%?6rO}l=CG7ePJ4x zBNH<;B_cjMaCRIoh+G%IOeeS#%*pRI+FUWmUe;w1g#2})lX}nOf^9C>CCOJIci!@l zdV;TU)OdT#9&t94-R;XvmcA}hv}Q;8--tHg3J4y=TQ`c*Zp4~=;Mz}I8p=Rt=TbQ{ zntlBTSQiOlxM~uA;z$6_1`UrQ$1P7Eze+^Y_EDfQ#_H$WCt4>mYj|4-GRa2*bu}eg zBTSycXS!@;7#JC^Pwl4jGq~;y(4Dr4uIT{G%KHirs9WxrJYaIysvW0Iuvxh@rVw}K zkpQnx{hGlaG2mTk6o{p#r_)ZjFScBsWdI+62oZ{j9W<WcL6%1an(H@&D4sC{)w_cS z@j@`zPKNWSCD>I)>OBq4H^DguZtc$@&7%oUl2d{-0WA=n92S05%7)GM1(X-J_Vu@V z2f4BRwv%QSR@ume+|4rfN&=qET2`n%bm*i%`_HgC{!j*rA-=12!7Z;jK~lNTAKOfR zS4C(ny>p5Dt|@$_*ZHaAJyXjXXhh*QA~A|7s2--B-oqtp(*h2au}+2ZCs7xA(w}6c zy=10$=_&SaHs@$Bidbf?Nyrepq|Wm^Eqj40M}t3=o^yTd`g@BQC{qFn#`hS!h7u{O zfZ)|BEpQ8xB4j<)YGfnL4%T8?(M>8V2HAETx6a1L+@xUE6K)>9%Fb*`V$@-E&ClHl zh|R__vb=K-Rk+_Kgo^zyjus52UTwYa>FjZ-ji@1~$=Lo`o-+u>grDDPu8_6P!D$p3 z>4%m?WCBR8*=?!8B^{G-tMC8Gf(b2fzpl_lELs+&tFot%#w2EJOpmnhrT381h)(24 zm%@sfo}{YXsiqXtc+ps>5WYKx!fQDrq904>Uz<~DEH&S!GJjyf(%EysP(fUme)Sm- z2+C2<%ik6@$Y?j|dq@B%t;QK5cRrDVFFnCpF7GWf1`HFGTxl}@p-~{n#~mTG-{zZ% zZ{_1@U2Td(lRhe|(IkPYhL4NvYNHf%#YFin5bnJq*C{%^tR}UC`z$3!dLJmB%iXbC zZv$(0>bHIja#cpi)b-V>sr!X!JR9=C)DV_OiX2*2sLqJQCLD|H7HZOS>~~w`TqZjo zq8&RF_|pdSEO4f``YdZDAl2FGYA5?ja?Tn`*tNYq?aQn^nn#pnyhNl;jykLo@q&yP zxvY=n#9R6mwC}1}C+PzzK38;E|GEJ<7GRugk7iN0D>G?r9nU+%*L%bEgt$a+A7l{f zOX~BPm_(!ooo3xWbUkHj5Y84b+y8|?$j;AR@S5s}wiu>nOR>l3$fpkkvhXPK5vtlL zz!vam9~f2p<iOpBL=({ImlY{z9CbLEhFj(buYBEcpX+5#bMo4uddXf<ZcZbsP$|L0 zH^O^?E_x&n#9?{Tria3-en3U$6rgp@%NqnpnA9zy%j;eW4K!SwFGWQlkHj=={k4^u zD%A{(ii-OtjQC4y?{`dSWMF86gZ+ivuc9DAs=A)qgLoTVy)Tx}JG9C!xHE1$e?367 zWUq)}b9|UIaWrG(0znjo^K`!w_lhgEv`{sK?U%IIRp;|&32TJn2q$~sXHx=0gyqIk zVnYYnXZiZp53D#1(J3z*%IVXq@u&Y=WX?-P1Lt#Z>aA?uw8mau#UnP^vGGI<+}K(l zHSN7M@yFjS^>J@^Z(j9tKeOV7-v-yvL_5#P_QI452bcbL<UsEY_3)^a{VME|`0&P? zlL1+5bS*^p<d?1g9V1?`71$2+iLMedLSO+y`0k^ML3*Rw>9SEEYDL@aN6f}o?0oJe zMr9$Wa8frjBXkjYJQJblpjpZ$#Rg7It~f&f{4Mjhf!@pvm|w8L&oQ*BXWxJ&>uyCr zLbH~Px#Sl*-dG-_4xpR_HiaRI%uXC3m*AN_D~}OPi<#`|;GKfZtvXZZuCte~_)Cy3 z-NOG^m(RW-c6Ny2#ONJ6PkjYlsC$&0C@$y9ts~<jf?`5TlP_wP^EO!W`Tc<Fi<jw^ z`zmhvv|dHsef7i>>Ew<|k__UCHdw*VT3ILbgtn1D94dEN3qkEg8c_B1&<cVuIM#71 zsg$gnx#$Kaon<VZ&VKKQ9wiH-(f;YJ>?ebgCk>W~G34s6s_LHu=;K+Ft6&R^eU^~q zste8(syb(ZY~5403RT0yH>|#K-JDvq3QvxS_Sd!Gt4?^U^1k>$#T?sKQC2o9ok{y^ zG;DrJ{q#n~LGrb6N*?8pZ%jB+(S(2tDF4{RQz6-0PS`<~mC!*-BzZmBscX{c(B&N; z85S9p5IK;<Bh9ZSN2}V`@ELhUVNO1Haio`D4{Hfy635qyHE+(J%~~0E#xF9~O-vug z21F#0#~G%j=8?%{KR5MA{X63M7WEiEQWh?hb+WwQg|eD@UTh&yD1w}&ex=K)C5%sh zE*EIm@ME0g{MNH$BCcGAasAFrx%FXAYj4X7i$p(9oU_TCX{%G<W(m&O-Py_2b)B_C zxwd|sGut^nm<RK=V`C!WdvE)$>jkh}fVKzzA<N}X2cxO+rBUKfo7^SMCApQt_CoAB zKf@sLHE~^T+f`_?7|Bn_MBFs<1-N|TnbHoI{YY$=*jcV^+tSOP=?7x8Z?-o}2<92@ zHUwW{m}?`QYB%>)0F&f3et>q7w)WlIjT+8(CLl^=Oex`3-I0W=9%Z50JC2`i32nMf zl$2Gf_pY};OUU{S6q4E*;PC34324jS=!LbuK#YC{iu{4i`g&X*+F2u>3nWrPeauGs z`W-Bz;!jfT9*@u4k{xR}5gMfewo%+?CJSm@F6>)VyOA(N98N{)%2HQ03YKL>6p)b* zJ0u!EX=n9-djgglpibT)OXnFnk<?9_k&%OTkVUQUvOs!Dihqcid2gg<v3puU!CV?O zhMWW4RsUmi|J*@>x~lD!%uK^Fi9cT*Fs3`oW1{RO(!jMVWv=!rPaIaTOD&pB@tOoc z^V`~nx36qW-zI$V-(B88&}e6Cy(Ek_5>Wy!kk~AK(Qr1%-7f5uL?LCKz*0UUZLVS; zHR>h>AJ$O+dRIGx`#5FjiQ_j^Qe++s<>O?p#Ur)kW&-yX5S&lbMg6zmSa~~#9Uxr% zd;&*HG@z*6U`)PyY?@{u4EJM>o*Eo#V25qeaccP-HZFZE$oMWbc-k|SwjM9!u-~e_ zq`5rgR~Vln$C1N(UE+VFhKR`$^X`h4>P<X*4R-{HBcqnFmanj%%t@(mwd*sxHs%^} z8C<b%vz>*3a92BPZ_N(61EfIZJT1}!�OC$lv5n%3xi{UJC%+fPZP@xqoyML}ctd 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 diff --git a/pc-bios/pxe-virtio.rom b/pc-bios/pxe-virtio.rom index 6dde514c79304041837ed0de99678149844d9419..b1ec909628998aa9289b915e59416717e718a618 100644 GIT binary patch literal 60416 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%0AnSMLox`{(uy#H~ef(<aZ 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 literal 56320 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 Xf6_VudT;)pA`bw(f&b{V|A+T~iG=>J diff --git a/scripts/refresh-pxe-roms.sh b/scripts/refresh-pxe-roms.sh new file mode 100755 index 0000000000..14d586070f --- /dev/null +++ b/scripts/refresh-pxe-roms.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# PXE ROM build script +# +# 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, see <http://www.gnu.org/licenses/>. +# +# Copyright (C) 2011 Red Hat, Inc. +# Authors: Alex Williamson <alex.williamson@redhat.com> +# +# Usage: Run from root of qemu tree +# ./scripts/refresh-pxe-roms.sh + +QEMU_DIR=$PWD +ROM_DIR="pc-bios" +BUILD_DIR="roms/ipxe" +LOCAL_CONFIG="src/config/local/general.h" + +function cleanup () +{ + if [ -n "$SAVED_CONFIG" ]; then + cp "$SAVED_CONFIG" "$BUILD_DIR"/"$LOCAL_CONFIG" + rm "$SAVED_CONFIG" + fi + cd "$QEMU_DIR" +} + +function make_rom () +{ + cd "$BUILD_DIR"/src + + BUILD_LOG=$(mktemp) + + echo Building "$2"... + make bin/"$1".rom > "$BUILD_LOG" 2>&1 + if [ $? -ne 0 ]; then + echo Build failed + tail --lines=100 "$BUILD_LOG" + rm "$BUILD_LOG" + cleanup + exit 1 + fi + rm "$BUILD_LOG" + + cp bin/"$1".rom "$QEMU_DIR"/"$ROM_DIR"/"$2" + + cd "$QEMU_DIR" +} + +if [ ! -d "$QEMU_DIR"/"$ROM_DIR" ]; then + echo "error: can't find $ROM_DIR directory," \ + "run me from the root of the qemu tree" + exit 1 +fi + +if [ ! -d "$BUILD_DIR"/src ]; then + echo "error: $BUILD_DIR not populated, try:" + echo " git submodule init $BUILD_DIR" + echo " git submodule update $BUILD_DIR" + exit 1 +fi + +if [ -e "$BUILD_DIR"/"$LOCAL_CONFIG" ]; then + SAVED_CONFIG=$(mktemp) + cp "$BUILD_DIR"/"$LOCAL_CONFIG" "$SAVED_CONFIG" +fi + +echo "#undef BANNER_TIMEOUT" > "$BUILD_DIR"/"$LOCAL_CONFIG" +echo "#define BANNER_TIMEOUT 0" >> "$BUILD_DIR"/"$LOCAL_CONFIG" + +IPXE_VERSION=$(cd "$BUILD_DIR" && git describe --tags) +if [ -z "$IPXE_VERSION" ]; then + echo "error: unable to retrieve git version" + cleanup + exit 1 +fi + +echo "#undef PRODUCT_NAME" >> "$BUILD_DIR"/"$LOCAL_CONFIG" +echo "#define PRODUCT_NAME \"iPXE $IPXE_VERSION\"" >> "$BUILD_DIR"/"$LOCAL_CONFIG" + +make_rom 8086100e pxe-e1000.rom +make_rom 80861209 pxe-eepro100.rom +make_rom 10500940 pxe-ne2k_pci.rom +make_rom 10222000 pxe-pcnet.rom +make_rom 10ec8139 pxe-rtl8139.rom +make_rom 1af41000 pxe-virtio.rom + +echo done +cleanup From bcec36eaa0f8570d455214512f1d6382410c509e Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Fri, 15 Apr 2011 17:32:47 +0200 Subject: [PATCH 232/386] s390x: Prepare cpu.h for emulation We need to add some more logic to the CPU description to leverage emulation of an s390x CPU. This patch adds all the required helpers, fields in CPUState and constant definitions required for user and system emulation. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/s390-virtio.c | 2 +- target-s390x/cpu.h | 1022 +++++++++++++++++++++++++++++++------- target-s390x/kvm.c | 17 +- target-s390x/translate.c | 2 +- 4 files changed, 864 insertions(+), 179 deletions(-) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index d429f10d56..48fb0d05c2 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -82,7 +82,7 @@ CPUState *s390_cpu_addr2state(uint16_t cpu_addr) return ipi_states[cpu_addr]; } -int s390_virtio_hypercall(CPUState *env) +int s390_virtio_hypercall(CPUState *env, uint64_t mem_, uint64_t hypercall) { int r = 0, i; target_ulong mem = env->regs[2]; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e47c372fbd..a84b3ee184 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -26,24 +26,35 @@ #define CPUState struct CPUS390XState #include "cpu-defs.h" +#define TARGET_PAGE_BITS 12 + +#define TARGET_PHYS_ADDR_SPACE_BITS 64 +#define TARGET_VIRT_ADDR_SPACE_BITS 64 + +#include "cpu-all.h" #include "softfloat.h" -#define NB_MMU_MODES 2 +#define NB_MMU_MODES 3 -typedef union FPReg { - struct { -#ifdef WORDS_BIGENDIAN - float32 e; - int32_t __pad; -#else - int32_t __pad; - float32 e; -#endif - }; - float64 d; - uint64_t i; -} FPReg; +#define MMU_MODE0_SUFFIX _primary +#define MMU_MODE1_SUFFIX _secondary +#define MMU_MODE2_SUFFIX _home + +#define MMU_USER_IDX 1 + +#define MAX_EXT_QUEUE 16 + +typedef struct PSW { + uint64_t mask; + uint64_t addr; +} PSW; + +typedef struct ExtQueue { + uint32_t code; + uint32_t param; + uint32_t param64; +} ExtQueue; typedef struct CPUS390XState { uint64_t regs[16]; /* GP registers */ @@ -51,17 +62,42 @@ typedef struct CPUS390XState { uint32_t aregs[16]; /* access registers */ uint32_t fpc; /* floating-point control register */ - FPReg fregs[16]; /* FP registers */ + CPU_DoubleU fregs[16]; /* FP registers */ float_status fpu_status; /* passed to softfloat lib */ - struct { - uint64_t mask; - uint64_t addr; - } psw; + PSW psw; - int cc; /* condition code (0-3) */ + uint32_t cc; + uint32_t cc_op; + uint64_t cc_src; + uint64_t cc_dst; + uint64_t cc_vr; uint64_t __excp_addr; + uint64_t psa; + + uint32_t int_pgm_code; + uint32_t int_pgm_ilc; + + uint32_t int_svc_code; + uint32_t int_svc_ilc; + + uint64_t cregs[16]; /* control registers */ + + int pending_int; + ExtQueue ext_queue[MAX_EXT_QUEUE]; + + /* reset does memset(0) up to here */ + + int ext_index; + int cpu_num; + uint8_t *storage_keys; + + uint64_t tod_offset; + uint64_t tod_basetime; + QEMUTimer *tod_timer; + + QEMUTimer *cpu_timer; CPU_COMMON } CPUS390XState; @@ -69,24 +105,174 @@ typedef struct CPUS390XState { #if defined(CONFIG_USER_ONLY) static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) { - if (newsp) + if (newsp) { env->regs[15] = newsp; + } env->regs[0] = 0; } #endif -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +/* Interrupt Codes */ +/* Program Interrupts */ +#define PGM_OPERATION 0x0001 +#define PGM_PRIVILEGED 0x0002 +#define PGM_EXECUTE 0x0003 +#define PGM_PROTECTION 0x0004 +#define PGM_ADDRESSING 0x0005 +#define PGM_SPECIFICATION 0x0006 +#define PGM_DATA 0x0007 +#define PGM_FIXPT_OVERFLOW 0x0008 +#define PGM_FIXPT_DIVIDE 0x0009 +#define PGM_DEC_OVERFLOW 0x000a +#define PGM_DEC_DIVIDE 0x000b +#define PGM_HFP_EXP_OVERFLOW 0x000c +#define PGM_HFP_EXP_UNDERFLOW 0x000d +#define PGM_HFP_SIGNIFICANCE 0x000e +#define PGM_HFP_DIVIDE 0x000f +#define PGM_SEGMENT_TRANS 0x0010 +#define PGM_PAGE_TRANS 0x0011 +#define PGM_TRANS_SPEC 0x0012 +#define PGM_SPECIAL_OP 0x0013 +#define PGM_OPERAND 0x0015 +#define PGM_TRACE_TABLE 0x0016 +#define PGM_SPACE_SWITCH 0x001c +#define PGM_HFP_SQRT 0x001d +#define PGM_PC_TRANS_SPEC 0x001f +#define PGM_AFX_TRANS 0x0020 +#define PGM_ASX_TRANS 0x0021 +#define PGM_LX_TRANS 0x0022 +#define PGM_EX_TRANS 0x0023 +#define PGM_PRIM_AUTH 0x0024 +#define PGM_SEC_AUTH 0x0025 +#define PGM_ALET_SPEC 0x0028 +#define PGM_ALEN_SPEC 0x0029 +#define PGM_ALE_SEQ 0x002a +#define PGM_ASTE_VALID 0x002b +#define PGM_ASTE_SEQ 0x002c +#define PGM_EXT_AUTH 0x002d +#define PGM_STACK_FULL 0x0030 +#define PGM_STACK_EMPTY 0x0031 +#define PGM_STACK_SPEC 0x0032 +#define PGM_STACK_TYPE 0x0033 +#define PGM_STACK_OP 0x0034 +#define PGM_ASCE_TYPE 0x0038 +#define PGM_REG_FIRST_TRANS 0x0039 +#define PGM_REG_SEC_TRANS 0x003a +#define PGM_REG_THIRD_TRANS 0x003b +#define PGM_MONITOR 0x0040 +#define PGM_PER 0x0080 +#define PGM_CRYPTO 0x0119 + +/* External Interrupts */ +#define EXT_INTERRUPT_KEY 0x0040 +#define EXT_CLOCK_COMP 0x1004 +#define EXT_CPU_TIMER 0x1005 +#define EXT_MALFUNCTION 0x1200 +#define EXT_EMERGENCY 0x1201 +#define EXT_EXTERNAL_CALL 0x1202 +#define EXT_ETR 0x1406 +#define EXT_SERVICE 0x2401 +#define EXT_VIRTIO 0x2603 + +/* PSW defines */ +#undef PSW_MASK_PER +#undef PSW_MASK_DAT +#undef PSW_MASK_IO +#undef PSW_MASK_EXT +#undef PSW_MASK_KEY +#undef PSW_SHIFT_KEY +#undef PSW_MASK_MCHECK +#undef PSW_MASK_WAIT +#undef PSW_MASK_PSTATE +#undef PSW_MASK_ASC +#undef PSW_MASK_CC +#undef PSW_MASK_PM +#undef PSW_MASK_64 + +#define PSW_MASK_PER 0x4000000000000000ULL +#define PSW_MASK_DAT 0x0400000000000000ULL +#define PSW_MASK_IO 0x0200000000000000ULL +#define PSW_MASK_EXT 0x0100000000000000ULL +#define PSW_MASK_KEY 0x00F0000000000000ULL +#define PSW_SHIFT_KEY 56 +#define PSW_MASK_MCHECK 0x0004000000000000ULL +#define PSW_MASK_WAIT 0x0002000000000000ULL +#define PSW_MASK_PSTATE 0x0001000000000000ULL +#define PSW_MASK_ASC 0x0000C00000000000ULL +#define PSW_MASK_CC 0x0000300000000000ULL +#define PSW_MASK_PM 0x00000F0000000000ULL +#define PSW_MASK_64 0x0000000100000000ULL +#define PSW_MASK_32 0x0000000080000000ULL + +#undef PSW_ASC_PRIMARY +#undef PSW_ASC_ACCREG +#undef PSW_ASC_SECONDARY +#undef PSW_ASC_HOME + +#define PSW_ASC_PRIMARY 0x0000000000000000ULL +#define PSW_ASC_ACCREG 0x0000400000000000ULL +#define PSW_ASC_SECONDARY 0x0000800000000000ULL +#define PSW_ASC_HOME 0x0000C00000000000ULL + +/* tb flags */ + +#define FLAG_MASK_PER (PSW_MASK_PER >> 32) +#define FLAG_MASK_DAT (PSW_MASK_DAT >> 32) +#define FLAG_MASK_IO (PSW_MASK_IO >> 32) +#define FLAG_MASK_EXT (PSW_MASK_EXT >> 32) +#define FLAG_MASK_KEY (PSW_MASK_KEY >> 32) +#define FLAG_MASK_MCHECK (PSW_MASK_MCHECK >> 32) +#define FLAG_MASK_WAIT (PSW_MASK_WAIT >> 32) +#define FLAG_MASK_PSTATE (PSW_MASK_PSTATE >> 32) +#define FLAG_MASK_ASC (PSW_MASK_ASC >> 32) +#define FLAG_MASK_CC (PSW_MASK_CC >> 32) +#define FLAG_MASK_PM (PSW_MASK_PM >> 32) +#define FLAG_MASK_64 (PSW_MASK_64 >> 32) +#define FLAG_MASK_32 0x00001000 + static inline int cpu_mmu_index (CPUState *env) { - /* XXX: Currently we don't implement virtual memory */ + if (env->psw.mask & PSW_MASK_PSTATE) { + return 1; + } + return 0; } +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->psw.addr; + *cs_base = 0; + *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) | + ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); +} + +static inline int get_ilc(uint8_t opc) +{ + switch (opc >> 6) { + case 0: + return 1; + case 1: + case 2: + return 2; + case 3: + return 3; + } + + return 0; +} + +#define ILC_LATER 0x20 +#define ILC_LATER_INC 0x21 +#define ILC_LATER_INC_2 0x22 + + CPUS390XState *cpu_s390x_init(const char *cpu_model); +void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); void cpu_s390x_close(CPUS390XState *s); +void do_interrupt (CPUState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero @@ -97,173 +283,673 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw int mmu_idx, int is_softmuu); #define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault -#define TARGET_PAGE_BITS 12 - -/* ??? This is certainly wrong for 64-bit s390x, but given that only KVM - emulation actually works, this is good enough for a placeholder. */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 #ifndef CONFIG_USER_ONLY -int s390_virtio_hypercall(CPUState *env); +int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall); + +void kvm_s390_interrupt(CPUState *env, int type, uint32_t code); void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token); +void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, + uint64_t parm64, int vm); CPUState *s390_cpu_addr2state(uint16_t cpu_addr); + +#ifndef KVM_S390_SIGP_STOP +#define KVM_S390_SIGP_STOP 0 +#define KVM_S390_PROGRAM_INT 0 +#define KVM_S390_SIGP_SET_PREFIX 0 +#define KVM_S390_RESTART 0 +#define KVM_S390_INT_VIRTIO 0 +#define KVM_S390_INT_SERVICE 0 +#define KVM_S390_INT_EMERGENCY 0 #endif +#endif +void cpu_lock(void); +void cpu_unlock(void); + +static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) +{ + env->aregs[0] = newtls >> 32; + env->aregs[1] = newtls & 0xffffffffULL; +} #define cpu_init cpu_s390x_init #define cpu_exec cpu_s390x_exec #define cpu_gen_code cpu_s390x_gen_code +#define cpu_signal_handler cpu_s390x_signal_handler -#include "cpu-all.h" +#include "exec-all.h" + +#ifdef CONFIG_USER_ONLY #define EXCP_OPEX 1 /* operation exception (sigill) */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ +#define EXCP_SPEC 6 /* specification exception */ -static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, - target_ulong *cs_base, int *flags) +#else + +#define EXCP_EXT 1 /* external interrupt */ +#define EXCP_SVC 2 /* supervisor call (syscall) */ +#define EXCP_PGM 3 /* program interruption */ + +#endif /* CONFIG_USER_ONLY */ + +#define INTERRUPT_EXT (1 << 0) +#define INTERRUPT_TOD (1 << 1) +#define INTERRUPT_CPUTIMER (1 << 2) + +/* Program Status Word. */ +#define S390_PSWM_REGNUM 0 +#define S390_PSWA_REGNUM 1 +/* General Purpose Registers. */ +#define S390_R0_REGNUM 2 +#define S390_R1_REGNUM 3 +#define S390_R2_REGNUM 4 +#define S390_R3_REGNUM 5 +#define S390_R4_REGNUM 6 +#define S390_R5_REGNUM 7 +#define S390_R6_REGNUM 8 +#define S390_R7_REGNUM 9 +#define S390_R8_REGNUM 10 +#define S390_R9_REGNUM 11 +#define S390_R10_REGNUM 12 +#define S390_R11_REGNUM 13 +#define S390_R12_REGNUM 14 +#define S390_R13_REGNUM 15 +#define S390_R14_REGNUM 16 +#define S390_R15_REGNUM 17 +/* Access Registers. */ +#define S390_A0_REGNUM 18 +#define S390_A1_REGNUM 19 +#define S390_A2_REGNUM 20 +#define S390_A3_REGNUM 21 +#define S390_A4_REGNUM 22 +#define S390_A5_REGNUM 23 +#define S390_A6_REGNUM 24 +#define S390_A7_REGNUM 25 +#define S390_A8_REGNUM 26 +#define S390_A9_REGNUM 27 +#define S390_A10_REGNUM 28 +#define S390_A11_REGNUM 29 +#define S390_A12_REGNUM 30 +#define S390_A13_REGNUM 31 +#define S390_A14_REGNUM 32 +#define S390_A15_REGNUM 33 +/* Floating Point Control Word. */ +#define S390_FPC_REGNUM 34 +/* Floating Point Registers. */ +#define S390_F0_REGNUM 35 +#define S390_F1_REGNUM 36 +#define S390_F2_REGNUM 37 +#define S390_F3_REGNUM 38 +#define S390_F4_REGNUM 39 +#define S390_F5_REGNUM 40 +#define S390_F6_REGNUM 41 +#define S390_F7_REGNUM 42 +#define S390_F8_REGNUM 43 +#define S390_F9_REGNUM 44 +#define S390_F10_REGNUM 45 +#define S390_F11_REGNUM 46 +#define S390_F12_REGNUM 47 +#define S390_F13_REGNUM 48 +#define S390_F14_REGNUM 49 +#define S390_F15_REGNUM 50 +/* Total. */ +#define S390_NUM_REGS 51 + +/* Pseudo registers -- PC and condition code. */ +#define S390_PC_REGNUM S390_NUM_REGS +#define S390_CC_REGNUM (S390_NUM_REGS+1) +#define S390_NUM_PSEUDO_REGS 2 +#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) + + + +/* Program Status Word. */ +#define S390_PSWM_REGNUM 0 +#define S390_PSWA_REGNUM 1 +/* General Purpose Registers. */ +#define S390_R0_REGNUM 2 +#define S390_R1_REGNUM 3 +#define S390_R2_REGNUM 4 +#define S390_R3_REGNUM 5 +#define S390_R4_REGNUM 6 +#define S390_R5_REGNUM 7 +#define S390_R6_REGNUM 8 +#define S390_R7_REGNUM 9 +#define S390_R8_REGNUM 10 +#define S390_R9_REGNUM 11 +#define S390_R10_REGNUM 12 +#define S390_R11_REGNUM 13 +#define S390_R12_REGNUM 14 +#define S390_R13_REGNUM 15 +#define S390_R14_REGNUM 16 +#define S390_R15_REGNUM 17 +/* Access Registers. */ +#define S390_A0_REGNUM 18 +#define S390_A1_REGNUM 19 +#define S390_A2_REGNUM 20 +#define S390_A3_REGNUM 21 +#define S390_A4_REGNUM 22 +#define S390_A5_REGNUM 23 +#define S390_A6_REGNUM 24 +#define S390_A7_REGNUM 25 +#define S390_A8_REGNUM 26 +#define S390_A9_REGNUM 27 +#define S390_A10_REGNUM 28 +#define S390_A11_REGNUM 29 +#define S390_A12_REGNUM 30 +#define S390_A13_REGNUM 31 +#define S390_A14_REGNUM 32 +#define S390_A15_REGNUM 33 +/* Floating Point Control Word. */ +#define S390_FPC_REGNUM 34 +/* Floating Point Registers. */ +#define S390_F0_REGNUM 35 +#define S390_F1_REGNUM 36 +#define S390_F2_REGNUM 37 +#define S390_F3_REGNUM 38 +#define S390_F4_REGNUM 39 +#define S390_F5_REGNUM 40 +#define S390_F6_REGNUM 41 +#define S390_F7_REGNUM 42 +#define S390_F8_REGNUM 43 +#define S390_F9_REGNUM 44 +#define S390_F10_REGNUM 45 +#define S390_F11_REGNUM 46 +#define S390_F12_REGNUM 47 +#define S390_F13_REGNUM 48 +#define S390_F14_REGNUM 49 +#define S390_F15_REGNUM 50 +/* Total. */ +#define S390_NUM_REGS 51 + +/* Pseudo registers -- PC and condition code. */ +#define S390_PC_REGNUM S390_NUM_REGS +#define S390_CC_REGNUM (S390_NUM_REGS+1) +#define S390_NUM_PSEUDO_REGS 2 +#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) + +/* CC optimization */ + +enum cc_op { + CC_OP_CONST0 = 0, /* CC is 0 */ + CC_OP_CONST1, /* CC is 1 */ + CC_OP_CONST2, /* CC is 2 */ + CC_OP_CONST3, /* CC is 3 */ + + CC_OP_DYNAMIC, /* CC calculation defined by env->cc_op */ + CC_OP_STATIC, /* CC value is env->cc_op */ + + CC_OP_NZ, /* env->cc_dst != 0 */ + CC_OP_LTGT_32, /* signed less/greater than (32bit) */ + CC_OP_LTGT_64, /* signed less/greater than (64bit) */ + CC_OP_LTUGTU_32, /* unsigned less/greater than (32bit) */ + CC_OP_LTUGTU_64, /* unsigned less/greater than (64bit) */ + CC_OP_LTGT0_32, /* signed less/greater than 0 (32bit) */ + CC_OP_LTGT0_64, /* signed less/greater than 0 (64bit) */ + + CC_OP_ADD_64, /* overflow on add (64bit) */ + CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_SUB_64, /* overflow on substraction (64bit) */ + CC_OP_SUBU_64, /* overflow on unsigned substraction (64bit) */ + CC_OP_ABS_64, /* sign eval on abs (64bit) */ + CC_OP_NABS_64, /* sign eval on nabs (64bit) */ + + CC_OP_ADD_32, /* overflow on add (32bit) */ + CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_SUB_32, /* overflow on substraction (32bit) */ + CC_OP_SUBU_32, /* overflow on unsigned substraction (32bit) */ + CC_OP_ABS_32, /* sign eval on abs (64bit) */ + CC_OP_NABS_32, /* sign eval on nabs (64bit) */ + + CC_OP_COMP_32, /* complement */ + CC_OP_COMP_64, /* complement */ + + CC_OP_TM_32, /* test under mask (32bit) */ + CC_OP_TM_64, /* test under mask (64bit) */ + + CC_OP_LTGT_F32, /* FP compare (32bit) */ + CC_OP_LTGT_F64, /* FP compare (64bit) */ + + CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ + CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + + CC_OP_ICM, /* insert characters under mask */ + CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_MAX +}; + +static const char *cc_names[] = { + [CC_OP_CONST0] = "CC_OP_CONST0", + [CC_OP_CONST1] = "CC_OP_CONST1", + [CC_OP_CONST2] = "CC_OP_CONST2", + [CC_OP_CONST3] = "CC_OP_CONST3", + [CC_OP_DYNAMIC] = "CC_OP_DYNAMIC", + [CC_OP_STATIC] = "CC_OP_STATIC", + [CC_OP_NZ] = "CC_OP_NZ", + [CC_OP_LTGT_32] = "CC_OP_LTGT_32", + [CC_OP_LTGT_64] = "CC_OP_LTGT_64", + [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32", + [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64", + [CC_OP_LTGT0_32] = "CC_OP_LTGT0_32", + [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", + [CC_OP_ADD_64] = "CC_OP_ADD_64", + [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_SUB_64] = "CC_OP_SUB_64", + [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_ABS_64] = "CC_OP_ABS_64", + [CC_OP_NABS_64] = "CC_OP_NABS_64", + [CC_OP_ADD_32] = "CC_OP_ADD_32", + [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_SUB_32] = "CC_OP_SUB_32", + [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_ABS_32] = "CC_OP_ABS_32", + [CC_OP_NABS_32] = "CC_OP_NABS_32", + [CC_OP_COMP_32] = "CC_OP_COMP_32", + [CC_OP_COMP_64] = "CC_OP_COMP_64", + [CC_OP_TM_32] = "CC_OP_TM_32", + [CC_OP_TM_64] = "CC_OP_TM_64", + [CC_OP_LTGT_F32] = "CC_OP_LTGT_F32", + [CC_OP_LTGT_F64] = "CC_OP_LTGT_F64", + [CC_OP_NZ_F32] = "CC_OP_NZ_F32", + [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_ICM] = "CC_OP_ICM", + [CC_OP_SLAG] = "CC_OP_SLAG", +}; + +static inline const char *cc_name(int cc_op) { - *pc = env->psw.addr; - /* XXX this is correct for user-mode emulation, but needs - * the asce register information as well when softmmu - * is implemented in the future */ - *cs_base = 0; - *flags = env->psw.mask; + return cc_names[cc_op]; } -/* Program Status Word. */ -#define S390_PSWM_REGNUM 0 -#define S390_PSWA_REGNUM 1 -/* General Purpose Registers. */ -#define S390_R0_REGNUM 2 -#define S390_R1_REGNUM 3 -#define S390_R2_REGNUM 4 -#define S390_R3_REGNUM 5 -#define S390_R4_REGNUM 6 -#define S390_R5_REGNUM 7 -#define S390_R6_REGNUM 8 -#define S390_R7_REGNUM 9 -#define S390_R8_REGNUM 10 -#define S390_R9_REGNUM 11 -#define S390_R10_REGNUM 12 -#define S390_R11_REGNUM 13 -#define S390_R12_REGNUM 14 -#define S390_R13_REGNUM 15 -#define S390_R14_REGNUM 16 -#define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 +/* SCLP PV interface defines */ +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) +#define SCP_LENGTH 0x00 +#define SCP_FUNCTION_CODE 0x02 +#define SCP_CONTROL_MASK 0x03 +#define SCP_RESPONSE_CODE 0x06 +#define SCP_MEM_CODE 0x08 +#define SCP_INCREMENT 0x0a + +typedef struct LowCore +{ + /* prefix area: defined by architecture */ + uint32_t ccw1[2]; /* 0x000 */ + uint32_t ccw2[4]; /* 0x008 */ + uint8_t pad1[0x80-0x18]; /* 0x018 */ + uint32_t ext_params; /* 0x080 */ + uint16_t cpu_addr; /* 0x084 */ + uint16_t ext_int_code; /* 0x086 */ + uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_code; /* 0x08a */ + uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_code; /* 0x08e */ + uint32_t data_exc_code; /* 0x090 */ + uint16_t mon_class_num; /* 0x094 */ + uint16_t per_perc_atmid; /* 0x096 */ + uint64_t per_address; /* 0x098 */ + uint8_t exc_access_id; /* 0x0a0 */ + uint8_t per_access_id; /* 0x0a1 */ + uint8_t op_access_id; /* 0x0a2 */ + uint8_t ar_access_id; /* 0x0a3 */ + uint8_t pad2[0xA8-0xA4]; /* 0x0a4 */ + uint64_t trans_exc_code; /* 0x0a8 */ + uint64_t monitor_code; /* 0x0b0 */ + uint16_t subchannel_id; /* 0x0b8 */ + uint16_t subchannel_nr; /* 0x0ba */ + uint32_t io_int_parm; /* 0x0bc */ + uint32_t io_int_word; /* 0x0c0 */ + uint8_t pad3[0xc8-0xc4]; /* 0x0c4 */ + uint32_t stfl_fac_list; /* 0x0c8 */ + uint8_t pad4[0xe8-0xcc]; /* 0x0cc */ + uint32_t mcck_interruption_code[2]; /* 0x0e8 */ + uint8_t pad5[0xf4-0xf0]; /* 0x0f0 */ + uint32_t external_damage_code; /* 0x0f4 */ + uint64_t failing_storage_address; /* 0x0f8 */ + uint8_t pad6[0x120-0x100]; /* 0x100 */ + PSW restart_old_psw; /* 0x120 */ + PSW external_old_psw; /* 0x130 */ + PSW svc_old_psw; /* 0x140 */ + PSW program_old_psw; /* 0x150 */ + PSW mcck_old_psw; /* 0x160 */ + PSW io_old_psw; /* 0x170 */ + uint8_t pad7[0x1a0-0x180]; /* 0x180 */ + PSW restart_psw; /* 0x1a0 */ + PSW external_new_psw; /* 0x1b0 */ + PSW svc_new_psw; /* 0x1c0 */ + PSW program_new_psw; /* 0x1d0 */ + PSW mcck_new_psw; /* 0x1e0 */ + PSW io_new_psw; /* 0x1f0 */ + PSW return_psw; /* 0x200 */ + uint8_t irb[64]; /* 0x210 */ + uint64_t sync_enter_timer; /* 0x250 */ + uint64_t async_enter_timer; /* 0x258 */ + uint64_t exit_timer; /* 0x260 */ + uint64_t last_update_timer; /* 0x268 */ + uint64_t user_timer; /* 0x270 */ + uint64_t system_timer; /* 0x278 */ + uint64_t last_update_clock; /* 0x280 */ + uint64_t steal_clock; /* 0x288 */ + PSW return_mcck_psw; /* 0x290 */ + uint8_t pad8[0xc00-0x2a0]; /* 0x2a0 */ + /* System info area */ + uint64_t save_area[16]; /* 0xc00 */ + uint8_t pad9[0xd40-0xc80]; /* 0xc80 */ + uint64_t kernel_stack; /* 0xd40 */ + uint64_t thread_info; /* 0xd48 */ + uint64_t async_stack; /* 0xd50 */ + uint64_t kernel_asce; /* 0xd58 */ + uint64_t user_asce; /* 0xd60 */ + uint64_t panic_stack; /* 0xd68 */ + uint64_t user_exec_asce; /* 0xd70 */ + uint8_t pad10[0xdc0-0xd78]; /* 0xd78 */ + + /* SMP info area: defined by DJB */ + uint64_t clock_comparator; /* 0xdc0 */ + uint64_t ext_call_fast; /* 0xdc8 */ + uint64_t percpu_offset; /* 0xdd0 */ + uint64_t current_task; /* 0xdd8 */ + uint32_t softirq_pending; /* 0xde0 */ + uint32_t pad_0x0de4; /* 0xde4 */ + uint64_t int_clock; /* 0xde8 */ + uint8_t pad12[0xe00-0xdf0]; /* 0xdf0 */ + + /* 0xe00 is used as indicator for dump tools */ + /* whether the kernel died with panic() or not */ + uint32_t panic_magic; /* 0xe00 */ + + uint8_t pad13[0x11b8-0xe04]; /* 0xe04 */ + + /* 64 bit extparam used for pfault, diag 250 etc */ + uint64_t ext_params2; /* 0x11B8 */ + + uint8_t pad14[0x1200-0x11C0]; /* 0x11C0 */ + + /* System info area */ + + uint64_t floating_pt_save_area[16]; /* 0x1200 */ + uint64_t gpregs_save_area[16]; /* 0x1280 */ + uint32_t st_status_fixed_logout[4]; /* 0x1300 */ + uint8_t pad15[0x1318-0x1310]; /* 0x1310 */ + uint32_t prefixreg_save_area; /* 0x1318 */ + uint32_t fpt_creg_save_area; /* 0x131c */ + uint8_t pad16[0x1324-0x1320]; /* 0x1320 */ + uint32_t tod_progreg_save_area; /* 0x1324 */ + uint32_t cpu_timer_save_area[2]; /* 0x1328 */ + uint32_t clock_comp_save_area[2]; /* 0x1330 */ + uint8_t pad17[0x1340-0x1338]; /* 0x1338 */ + uint32_t access_regs_save_area[16]; /* 0x1340 */ + uint64_t cregs_save_area[16]; /* 0x1380 */ + + /* align to the top of the prefix area */ + + uint8_t pad18[0x2000-0x1400]; /* 0x1400 */ +} __attribute__((packed)) LowCore; + +/* STSI */ +#define STSI_LEVEL_MASK 0x00000000f0000000ULL +#define STSI_LEVEL_CURRENT 0x0000000000000000ULL +#define STSI_LEVEL_1 0x0000000010000000ULL +#define STSI_LEVEL_2 0x0000000020000000ULL +#define STSI_LEVEL_3 0x0000000030000000ULL +#define STSI_R0_RESERVED_MASK 0x000000000fffff00ULL +#define STSI_R0_SEL1_MASK 0x00000000000000ffULL +#define STSI_R1_RESERVED_MASK 0x00000000ffff0000ULL +#define STSI_R1_SEL2_MASK 0x000000000000ffffULL + +/* Basic Machine Configuration */ +struct sysib_111 { + uint32_t res1[8]; + uint8_t manuf[16]; + uint8_t type[4]; + uint8_t res2[12]; + uint8_t model[16]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint8_t res3[156]; +}; + +/* Basic Machine CPU */ +struct sysib_121 { + uint32_t res1[80]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint8_t res2[2]; + uint16_t cpu_addr; + uint8_t res3[152]; +}; + +/* Basic Machine CPUs */ +struct sysib_122 { + uint8_t res1[32]; + uint32_t capability; + uint16_t total_cpus; + uint16_t active_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint16_t adjustments[2026]; +}; + +/* LPAR CPU */ +struct sysib_221 { + uint32_t res1[80]; + uint8_t sequence[16]; + uint8_t plant[4]; + uint16_t cpu_id; + uint16_t cpu_addr; + uint8_t res3[152]; +}; + +/* LPAR CPUs */ +struct sysib_222 { + uint32_t res1[32]; + uint16_t lpar_num; + uint8_t res2; + uint8_t lcpuc; + uint16_t total_cpus; + uint16_t conf_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint8_t name[8]; + uint32_t caf; + uint8_t res3[16]; + uint16_t dedicated_cpus; + uint16_t shared_cpus; + uint8_t res4[180]; +}; + +/* VM CPUs */ +struct sysib_322 { + uint8_t res1[31]; + uint8_t count; + struct { + uint8_t res2[4]; + uint16_t total_cpus; + uint16_t conf_cpus; + uint16_t standby_cpus; + uint16_t reserved_cpus; + uint8_t name[8]; + uint32_t caf; + uint8_t cpi[16]; + uint8_t res3[24]; + } vm[8]; + uint8_t res4[3552]; +}; + +/* MMU defines */ +#define _ASCE_ORIGIN ~0xfffULL /* segment table origin */ +#define _ASCE_SUBSPACE 0x200 /* subspace group control */ +#define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ +#define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ +#define _ASCE_SPACE_SWITCH 0x40 /* space switch event */ +#define _ASCE_REAL_SPACE 0x20 /* real space control */ +#define _ASCE_TYPE_MASK 0x0c /* asce table type mask */ +#define _ASCE_TYPE_REGION1 0x0c /* region first table type */ +#define _ASCE_TYPE_REGION2 0x08 /* region second table type */ +#define _ASCE_TYPE_REGION3 0x04 /* region third table type */ +#define _ASCE_TYPE_SEGMENT 0x00 /* segment table type */ +#define _ASCE_TABLE_LENGTH 0x03 /* region table length */ + +#define _REGION_ENTRY_ORIGIN ~0xfffULL /* region/segment table origin */ +#define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ +#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ +#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ +#define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */ +#define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */ +#define _REGION_ENTRY_LENGTH 0x03 /* region third length */ + +#define _SEGMENT_ENTRY_ORIGIN ~0x7ffULL /* segment table origin */ +#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ +#define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ + +#define _PAGE_RO 0x200 /* HW read-only bit */ +#define _PAGE_INVALID 0x400 /* HW invalid bit */ -/* Program Status Word. */ -#define S390_PSWM_REGNUM 0 -#define S390_PSWA_REGNUM 1 -/* General Purpose Registers. */ -#define S390_R0_REGNUM 2 -#define S390_R1_REGNUM 3 -#define S390_R2_REGNUM 4 -#define S390_R3_REGNUM 5 -#define S390_R4_REGNUM 6 -#define S390_R5_REGNUM 7 -#define S390_R6_REGNUM 8 -#define S390_R7_REGNUM 9 -#define S390_R8_REGNUM 10 -#define S390_R9_REGNUM 11 -#define S390_R10_REGNUM 12 -#define S390_R11_REGNUM 13 -#define S390_R12_REGNUM 14 -#define S390_R13_REGNUM 15 -#define S390_R14_REGNUM 16 -#define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 +/* EBCDIC handling */ +static const uint8_t ebcdic2ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, +}; -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) +static const uint8_t ascii2ebcdic [] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; +static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) +{ + int i; + + for (i = 0; i < len; i++) { + p[i] = ascii2ebcdic[(int)ascii[i]]; + } +} + +#define SIGP_SENSE 0x01 +#define SIGP_EXTERNAL_CALL 0x02 +#define SIGP_EMERGENCY 0x03 +#define SIGP_START 0x04 +#define SIGP_STOP 0x05 +#define SIGP_RESTART 0x06 +#define SIGP_STOP_STORE_STATUS 0x09 +#define SIGP_INITIAL_CPU_RESET 0x0b +#define SIGP_CPU_RESET 0x0c +#define SIGP_SET_PREFIX 0x0d +#define SIGP_STORE_STATUS_ADDR 0x0e +#define SIGP_SET_ARCH 0x12 + +/* cpu status bits */ +#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL +#define SIGP_STAT_INCORRECT_STATE 0x00000200UL +#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL +#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL +#define SIGP_STAT_STOPPED 0x00000040UL +#define SIGP_STAT_OPERATOR_INTERV 0x00000020UL +#define SIGP_STAT_CHECK_STOP 0x00000010UL +#define SIGP_STAT_INOPERATIVE 0x00000004UL +#define SIGP_STAT_INVALID_ORDER 0x00000002UL +#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL + +void load_psw(CPUState *env, uint64_t mask, uint64_t addr); +int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc, + target_ulong *raddr, int *flags); +int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code); +uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr); + +#define TARGET_HAS_ICE 1 + +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + +/* Converts ns to s390's clock format */ +static inline uint64_t time2tod(uint64_t ns) { + return (ns << 9) / 125; +} + +static inline void cpu_inject_ext(CPUState *env, uint32_t code, uint32_t param, + uint64_t param64) +{ + if (env->ext_index == MAX_EXT_QUEUE - 1) { + /* ugh - can't queue anymore. Let's drop. */ + return; + } + + env->ext_index++; + assert(env->ext_index < MAX_EXT_QUEUE); + + env->ext_queue[env->ext_index].code = code; + env->ext_queue[env->ext_index].param = param; + env->ext_queue[env->ext_index].param64 = param64; + + env->pending_int |= INTERRUPT_EXT; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} #endif diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index ae7dc561b3..2643460722 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -182,8 +182,8 @@ int kvm_arch_process_async_events(CPUState *env) return 0; } -static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, - uint64_t parm64, int vm) +void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, + uint64_t parm64, int vm) { struct kvm_s390_interrupt kvmint; int r; @@ -218,7 +218,7 @@ void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token) token, 1); } -static void kvm_s390_interrupt(CPUState *env, int type, uint32_t code) +void kvm_s390_interrupt(CPUState *env, int type, uint32_t code) { kvm_s390_interrupt_internal(env, type, code, 0, 0); } @@ -237,7 +237,8 @@ static void setcc(CPUState *env, uint64_t cc) env->psw.mask |= (cc & 3) << 44; } -static int sclp_service_call(CPUState *env, struct kvm_run *run, uint16_t ipbh0) +static int kvm_sclp_service_call(CPUState *env, struct kvm_run *run, + uint16_t ipbh0) { uint32_t sccb; uint64_t code; @@ -287,7 +288,7 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1) dprintf("KVM: PRIV: %d\n", ipa1); switch (ipa1) { case PRIV_SCLP_CALL: - r = sclp_service_call(env, run, ipbh0); + r = kvm_sclp_service_call(env, run, ipbh0); break; default: dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); @@ -300,12 +301,10 @@ static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1) static int handle_hypercall(CPUState *env, struct kvm_run *run) { - int r; - cpu_synchronize_state(env); - r = s390_virtio_hypercall(env); + env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]); - return r; + return 0; } static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d33bfb1f31..2cb893f219 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, } } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i); + cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { From 3110e2925489c571901e945e315942ce84fe696f Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Fri, 15 Apr 2011 17:32:48 +0200 Subject: [PATCH 233/386] s390x: Enable s390x-softmmu target This patch adds some code paths for running s390x guest OSs without the need for KVM. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- cpu-exec.c | 8 ++++++++ target-s390x/exec.h | 11 ++++++++++- target-s390x/helper.c | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 5d6c9a8a1c..d57afef642 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -346,6 +346,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_M68K) do_interrupt(0); +#elif defined(TARGET_S390X) + do_interrupt(env); #endif env->exception_index = -1; #endif @@ -560,6 +562,12 @@ int cpu_exec(CPUState *env1) do_interrupt(1); next_tb = 0; } +#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->psw.mask & PSW_MASK_EXT)) { + do_interrupt(env); + next_tb = 0; + } #endif /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ diff --git a/target-s390x/exec.h b/target-s390x/exec.h index f7893f3877..7a87fffca6 100644 --- a/target-s390x/exec.h +++ b/target-s390x/exec.h @@ -31,7 +31,16 @@ register struct CPUS390XState *env asm(AREG0); static inline int cpu_has_work(CPUState *env) { - return env->interrupt_request & CPU_INTERRUPT_HARD; // guess + return ((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->psw.mask & PSW_MASK_EXT)); +} + +static inline void regs_to_env(void) +{ +} + +static inline void env_to_regs(void) +{ } static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 4a5297be18..629dfd9708 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -82,3 +82,7 @@ int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 0; } #endif /* CONFIG_USER_ONLY */ + +void do_interrupt (CPUState *env) +{ +} From 8103b4d161d7c00ea3ff89ffe66bb2bc2c67de5d Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Fri, 15 Apr 2011 17:32:49 +0200 Subject: [PATCH 234/386] s390x: Dispatch interrupts to KVM or the real CPU The KVM interrupt injection path is non-generic for now. So we need to push knowledge of how to inject a device interrupt using KVM into the actual device code. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/s390-virtio-bus.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 175e5cb3a0..bb49e393ec 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -43,6 +43,8 @@ do { } while (0) #endif +#define VIRTIO_EXT_CODE 0x2603 + struct BusInfo s390_virtio_bus_info = { .name = "s390-virtio", .size = sizeof(VirtIOS390Bus), @@ -305,9 +307,13 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) { VirtIOS390Device *dev = (VirtIOS390Device*)opaque; uint64_t token = s390_virtio_device_vq_token(dev, vector); + CPUState *env = s390_cpu_addr2state(0); - /* XXX kvm dependency! */ - kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token); + if (kvm_enabled()) { + kvm_s390_virtio_irq(env, 0, token); + } else { + cpu_inject_ext(env, VIRTIO_EXT_CODE, 0, token); + } } static unsigned virtio_s390_get_features(void *opaque) From 8d5192ee15bc519f83741f5e413ebba5d57a6abd Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Fri, 15 Apr 2011 17:32:50 +0200 Subject: [PATCH 235/386] s390x: virtio machine storage keys For emulation (and migration) we need to know about the guest's storage keys. These are separate from actual RAM contents, so we need to allocate them in parallel to RAM. While touching the file, this patch also adjusts the hypercall function to a new syntax that aligns better with tcg emulated code. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/s390-virtio.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 48fb0d05c2..698ff6f345 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -82,13 +82,12 @@ CPUState *s390_cpu_addr2state(uint16_t cpu_addr) return ipi_states[cpu_addr]; } -int s390_virtio_hypercall(CPUState *env, uint64_t mem_, uint64_t hypercall) +int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall) { int r = 0, i; - target_ulong mem = env->regs[2]; - dprintf("KVM hypercall: %ld\n", env->regs[1]); - switch (env->regs[1]) { + dprintf("KVM hypercall: %ld\n", hypercall); + switch (hypercall) { case KVM_S390_VIRTIO_NOTIFY: if (mem > ram_size) { VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, @@ -128,8 +127,7 @@ int s390_virtio_hypercall(CPUState *env, uint64_t mem_, uint64_t hypercall) break; } - env->regs[2] = r; - return 0; + return r; } /* PC hardware initialisation */ @@ -145,14 +143,9 @@ static void s390_init(ram_addr_t ram_size, ram_addr_t kernel_size = 0; ram_addr_t initrd_offset; ram_addr_t initrd_size = 0; + uint8_t *storage_keys; int i; - /* XXX we only work on KVM for now */ - - if (!kvm_enabled()) { - fprintf(stderr, "The S390 target only works with KVM enabled\n"); - exit(1); - } /* get a BUS */ s390_bus = s390_virtio_bus_init(&ram_size); @@ -161,6 +154,9 @@ static void s390_init(ram_addr_t ram_size, ram_addr = qemu_ram_alloc(NULL, "s390.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_addr); + /* allocate storage keys */ + storage_keys = qemu_mallocz(ram_size / TARGET_PAGE_SIZE); + /* init CPUs */ if (cpu_model == NULL) { cpu_model = "host"; @@ -178,6 +174,7 @@ static void s390_init(ram_addr_t ram_size, ipi_states[i] = tmp_env; tmp_env->halted = 1; tmp_env->exception_index = EXCP_HLT; + tmp_env->storage_keys = storage_keys; } env->halted = 0; From e87b7cb0f0e04d7c4510564530ab00ed4db37a45 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Mon, 18 Apr 2011 06:39:52 +0000 Subject: [PATCH 236/386] Remove unused function parameters from gen_pc_load and rename the function Function gen_pc_load was introduced in commit d2856f1ad4c259e5766847c49acbb4e390731bd4. The only reason for parameter searched_pc was a debug statement in target-i386/translate.c. Parameter puc was needed by target-sparc until commit d7da2a10402f1644128b66414ca8f86bdea9ae7c. Remove searched_pc from the debug statement and remove both parameters from the parameter list of gen_pc_load. As the function name gen_pc_load was also misleading, it is now called restore_state_to_opc. This new name was suggested by Peter Maydell, thanks. v2: Remove last parameter, too, and rename the function. v3: Fix [] typo in target-arm/translate.c. Fix wrong SHA1 object name in commit message (copy+paste error). Cc: Aurelien Jarno <aurelien@aurel32.net> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- exec-all.h | 4 ++-- target-alpha/translate.c | 3 +-- target-arm/translate.c | 7 +++---- target-cris/translate.c | 3 +-- target-i386/translate.c | 7 +++---- target-lm32/translate.c | 3 +-- target-m68k/translate.c | 3 +-- target-microblaze/translate.c | 3 +-- target-mips/translate.c | 3 +-- target-ppc/translate.c | 3 +-- target-s390x/translate.c | 3 +-- target-sh4/translate.c | 3 +-- target-sparc/translate.c | 3 +-- target-unicore32/translate.c | 3 +-- translate-all.c | 2 +- 15 files changed, 20 insertions(+), 33 deletions(-) diff --git a/exec-all.h b/exec-all.h index 496c001c03..29fd322347 100644 --- a/exec-all.h +++ b/exec-all.h @@ -77,8 +77,8 @@ extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc); +void restore_state_to_opc(CPUState *env, struct TranslationBlock *tb, + int pc_pos); void cpu_gen_init(void); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 96e922b569..456ba51ac6 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3367,8 +3367,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) return env; } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-arm/translate.c b/target-arm/translate.c index fc9ff8d9e8..e1bda57e81 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9551,8 +9551,8 @@ static inline void gen_intermediate_code_internal(CPUState *env, * This is handled in the same way as restoration of the * PC in these situations: we will be called again with search_pc=1 * and generate a mapping of the condexec bits for each PC in - * gen_opc_condexec_bits[]. gen_pc_load[] then uses this to restore - * the condexec bits. + * gen_opc_condexec_bits[]. restore_state_to_opc() then uses + * this to restore the condexec bits. * * Note that there are no instructions which can read the condexec * bits, and none which can write non-static values to them, so @@ -9817,8 +9817,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, #endif } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->regs[15] = gen_opc_pc[pc_pos]; env->condexec_bits = gen_opc_condexec_bits[pc_pos]; diff --git a/target-cris/translate.c b/target-cris/translate.c index 1c03fa5fb6..e2607d64c0 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3604,8 +3604,7 @@ void cpu_reset (CPUCRISState *env) #endif } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-i386/translate.c b/target-i386/translate.c index 7d1340ed01..199302e517 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7890,8 +7890,7 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { int cc_op; #ifdef DEBUG_DISAS @@ -7903,8 +7902,8 @@ void gen_pc_load(CPUState *env, TranslationBlock *tb, qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); } } - qemu_log("spc=0x%08lx pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", - searched_pc, pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, + qemu_log("pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", + pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, (uint32_t)tb->cs_base); } #endif diff --git a/target-lm32/translate.c b/target-lm32/translate.c index efc9b5a856..51b4f5a814 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -1212,8 +1212,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n\n"); } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 038c0af3ef..9e5578d455 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3113,8 +3113,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index bff3a11bc8..b47b92e909 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1940,8 +1940,7 @@ void cpu_reset (CPUState *env) #endif } -void gen_pc_load(CPUState *env, struct TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->sregs[SR_PC] = gen_opc_pc[pc_pos]; } diff --git a/target-mips/translate.c b/target-mips/translate.c index 953c528068..4eaa8261c3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12737,8 +12737,7 @@ void cpu_reset (CPUMIPSState *env) env->exception_index = EXCP_NONE; } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->active_tc.PC = gen_opc_pc[pc_pos]; env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3c3ee24c95..a943dbcf8e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9367,8 +9367,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->nip = gen_opc_pc[pc_pos]; } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2cb893f219..4d45e32616 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -54,8 +54,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->psw.addr = gen_opc_pc[pc_pos]; } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 88098d7c23..93c863650d 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -2069,8 +2069,7 @@ void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; env->flags = gen_opc_hflags[pc_pos]; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 883ecd2d2f..3c958b26d6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -5080,8 +5080,7 @@ void gen_intermediate_code_init(CPUSPARCState *env) } } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { target_ulong npc; env->pc = gen_opc_pc[pc_pos]; diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index a6ba991e92..98eaeb3d43 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -2098,8 +2098,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, #endif } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->regs[31] = gen_opc_pc[pc_pos]; } diff --git a/translate-all.c b/translate-all.c index efcfb9adcd..97668b2c8e 100644 --- a/translate-all.c +++ b/translate-all.c @@ -157,7 +157,7 @@ int cpu_restore_state(TranslationBlock *tb, j--; env->icount_decr.u16.low -= gen_opc_icount[j]; - gen_pc_load(env, tb, searched_pc, j, puc); + restore_state_to_opc(env, tb, j); #ifdef CONFIG_PROFILER s->restore_time += profile_getclock() - ti; From 618ba8e6a1313df6a8366ac8ffee47e3f885ac90 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Mon, 18 Apr 2011 06:39:53 +0000 Subject: [PATCH 237/386] Remove unused function parameter from cpu_restore_state The previous patch removed the need for parameter puc. Is is now unused, so remove it. Cc: Aurelien Jarno <aurelien@aurel32.net> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- cpu-exec.c | 2 +- exec-all.h | 3 +-- exec.c | 9 ++++----- target-alpha/op_helper.c | 2 +- target-arm/op_helper.c | 2 +- target-cris/op_helper.c | 2 +- target-i386/op_helper.c | 2 +- target-lm32/op_helper.c | 2 +- target-m68k/op_helper.c | 2 +- target-microblaze/op_helper.c | 2 +- target-mips/op_helper.c | 4 ++-- target-ppc/op_helper.c | 2 +- target-s390x/op_helper.c | 2 +- target-sh4/op_helper.c | 2 +- target-sparc/op_helper.c | 2 +- translate-all.c | 3 +-- 16 files changed, 20 insertions(+), 23 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d57afef642..395cd8cf90 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -808,7 +808,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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); + cpu_restore_state(tb, env, pc); } /* we restore the process signal mask as the sigreturn should diff --git a/exec-all.h b/exec-all.h index 29fd322347..7c2d29ff98 100644 --- a/exec-all.h +++ b/exec-all.h @@ -84,8 +84,7 @@ void cpu_gen_init(void); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, - CPUState *env, unsigned long searched_pc, - void *puc); + CPUState *env, unsigned long searched_pc); void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_io_recompile(CPUState *env, void *retaddr); TranslationBlock *tb_gen_code(CPUState *env, diff --git a/exec.c b/exec.c index b1ee52a4d0..c3dc68ae09 100644 --- a/exec.c +++ b/exec.c @@ -1070,8 +1070,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state(current_tb, env, - env->mem_io_pc, NULL); + cpu_restore_state(current_tb, env, env->mem_io_pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -1179,7 +1178,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, restore the CPU state */ current_tb_modified = 1; - cpu_restore_state(current_tb, env, pc, puc); + cpu_restore_state(current_tb, env, pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -3266,7 +3265,7 @@ static void check_watchpoint(int offset, int len_mask, int flags) cpu_abort(env, "check_watchpoint: could not find TB for " "pc=%p", (void *)env->mem_io_pc); } - cpu_restore_state(tb, env, env->mem_io_pc, NULL); + cpu_restore_state(tb, env, env->mem_io_pc); tb_phys_invalidate(tb, -1); if (wp->flags & BP_STOP_BEFORE_ACCESS) { env->exception_index = EXCP_DEBUG; @@ -4301,7 +4300,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr) retaddr); } n = env->icount_decr.u16.low + tb->icount; - cpu_restore_state(tb, env, (unsigned long)retaddr, NULL); + cpu_restore_state(tb, env, (unsigned long)retaddr); /* Calculate how many instructions had been executed before the fault occurred. */ n = n - env->icount_decr.u16.low; diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 9f71db4c3a..4ccb10b0f4 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1374,7 +1374,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } /* Exception index and error code are already set */ diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index ee7286b77a..8334fbcf6d 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -90,7 +90,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } raise_exception(env->exception_index); diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index be9eb06fd0..34329e2a60 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -77,7 +77,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); /* Evaluate flags after retranslation. */ helper_top_evaluate_flags(); diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index a73427fe45..fba536f0fb 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4835,7 +4835,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } raise_exception_err(env->exception_index, env->error_code); diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index e84ba488be..c72b1df47b 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -95,7 +95,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 07111073f8..9b13bdbcc2 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -68,7 +68,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index b7cd6b288f..c7b2f97d96 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -60,7 +60,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } cpu_loop_exit(); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 8cba535a32..b8e4991f32 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -54,7 +54,7 @@ static void do_restore_state (void *pc_ptr) tb = tb_find_pc (pc); if (tb) { - cpu_restore_state (tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } #endif @@ -1972,7 +1972,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } helper_raise_exception_err(env->exception_index, env->error_code); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 28d40ac9aa..d5db484b4a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3741,7 +3741,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } helper_raise_exception_err(env->exception_index, env->error_code); diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c index 402df2d85e..be455b9de2 100644 --- a/target-s390x/op_helper.c +++ b/target-s390x/op_helper.c @@ -61,7 +61,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (likely(tb)) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } /* XXX */ diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index c127860cd9..b909d18bc4 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -32,7 +32,7 @@ static void cpu_restore_state_from_retaddr(void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc); } } } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 854f168c60..ffffb8c0bd 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -4375,7 +4375,7 @@ static void cpu_restore_state2(void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, (void *)(long)env->cond); + cpu_restore_state(tb, env, pc); } } } diff --git a/translate-all.c b/translate-all.c index 97668b2c8e..2ca190ca8f 100644 --- a/translate-all.c +++ b/translate-all.c @@ -112,8 +112,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) /* The cpu state corresponding to 'searched_pc' is restored. */ int cpu_restore_state(TranslationBlock *tb, - CPUState *env, unsigned long searched_pc, - void *puc) + CPUState *env, unsigned long searched_pc) { TCGContext *s = &tcg_ctx; int j; From 5bc95aa2461f3b9f70ecbb2a9ec22f939fc33d6d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Date: Tue, 19 Apr 2011 18:56:45 +0400 Subject: [PATCH 238/386] Implement basic part of SA-1110/SA-1100 Basic implementation of DEC/Intel SA-1100/SA-1110 chips emulation. Implemented: - IRQs - GPIO - PPC - RTC - UARTs (no IrDA/etc.) - OST reused from pxa25x Everything else is TODO (esp. PM/idle/sleep!) - see the todo in the hw/strongarm.c Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- Makefile.target | 1 + hw/strongarm.c | 1598 +++++++++++++++++++++++++++++++++++++++++++ hw/strongarm.h | 64 ++ target-arm/cpu.h | 3 + target-arm/helper.c | 9 + 5 files changed, 1675 insertions(+) create mode 100644 hw/strongarm.c create mode 100644 hw/strongarm.h diff --git a/Makefile.target b/Makefile.target index d5761b72f5..9e4cfc055a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -352,6 +352,7 @@ obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o obj-arm-y += syborg_virtio.o obj-arm-y += vexpress.o +obj-arm-y += strongarm.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/hw/strongarm.c b/hw/strongarm.c new file mode 100644 index 0000000000..de08bdf674 --- /dev/null +++ b/hw/strongarm.c @@ -0,0 +1,1598 @@ +/* + * StrongARM SA-1100/SA-1110 emulation + * + * Copyright (C) 2011 Dmitry Eremin-Solenikov + * + * Largely based on StrongARM emulation: + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski <balrog@zabor.org> + * + * UART code based on QEMU 16550A UART emulation + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include "sysbus.h" +#include "strongarm.h" +#include "qemu-error.h" +#include "arm-misc.h" +#include "sysemu.h" +#include "ssi.h" + +//#define DEBUG + +/* + TODO + - Implement cp15, c14 ? + - Implement cp15, c15 !!! (idle used in L) + - Implement idle mode handling/DIM + - Implement sleep mode/Wake sources + - Implement reset control + - Implement memory control regs + - PCMCIA handling + - Maybe support MBGNT/MBREQ + - DMA channels + - GPCLK + - IrDA + - MCP + - Enhance UART with modem signals + */ + +#ifdef DEBUG +# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__) +#else +# define DPRINTF(format, ...) do { } while (0) +#endif + +static struct { + target_phys_addr_t io_base; + int irq; +} sa_serial[] = { + { 0x80010000, SA_PIC_UART1 }, + { 0x80030000, SA_PIC_UART2 }, + { 0x80050000, SA_PIC_UART3 }, + { 0, 0 } +}; + +/* Interrupt Controller */ +typedef struct { + SysBusDevice busdev; + qemu_irq irq; + qemu_irq fiq; + + uint32_t pending; + uint32_t enabled; + uint32_t is_fiq; + uint32_t int_idle; +} StrongARMPICState; + +#define ICIP 0x00 +#define ICMR 0x04 +#define ICLR 0x08 +#define ICFP 0x10 +#define ICPR 0x20 +#define ICCR 0x0c + +#define SA_PIC_SRCS 32 + + +static void strongarm_pic_update(void *opaque) +{ + StrongARMPICState *s = opaque; + + /* FIXME: reflect DIM */ + qemu_set_irq(s->fiq, s->pending & s->enabled & s->is_fiq); + qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq); +} + +static void strongarm_pic_set_irq(void *opaque, int irq, int level) +{ + StrongARMPICState *s = opaque; + + if (level) { + s->pending |= 1 << irq; + } else { + s->pending &= ~(1 << irq); + } + + strongarm_pic_update(s); +} + +static uint32_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMPICState *s = opaque; + + switch (offset) { + case ICIP: + return s->pending & ~s->is_fiq & s->enabled; + case ICMR: + return s->enabled; + case ICLR: + return s->is_fiq; + case ICCR: + return s->int_idle == 0; + case ICFP: + return s->pending & s->is_fiq & s->enabled; + case ICPR: + return s->pending; + default: + printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + __func__, offset); + return 0; + } +} + +static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + StrongARMPICState *s = opaque; + + switch (offset) { + case ICMR: + s->enabled = value; + break; + case ICLR: + s->is_fiq = value; + break; + case ICCR: + s->int_idle = (value & 1) ? 0 : ~0; + break; + default: + printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n", + __func__, offset); + break; + } + strongarm_pic_update(s); +} + +static CPUReadMemoryFunc * const strongarm_pic_readfn[] = { + strongarm_pic_mem_read, + strongarm_pic_mem_read, + strongarm_pic_mem_read, +}; + +static CPUWriteMemoryFunc * const strongarm_pic_writefn[] = { + strongarm_pic_mem_write, + strongarm_pic_mem_write, + strongarm_pic_mem_write, +}; + +static int strongarm_pic_initfn(SysBusDevice *dev) +{ + StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev); + int iomemtype; + + qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS); + iomemtype = cpu_register_io_memory(strongarm_pic_readfn, + strongarm_pic_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x1000, iomemtype); + sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(dev, &s->fiq); + + return 0; +} + +static int strongarm_pic_post_load(void *opaque, int version_id) +{ + strongarm_pic_update(opaque); + return 0; +} + +static VMStateDescription vmstate_strongarm_pic_regs = { + .name = "strongarm_pic", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_pic_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pending, StrongARMPICState), + VMSTATE_UINT32(enabled, StrongARMPICState), + VMSTATE_UINT32(is_fiq, StrongARMPICState), + VMSTATE_UINT32(int_idle, StrongARMPICState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_pic_info = { + .init = strongarm_pic_initfn, + .qdev.name = "strongarm_pic", + .qdev.desc = "StrongARM PIC", + .qdev.size = sizeof(StrongARMPICState), + .qdev.vmsd = &vmstate_strongarm_pic_regs, +}; + +/* Real-Time Clock */ +#define RTAR 0x00 /* RTC Alarm register */ +#define RCNR 0x04 /* RTC Counter register */ +#define RTTR 0x08 /* RTC Timer Trim register */ +#define RTSR 0x10 /* RTC Status register */ + +#define RTSR_AL (1 << 0) /* RTC Alarm detected */ +#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */ +#define RTSR_ALE (1 << 2) /* RTC Alarm enable */ +#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */ + +/* 16 LSB of RTTR are clockdiv for internal trim logic, + * trim delete isn't emulated, so + * f = 32 768 / (RTTR_trim + 1) */ + +typedef struct { + SysBusDevice busdev; + uint32_t rttr; + uint32_t rtsr; + uint32_t rtar; + uint32_t last_rcnr; + int64_t last_hz; + QEMUTimer *rtc_alarm; + QEMUTimer *rtc_hz; + qemu_irq rtc_irq; + qemu_irq rtc_hz_irq; +} StrongARMRTCState; + +static inline void strongarm_rtc_int_update(StrongARMRTCState *s) +{ + qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL); + qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ); +} + +static void strongarm_rtc_hzupdate(StrongARMRTCState *s) +{ + int64_t rt = qemu_get_clock_ms(rt_clock); + s->last_rcnr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_hz = rt; +} + +static inline void strongarm_rtc_timer_update(StrongARMRTCState *s) +{ + if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) { + qemu_mod_timer(s->rtc_hz, s->last_hz + 1000); + } else { + qemu_del_timer(s->rtc_hz); + } + + if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) { + qemu_mod_timer(s->rtc_alarm, s->last_hz + + (((s->rtar - s->last_rcnr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); + } else { + qemu_del_timer(s->rtc_alarm); + } +} + +static inline void strongarm_rtc_alarm_tick(void *opaque) +{ + StrongARMRTCState *s = opaque; + s->rtsr |= RTSR_AL; + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); +} + +static inline void strongarm_rtc_hz_tick(void *opaque) +{ + StrongARMRTCState *s = opaque; + s->rtsr |= RTSR_HZ; + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); +} + +static uint32_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMRTCState *s = opaque; + + switch (addr) { + case RTTR: + return s->rttr; + case RTSR: + return s->rtsr; + case RTAR: + return s->rtar; + case RCNR: + return s->last_rcnr + + ((qemu_get_clock_ms(rt_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + return 0; + } +} + +static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMRTCState *s = opaque; + uint32_t old_rtsr; + + switch (addr) { + case RTTR: + strongarm_rtc_hzupdate(s); + s->rttr = value; + strongarm_rtc_timer_update(s); + break; + + case RTSR: + old_rtsr = s->rtsr; + s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) | + (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ))); + + if (s->rtsr != old_rtsr) { + strongarm_rtc_timer_update(s); + } + + strongarm_rtc_int_update(s); + break; + + case RTAR: + s->rtar = value; + strongarm_rtc_timer_update(s); + break; + + case RCNR: + strongarm_rtc_hzupdate(s); + s->last_rcnr = value; + strongarm_rtc_timer_update(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + } +} + +static CPUReadMemoryFunc * const strongarm_rtc_readfn[] = { + strongarm_rtc_read, + strongarm_rtc_read, + strongarm_rtc_read, +}; + +static CPUWriteMemoryFunc * const strongarm_rtc_writefn[] = { + strongarm_rtc_write, + strongarm_rtc_write, + strongarm_rtc_write, +}; + +static int strongarm_rtc_init(SysBusDevice *dev) +{ + StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev); + struct tm tm; + int iomemtype; + + s->rttr = 0x0; + s->rtsr = 0; + + qemu_get_timedate(&tm, 0); + + s->last_rcnr = (uint32_t) mktimegm(&tm); + s->last_hz = qemu_get_clock_ms(rt_clock); + + s->rtc_alarm = qemu_new_timer_ms(rt_clock, strongarm_rtc_alarm_tick, s); + s->rtc_hz = qemu_new_timer_ms(rt_clock, strongarm_rtc_hz_tick, s); + + sysbus_init_irq(dev, &s->rtc_irq); + sysbus_init_irq(dev, &s->rtc_hz_irq); + + iomemtype = cpu_register_io_memory(strongarm_rtc_readfn, + strongarm_rtc_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x10000, iomemtype); + + return 0; +} + +static void strongarm_rtc_pre_save(void *opaque) +{ + StrongARMRTCState *s = opaque; + + strongarm_rtc_hzupdate(s); +} + +static int strongarm_rtc_post_load(void *opaque, int version_id) +{ + StrongARMRTCState *s = opaque; + + strongarm_rtc_timer_update(s); + strongarm_rtc_int_update(s); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_rtc_regs = { + .name = "strongarm-rtc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = strongarm_rtc_pre_save, + .post_load = strongarm_rtc_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(rttr, StrongARMRTCState), + VMSTATE_UINT32(rtsr, StrongARMRTCState), + VMSTATE_UINT32(rtar, StrongARMRTCState), + VMSTATE_UINT32(last_rcnr, StrongARMRTCState), + VMSTATE_INT64(last_hz, StrongARMRTCState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_rtc_sysbus_info = { + .init = strongarm_rtc_init, + .qdev.name = "strongarm-rtc", + .qdev.desc = "StrongARM RTC Controller", + .qdev.size = sizeof(StrongARMRTCState), + .qdev.vmsd = &vmstate_strongarm_rtc_regs, +}; + +/* GPIO */ +#define GPLR 0x00 +#define GPDR 0x04 +#define GPSR 0x08 +#define GPCR 0x0c +#define GRER 0x10 +#define GFER 0x14 +#define GEDR 0x18 +#define GAFR 0x1c + +typedef struct StrongARMGPIOInfo StrongARMGPIOInfo; +struct StrongARMGPIOInfo { + SysBusDevice busdev; + qemu_irq handler[28]; + qemu_irq irqs[11]; + qemu_irq irqX; + + uint32_t ilevel; + uint32_t olevel; + uint32_t dir; + uint32_t rising; + uint32_t falling; + uint32_t status; + uint32_t gpsr; + uint32_t gafr; + + uint32_t prev_level; +}; + + +static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s) +{ + int i; + for (i = 0; i < 11; i++) { + qemu_set_irq(s->irqs[i], s->status & (1 << i)); + } + + qemu_set_irq(s->irqX, (s->status & ~0x7ff)); +} + +static void strongarm_gpio_set(void *opaque, int line, int level) +{ + StrongARMGPIOInfo *s = opaque; + uint32_t mask; + + mask = 1 << line; + + if (level) { + s->status |= s->rising & mask & + ~s->ilevel & ~s->dir; + s->ilevel |= mask; + } else { + s->status |= s->falling & mask & + s->ilevel & ~s->dir; + s->ilevel &= ~mask; + } + + if (s->status & mask) { + strongarm_gpio_irq_update(s); + } +} + +static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s) +{ + uint32_t level, diff; + int bit; + + level = s->olevel & s->dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +static uint32_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMGPIOInfo *s = opaque; + + switch (offset) { + case GPDR: /* GPIO Pin-Direction registers */ + return s->dir; + + case GPSR: /* GPIO Pin-Output Set registers */ + DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n", + __func__, offset); + return s->gpsr; /* Return last written value. */ + + case GPCR: /* GPIO Pin-Output Clear registers */ + DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n", + __func__, offset); + return 31337; /* Specified as unpredictable in the docs. */ + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + return s->rising; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + return s->falling; + + case GAFR: /* GPIO Alternate Function registers */ + return s->gafr; + + case GPLR: /* GPIO Pin-Level registers */ + return (s->olevel & s->dir) | + (s->ilevel & ~s->dir); + + case GEDR: /* GPIO Edge Detect Status registers */ + return s->status; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } + + return 0; +} + +static void strongarm_gpio_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + StrongARMGPIOInfo *s = opaque; + + switch (offset) { + case GPDR: /* GPIO Pin-Direction registers */ + s->dir = value; + strongarm_gpio_handler_update(s); + break; + + case GPSR: /* GPIO Pin-Output Set registers */ + s->olevel |= value; + strongarm_gpio_handler_update(s); + s->gpsr = value; + break; + + case GPCR: /* GPIO Pin-Output Clear registers */ + s->olevel &= ~value; + strongarm_gpio_handler_update(s); + break; + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + s->rising = value; + break; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + s->falling = value; + break; + + case GAFR: /* GPIO Alternate Function registers */ + s->gafr = value; + break; + + case GEDR: /* GPIO Edge Detect Status registers */ + s->status &= ~value; + strongarm_gpio_irq_update(s); + break; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } +} + +static CPUReadMemoryFunc * const strongarm_gpio_readfn[] = { + strongarm_gpio_read, + strongarm_gpio_read, + strongarm_gpio_read +}; + +static CPUWriteMemoryFunc * const strongarm_gpio_writefn[] = { + strongarm_gpio_write, + strongarm_gpio_write, + strongarm_gpio_write +}; + +static DeviceState *strongarm_gpio_init(target_phys_addr_t base, + DeviceState *pic) +{ + DeviceState *dev; + int i; + + dev = qdev_create(NULL, "strongarm-gpio"); + qdev_init_nofail(dev); + + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + for (i = 0; i < 12; i++) + sysbus_connect_irq(sysbus_from_qdev(dev), i, + qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i)); + + return dev; +} + +static int strongarm_gpio_initfn(SysBusDevice *dev) +{ + int iomemtype; + StrongARMGPIOInfo *s; + int i; + + s = FROM_SYSBUS(StrongARMGPIOInfo, dev); + + qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28); + qdev_init_gpio_out(&dev->qdev, s->handler, 28); + + iomemtype = cpu_register_io_memory(strongarm_gpio_readfn, + strongarm_gpio_writefn, s, DEVICE_NATIVE_ENDIAN); + + sysbus_init_mmio(dev, 0x1000, iomemtype); + for (i = 0; i < 11; i++) { + sysbus_init_irq(dev, &s->irqs[i]); + } + sysbus_init_irq(dev, &s->irqX); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_gpio_regs = { + .name = "strongarm-gpio", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ilevel, StrongARMGPIOInfo), + VMSTATE_UINT32(olevel, StrongARMGPIOInfo), + VMSTATE_UINT32(dir, StrongARMGPIOInfo), + VMSTATE_UINT32(rising, StrongARMGPIOInfo), + VMSTATE_UINT32(falling, StrongARMGPIOInfo), + VMSTATE_UINT32(status, StrongARMGPIOInfo), + VMSTATE_UINT32(gafr, StrongARMGPIOInfo), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_gpio_info = { + .init = strongarm_gpio_initfn, + .qdev.name = "strongarm-gpio", + .qdev.desc = "StrongARM GPIO controller", + .qdev.size = sizeof(StrongARMGPIOInfo), +}; + +/* Peripheral Pin Controller */ +#define PPDR 0x00 +#define PPSR 0x04 +#define PPAR 0x08 +#define PSDR 0x0c +#define PPFR 0x10 + +typedef struct StrongARMPPCInfo StrongARMPPCInfo; +struct StrongARMPPCInfo { + SysBusDevice busdev; + qemu_irq handler[28]; + + uint32_t ilevel; + uint32_t olevel; + uint32_t dir; + uint32_t ppar; + uint32_t psdr; + uint32_t ppfr; + + uint32_t prev_level; +}; + +static void strongarm_ppc_set(void *opaque, int line, int level) +{ + StrongARMPPCInfo *s = opaque; + + if (level) { + s->ilevel |= 1 << line; + } else { + s->ilevel &= ~(1 << line); + } +} + +static void strongarm_ppc_handler_update(StrongARMPPCInfo *s) +{ + uint32_t level, diff; + int bit; + + level = s->olevel & s->dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->handler[bit], (level >> bit) & 1); + } + + s->prev_level = level; +} + +static uint32_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset) +{ + StrongARMPPCInfo *s = opaque; + + switch (offset) { + case PPDR: /* PPC Pin Direction registers */ + return s->dir | ~0x3fffff; + + case PPSR: /* PPC Pin State registers */ + return (s->olevel & s->dir) | + (s->ilevel & ~s->dir) | + ~0x3fffff; + + case PPAR: + return s->ppar | ~0x41000; + + case PSDR: + return s->psdr; + + case PPFR: + return s->ppfr | ~0x7f001; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } + + return 0; +} + +static void strongarm_ppc_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + StrongARMPPCInfo *s = opaque; + + switch (offset) { + case PPDR: /* PPC Pin Direction registers */ + s->dir = value & 0x3fffff; + strongarm_ppc_handler_update(s); + break; + + case PPSR: /* PPC Pin State registers */ + s->olevel = value & s->dir & 0x3fffff; + strongarm_ppc_handler_update(s); + break; + + case PPAR: + s->ppar = value & 0x41000; + break; + + case PSDR: + s->psdr = value & 0x3fffff; + break; + + case PPFR: + s->ppfr = value & 0x7f001; + break; + + default: + printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset); + } +} + +static CPUReadMemoryFunc * const strongarm_ppc_readfn[] = { + strongarm_ppc_read, + strongarm_ppc_read, + strongarm_ppc_read +}; + +static CPUWriteMemoryFunc * const strongarm_ppc_writefn[] = { + strongarm_ppc_write, + strongarm_ppc_write, + strongarm_ppc_write +}; + +static int strongarm_ppc_init(SysBusDevice *dev) +{ + int iomemtype; + StrongARMPPCInfo *s; + + s = FROM_SYSBUS(StrongARMPPCInfo, dev); + + qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22); + qdev_init_gpio_out(&dev->qdev, s->handler, 22); + + iomemtype = cpu_register_io_memory(strongarm_ppc_readfn, + strongarm_ppc_writefn, s, DEVICE_NATIVE_ENDIAN); + + sysbus_init_mmio(dev, 0x1000, iomemtype); + + return 0; +} + +static const VMStateDescription vmstate_strongarm_ppc_regs = { + .name = "strongarm-ppc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ilevel, StrongARMPPCInfo), + VMSTATE_UINT32(olevel, StrongARMPPCInfo), + VMSTATE_UINT32(dir, StrongARMPPCInfo), + VMSTATE_UINT32(ppar, StrongARMPPCInfo), + VMSTATE_UINT32(psdr, StrongARMPPCInfo), + VMSTATE_UINT32(ppfr, StrongARMPPCInfo), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_ppc_info = { + .init = strongarm_ppc_init, + .qdev.name = "strongarm-ppc", + .qdev.desc = "StrongARM PPC controller", + .qdev.size = sizeof(StrongARMPPCInfo), +}; + +/* UART Ports */ +#define UTCR0 0x00 +#define UTCR1 0x04 +#define UTCR2 0x08 +#define UTCR3 0x0c +#define UTDR 0x14 +#define UTSR0 0x1c +#define UTSR1 0x20 + +#define UTCR0_PE (1 << 0) /* Parity enable */ +#define UTCR0_OES (1 << 1) /* Even parity */ +#define UTCR0_SBS (1 << 2) /* 2 stop bits */ +#define UTCR0_DSS (1 << 3) /* 8-bit data */ + +#define UTCR3_RXE (1 << 0) /* Rx enable */ +#define UTCR3_TXE (1 << 1) /* Tx enable */ +#define UTCR3_BRK (1 << 2) /* Force Break */ +#define UTCR3_RIE (1 << 3) /* Rx int enable */ +#define UTCR3_TIE (1 << 4) /* Tx int enable */ +#define UTCR3_LBM (1 << 5) /* Loopback */ + +#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */ +#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */ +#define UTSR0_RID (1 << 2) /* Receiver Idle */ +#define UTSR0_RBB (1 << 3) /* Receiver begin break */ +#define UTSR0_REB (1 << 4) /* Receiver end break */ +#define UTSR0_EIF (1 << 5) /* Error in FIFO */ + +#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */ +#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */ +#define UTSR1_PRE (1 << 3) /* Parity error */ +#define UTSR1_FRE (1 << 4) /* Frame error */ +#define UTSR1_ROR (1 << 5) /* Receive Over Run */ + +#define RX_FIFO_PRE (1 << 8) +#define RX_FIFO_FRE (1 << 9) +#define RX_FIFO_ROR (1 << 10) + +typedef struct { + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq irq; + + uint8_t utcr0; + uint16_t brd; + uint8_t utcr3; + uint8_t utsr0; + uint8_t utsr1; + + uint8_t tx_fifo[8]; + uint8_t tx_start; + uint8_t tx_len; + uint16_t rx_fifo[12]; /* value + error flags in high bits */ + uint8_t rx_start; + uint8_t rx_len; + + uint64_t char_transmit_time; /* time to transmit a char in ticks*/ + bool wait_break_end; + QEMUTimer *rx_timeout_timer; + QEMUTimer *tx_timer; +} StrongARMUARTState; + +static void strongarm_uart_update_status(StrongARMUARTState *s) +{ + uint16_t utsr1 = 0; + + if (s->tx_len != 8) { + utsr1 |= UTSR1_TNF; + } + + if (s->rx_len != 0) { + uint16_t ent = s->rx_fifo[s->rx_start]; + + utsr1 |= UTSR1_RNE; + if (ent & RX_FIFO_PRE) { + s->utsr1 |= UTSR1_PRE; + } + if (ent & RX_FIFO_FRE) { + s->utsr1 |= UTSR1_FRE; + } + if (ent & RX_FIFO_ROR) { + s->utsr1 |= UTSR1_ROR; + } + } + + s->utsr1 = utsr1; +} + +static void strongarm_uart_update_int_status(StrongARMUARTState *s) +{ + uint16_t utsr0 = s->utsr0 & + (UTSR0_REB | UTSR0_RBB | UTSR0_RID); + int i; + + if ((s->utcr3 & UTCR3_TXE) && + (s->utcr3 & UTCR3_TIE) && + s->tx_len <= 4) { + utsr0 |= UTSR0_TFS; + } + + if ((s->utcr3 & UTCR3_RXE) && + (s->utcr3 & UTCR3_RIE) && + s->rx_len > 4) { + utsr0 |= UTSR0_RFS; + } + + for (i = 0; i < s->rx_len && i < 4; i++) + if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) { + utsr0 |= UTSR0_EIF; + break; + } + + s->utsr0 = utsr0; + qemu_set_irq(s->irq, utsr0); +} + +static void strongarm_uart_update_parameters(StrongARMUARTState *s) +{ + int speed, parity, data_bits, stop_bits, frame_size; + QEMUSerialSetParams ssp; + + /* Start bit. */ + frame_size = 1; + if (s->utcr0 & UTCR0_PE) { + /* Parity bit. */ + frame_size++; + if (s->utcr0 & UTCR0_OES) { + parity = 'E'; + } else { + parity = 'O'; + } + } else { + parity = 'N'; + } + if (s->utcr0 & UTCR0_SBS) { + stop_bits = 2; + } else { + stop_bits = 1; + } + + data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7; + frame_size += data_bits + stop_bits; + speed = 3686400 / 16 / (s->brd + 1); + ssp.speed = speed; + ssp.parity = parity; + ssp.data_bits = data_bits; + ssp.stop_bits = stop_bits; + s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; + if (s->chr) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); + } + + DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, + speed, parity, data_bits, stop_bits); +} + +static void strongarm_uart_rx_to(void *opaque) +{ + StrongARMUARTState *s = opaque; + + if (s->rx_len) { + s->utsr0 |= UTSR0_RID; + strongarm_uart_update_int_status(s); + } +} + +static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c) +{ + if ((s->utcr3 & UTCR3_RXE) == 0) { + /* rx disabled */ + return; + } + + if (s->wait_break_end) { + s->utsr0 |= UTSR0_REB; + s->wait_break_end = false; + } + + if (s->rx_len < 12) { + s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c; + s->rx_len++; + } else + s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR; +} + +static int strongarm_uart_can_receive(void *opaque) +{ + StrongARMUARTState *s = opaque; + + if (s->rx_len == 12) { + return 0; + } + /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */ + if (s->rx_len < 8) { + return 8 - s->rx_len; + } + return 1; +} + +static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + StrongARMUARTState *s = opaque; + int i; + + for (i = 0; i < size; i++) { + strongarm_uart_rx_push(s, buf[i]); + } + + /* call the timeout receive callback in 3 char transmit time */ + qemu_mod_timer(s->rx_timeout_timer, + qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static void strongarm_uart_event(void *opaque, int event) +{ + StrongARMUARTState *s = opaque; + if (event == CHR_EVENT_BREAK) { + s->utsr0 |= UTSR0_RBB; + strongarm_uart_rx_push(s, RX_FIFO_FRE); + s->wait_break_end = true; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + } +} + +static void strongarm_uart_tx(void *opaque) +{ + StrongARMUARTState *s = opaque; + uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); + + if (s->utcr3 & UTCR3_LBM) /* loopback */ { + strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1); + } else if (s->chr) { + qemu_chr_write(s->chr, &s->tx_fifo[s->tx_start], 1); + } + + s->tx_start = (s->tx_start + 1) % 8; + s->tx_len--; + if (s->tx_len) { + qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time); + } + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static uint32_t strongarm_uart_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMUARTState *s = opaque; + uint16_t ret; + + switch (addr) { + case UTCR0: + return s->utcr0; + + case UTCR1: + return s->brd >> 8; + + case UTCR2: + return s->brd & 0xff; + + case UTCR3: + return s->utcr3; + + case UTDR: + if (s->rx_len != 0) { + ret = s->rx_fifo[s->rx_start]; + s->rx_start = (s->rx_start + 1) % 12; + s->rx_len--; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + return ret; + } + return 0; + + case UTSR0: + return s->utsr0; + + case UTSR1: + return s->utsr1; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + return 0; + } +} + +static void strongarm_uart_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMUARTState *s = opaque; + + switch (addr) { + case UTCR0: + s->utcr0 = value & 0x7f; + strongarm_uart_update_parameters(s); + break; + + case UTCR1: + s->brd = (s->brd & 0xff) | ((value & 0xf) << 8); + strongarm_uart_update_parameters(s); + break; + + case UTCR2: + s->brd = (s->brd & 0xf00) | (value & 0xff); + strongarm_uart_update_parameters(s); + break; + + case UTCR3: + s->utcr3 = value & 0x3f; + if ((s->utcr3 & UTCR3_RXE) == 0) { + s->rx_len = 0; + } + if ((s->utcr3 & UTCR3_TXE) == 0) { + s->tx_len = 0; + } + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + break; + + case UTDR: + if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) { + s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value; + s->tx_len++; + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + if (s->tx_len == 1) { + strongarm_uart_tx(s); + } + } + break; + + case UTSR0: + s->utsr0 = s->utsr0 & ~(value & + (UTSR0_REB | UTSR0_RBB | UTSR0_RID)); + strongarm_uart_update_int_status(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + } +} + +static CPUReadMemoryFunc * const strongarm_uart_readfn[] = { + strongarm_uart_read, + strongarm_uart_read, + strongarm_uart_read, +}; + +static CPUWriteMemoryFunc * const strongarm_uart_writefn[] = { + strongarm_uart_write, + strongarm_uart_write, + strongarm_uart_write, +}; + +static int strongarm_uart_init(SysBusDevice *dev) +{ + StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); + int iomemtype; + + iomemtype = cpu_register_io_memory(strongarm_uart_readfn, + strongarm_uart_writefn, s, DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x10000, iomemtype); + sysbus_init_irq(dev, &s->irq); + + s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s); + s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); + + if (s->chr) { + qemu_chr_add_handlers(s->chr, + strongarm_uart_can_receive, + strongarm_uart_receive, + strongarm_uart_event, + s); + } + + return 0; +} + +static void strongarm_uart_reset(DeviceState *dev) +{ + StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev); + + s->utcr0 = UTCR0_DSS; /* 8 data, no parity */ + s->brd = 23; /* 9600 */ + /* enable send & recv - this actually violates spec */ + s->utcr3 = UTCR3_TXE | UTCR3_RXE; + + s->rx_len = s->tx_len = 0; + + strongarm_uart_update_parameters(s); + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); +} + +static int strongarm_uart_post_load(void *opaque, int version_id) +{ + StrongARMUARTState *s = opaque; + + strongarm_uart_update_parameters(s); + strongarm_uart_update_status(s); + strongarm_uart_update_int_status(s); + + /* tx and restart timer */ + if (s->tx_len) { + strongarm_uart_tx(s); + } + + /* restart rx timeout timer */ + if (s->rx_len) { + qemu_mod_timer(s->rx_timeout_timer, + qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3); + } + + return 0; +} + +static const VMStateDescription vmstate_strongarm_uart_regs = { + .name = "strongarm-uart", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_uart_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(utcr0, StrongARMUARTState), + VMSTATE_UINT16(brd, StrongARMUARTState), + VMSTATE_UINT8(utcr3, StrongARMUARTState), + VMSTATE_UINT8(utsr0, StrongARMUARTState), + VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8), + VMSTATE_UINT8(tx_start, StrongARMUARTState), + VMSTATE_UINT8(tx_len, StrongARMUARTState), + VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12), + VMSTATE_UINT8(rx_start, StrongARMUARTState), + VMSTATE_UINT8(rx_len, StrongARMUARTState), + VMSTATE_BOOL(wait_break_end, StrongARMUARTState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_uart_info = { + .init = strongarm_uart_init, + .qdev.name = "strongarm-uart", + .qdev.desc = "StrongARM UART controller", + .qdev.size = sizeof(StrongARMUARTState), + .qdev.reset = strongarm_uart_reset, + .qdev.vmsd = &vmstate_strongarm_uart_regs, + .qdev.props = (Property[]) { + DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), + DEFINE_PROP_END_OF_LIST(), + } +}; + +/* Synchronous Serial Ports */ +typedef struct { + SysBusDevice busdev; + qemu_irq irq; + SSIBus *bus; + + uint16_t sscr[2]; + uint16_t sssr; + + uint16_t rx_fifo[8]; + uint8_t rx_level; + uint8_t rx_start; +} StrongARMSSPState; + +#define SSCR0 0x60 /* SSP Control register 0 */ +#define SSCR1 0x64 /* SSP Control register 1 */ +#define SSDR 0x6c /* SSP Data register */ +#define SSSR 0x74 /* SSP Status register */ + +/* Bitfields for above registers */ +#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) +#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) +#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) +#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) +#define SSCR0_SSE (1 << 7) +#define SSCR0_DSS(x) (((x) & 0xf) + 1) +#define SSCR1_RIE (1 << 0) +#define SSCR1_TIE (1 << 1) +#define SSCR1_LBM (1 << 2) +#define SSSR_TNF (1 << 2) +#define SSSR_RNE (1 << 3) +#define SSSR_TFS (1 << 5) +#define SSSR_RFS (1 << 6) +#define SSSR_ROR (1 << 7) +#define SSSR_RW 0x0080 + +static void strongarm_ssp_int_update(StrongARMSSPState *s) +{ + int level = 0; + + level |= (s->sssr & SSSR_ROR); + level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); + level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); + qemu_set_irq(s->irq, level); +} + +static void strongarm_ssp_fifo_update(StrongARMSSPState *s) +{ + s->sssr &= ~SSSR_TFS; + s->sssr &= ~SSSR_TNF; + if (s->sscr[0] & SSCR0_SSE) { + if (s->rx_level >= 4) { + s->sssr |= SSSR_RFS; + } else { + s->sssr &= ~SSSR_RFS; + } + if (s->rx_level) { + s->sssr |= SSSR_RNE; + } else { + s->sssr &= ~SSSR_RNE; + } + /* TX FIFO is never filled, so it is always in underrun + condition if SSP is enabled */ + s->sssr |= SSSR_TFS; + s->sssr |= SSSR_TNF; + } + + strongarm_ssp_int_update(s); +} + +static uint32_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr) +{ + StrongARMSSPState *s = opaque; + uint32_t retval; + + switch (addr) { + case SSCR0: + return s->sscr[0]; + case SSCR1: + return s->sscr[1]; + case SSSR: + return s->sssr; + case SSDR: + if (~s->sscr[0] & SSCR0_SSE) { + return 0xffffffff; + } + if (s->rx_level < 1) { + printf("%s: SSP Rx Underrun\n", __func__); + return 0xffffffff; + } + s->rx_level--; + retval = s->rx_fifo[s->rx_start++]; + s->rx_start &= 0x7; + strongarm_ssp_fifo_update(s); + return retval; + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + break; + } + return 0; +} + +static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + StrongARMSSPState *s = opaque; + + switch (addr) { + case SSCR0: + s->sscr[0] = value & 0xffbf; + if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { + printf("%s: Wrong data size: %i bits\n", __func__, + SSCR0_DSS(value)); + } + if (!(value & SSCR0_SSE)) { + s->sssr = 0; + s->rx_level = 0; + } + strongarm_ssp_fifo_update(s); + break; + + case SSCR1: + s->sscr[1] = value & 0x2f; + if (value & SSCR1_LBM) { + printf("%s: Attempt to use SSP LBM mode\n", __func__); + } + strongarm_ssp_fifo_update(s); + break; + + case SSSR: + s->sssr &= ~(value & SSSR_RW); + strongarm_ssp_int_update(s); + break; + + case SSDR: + if (SSCR0_UWIRE(s->sscr[0])) { + value &= 0xff; + } else + /* Note how 32bits overflow does no harm here */ + value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; + + /* Data goes from here to the Tx FIFO and is shifted out from + * there directly to the slave, no need to buffer it. + */ + if (s->sscr[0] & SSCR0_SSE) { + uint32_t readval; + if (s->sscr[1] & SSCR1_LBM) { + readval = value; + } else { + readval = ssi_transfer(s->bus, value); + } + + if (s->rx_level < 0x08) { + s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval; + } else { + s->sssr |= SSSR_ROR; + } + } + strongarm_ssp_fifo_update(s); + break; + + default: + printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr); + break; + } +} + +static CPUReadMemoryFunc * const strongarm_ssp_readfn[] = { + strongarm_ssp_read, + strongarm_ssp_read, + strongarm_ssp_read, +}; + +static CPUWriteMemoryFunc * const strongarm_ssp_writefn[] = { + strongarm_ssp_write, + strongarm_ssp_write, + strongarm_ssp_write, +}; + +static int strongarm_ssp_post_load(void *opaque, int version_id) +{ + StrongARMSSPState *s = opaque; + + strongarm_ssp_fifo_update(s); + + return 0; +} + +static int strongarm_ssp_init(SysBusDevice *dev) +{ + int iomemtype; + StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev); + + sysbus_init_irq(dev, &s->irq); + + iomemtype = cpu_register_io_memory(strongarm_ssp_readfn, + strongarm_ssp_writefn, s, + DEVICE_NATIVE_ENDIAN); + sysbus_init_mmio(dev, 0x1000, iomemtype); + + s->bus = ssi_create_bus(&dev->qdev, "ssi"); + return 0; +} + +static void strongarm_ssp_reset(DeviceState *dev) +{ + StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev); + s->sssr = 0x03; /* 3 bit data, SPI, disabled */ + s->rx_start = 0; + s->rx_level = 0; +} + +static const VMStateDescription vmstate_strongarm_ssp_regs = { + .name = "strongarm-ssp", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = strongarm_ssp_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2), + VMSTATE_UINT16(sssr, StrongARMSSPState), + VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8), + VMSTATE_UINT8(rx_start, StrongARMSSPState), + VMSTATE_UINT8(rx_level, StrongARMSSPState), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo strongarm_ssp_info = { + .init = strongarm_ssp_init, + .qdev.name = "strongarm-ssp", + .qdev.desc = "StrongARM SSP controller", + .qdev.size = sizeof(StrongARMSSPState), + .qdev.reset = strongarm_ssp_reset, + .qdev.vmsd = &vmstate_strongarm_ssp_regs, +}; + +/* Main CPU functions */ +StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev) +{ + StrongARMState *s; + qemu_irq *pic; + int i; + + s = qemu_mallocz(sizeof(StrongARMState)); + + if (!rev) { + rev = "sa1110-b5"; + } + + if (strncmp(rev, "sa1110", 6)) { + error_report("Machine requires a SA1110 processor.\n"); + exit(1); + } + + s->env = cpu_init(rev); + + if (!s->env) { + error_report("Unable to find CPU definition\n"); + exit(1); + } + + cpu_register_physical_memory(SA_SDCS0, + sdram_size, qemu_ram_alloc(NULL, "strongarm.sdram", + sdram_size) | IO_MEM_RAM); + + pic = arm_pic_init_cpu(s->env); + s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000, + pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL); + + sysbus_create_varargs("pxa25x-timer", 0x90000000, + qdev_get_gpio_in(s->pic, SA_PIC_OSTC0), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC1), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC2), + qdev_get_gpio_in(s->pic, SA_PIC_OSTC3), + NULL); + + sysbus_create_simple("strongarm-rtc", 0x90010000, + qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM)); + + s->gpio = strongarm_gpio_init(0x90040000, s->pic); + + s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL); + + for (i = 0; sa_serial[i].io_base; i++) { + DeviceState *dev = qdev_create(NULL, "strongarm-uart"); + qdev_prop_set_chr(dev, "chardev", serial_hds[i]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, + sa_serial[i].io_base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, + qdev_get_gpio_in(s->pic, sa_serial[i].irq)); + } + + s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000, + qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL); + s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi"); + + return s; +} + +static void strongarm_register_devices(void) +{ + sysbus_register_withprop(&strongarm_pic_info); + sysbus_register_withprop(&strongarm_rtc_sysbus_info); + sysbus_register_withprop(&strongarm_gpio_info); + sysbus_register_withprop(&strongarm_ppc_info); + sysbus_register_withprop(&strongarm_uart_info); + sysbus_register_withprop(&strongarm_ssp_info); +} +device_init(strongarm_register_devices) diff --git a/hw/strongarm.h b/hw/strongarm.h new file mode 100644 index 0000000000..a81b110e23 --- /dev/null +++ b/hw/strongarm.h @@ -0,0 +1,64 @@ +#ifndef _STRONGARM_H +#define _STRONGARM_H + +#define SA_CS0 0x00000000 +#define SA_CS1 0x08000000 +#define SA_CS2 0x10000000 +#define SA_CS3 0x18000000 +#define SA_PCMCIA_CS0 0x20000000 +#define SA_PCMCIA_CS1 0x30000000 +#define SA_CS4 0x40000000 +#define SA_CS5 0x48000000 +/* system registers here */ +#define SA_SDCS0 0xc0000000 +#define SA_SDCS1 0xc8000000 +#define SA_SDCS2 0xd0000000 +#define SA_SDCS3 0xd8000000 + +enum { + SA_PIC_GPIO0_EDGE = 0, + SA_PIC_GPIO1_EDGE, + SA_PIC_GPIO2_EDGE, + SA_PIC_GPIO3_EDGE, + SA_PIC_GPIO4_EDGE, + SA_PIC_GPIO5_EDGE, + SA_PIC_GPIO6_EDGE, + SA_PIC_GPIO7_EDGE, + SA_PIC_GPIO8_EDGE, + SA_PIC_GPIO9_EDGE, + SA_PIC_GPIO10_EDGE, + SA_PIC_GPIOX_EDGE, + SA_PIC_LCD, + SA_PIC_UDC, + SA_PIC_RSVD1, + SA_PIC_UART1, + SA_PIC_UART2, + SA_PIC_UART3, + SA_PIC_MCP, + SA_PIC_SSP, + SA_PIC_DMA_CH0, + SA_PIC_DMA_CH1, + SA_PIC_DMA_CH2, + SA_PIC_DMA_CH3, + SA_PIC_DMA_CH4, + SA_PIC_DMA_CH5, + SA_PIC_OSTC0, + SA_PIC_OSTC1, + SA_PIC_OSTC2, + SA_PIC_OSTC3, + SA_PIC_RTC_HZ, + SA_PIC_RTC_ALARM, +}; + +typedef struct { + CPUState *env; + DeviceState *pic; + DeviceState *gpio; + DeviceState *ppc; + DeviceState *ssp; + SSIBus *ssp_bus; +} StrongARMState; + +StrongARMState *sa1110_init(unsigned int sdram_size, const char *rev); + +#endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index e247a7ade0..d5af64465f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -363,6 +363,7 @@ enum arm_features { ARM_FEATURE_V7MP, /* v7 Multiprocessing Extensions */ ARM_FEATURE_V4T, ARM_FEATURE_V5, + ARM_FEATURE_STRONGARM, }; static inline int arm_feature(CPUARMState *env, int feature) @@ -393,6 +394,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_ARM946 0x41059461 #define ARM_CPUID_TI915T 0x54029152 #define ARM_CPUID_TI925T 0x54029252 +#define ARM_CPUID_SA1100 0x4401A11B +#define ARM_CPUID_SA1110 0x6901B119 #define ARM_CPUID_PXA250 0x69052100 #define ARM_CPUID_PXA255 0x69052d00 #define ARM_CPUID_PXA260 0x69052903 diff --git a/target-arm/helper.c b/target-arm/helper.c index 12127dee74..bf843353e0 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -214,6 +214,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0xd172172; env->cp15.c1_sys = 0x00000078; break; + case ARM_CPUID_SA1100: + case ARM_CPUID_SA1110: + set_feature(env, ARM_FEATURE_STRONGARM); + env->cp15.c1_sys = 0x00000070; + break; default: cpu_abort(env, "Bad CPU ID: %x\n", id); break; @@ -378,6 +383,8 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_CORTEXA9, "cortex-a9"}, { ARM_CPUID_TI925T, "ti925t" }, { ARM_CPUID_PXA250, "pxa250" }, + { ARM_CPUID_SA1100, "sa1100" }, + { ARM_CPUID_SA1110, "sa1110" }, { ARM_CPUID_PXA255, "pxa255" }, { ARM_CPUID_PXA260, "pxa260" }, { ARM_CPUID_PXA261, "pxa261" }, @@ -1553,6 +1560,8 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) case 9: if (arm_feature(env, ARM_FEATURE_OMAPCP)) break; + if (arm_feature(env, ARM_FEATURE_STRONGARM)) + break; /* Ignore ReadBuffer access */ switch (crm) { case 0: /* Cache lockdown. */ switch (op1) { From c64b21d519a6ecae12f65625fa60f3035ed88644 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Date: Tue, 19 Apr 2011 18:56:46 +0400 Subject: [PATCH 239/386] Basic implementation of Sharp Zaurus SL-5500 collie PDA Add very basic implementation of collie PDA emulation. The system lacks LoCoMo and graphics/sound emulation. Linux kernel boots up to mounting rootfs (theoretically it can be provided in pflash images). Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- Makefile.target | 1 + hw/collie.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 hw/collie.c diff --git a/Makefile.target b/Makefile.target index 9e4cfc055a..0e0ef36b97 100644 --- a/Makefile.target +++ b/Makefile.target @@ -353,6 +353,7 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o obj-arm-y += syborg_virtio.o obj-arm-y += vexpress.o obj-arm-y += strongarm.o +obj-arm-y += collie.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/hw/collie.c b/hw/collie.c new file mode 100644 index 0000000000..156404d9f3 --- /dev/null +++ b/hw/collie.c @@ -0,0 +1,69 @@ +/* + * SA-1110-based Sharp Zaurus SL-5500 platform. + * + * Copyright (C) 2011 Dmitry Eremin-Solenikov + * + * This code is licensed under GNU GPL v2. + */ +#include "hw.h" +#include "sysbus.h" +#include "boards.h" +#include "devices.h" +#include "strongarm.h" +#include "arm-misc.h" +#include "flash.h" +#include "blockdev.h" + +static struct arm_boot_info collie_binfo = { + .loader_start = SA_SDCS0, + .ram_size = 0x20000000, +}; + +static void collie_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + StrongARMState *s; + DriveInfo *dinfo; + ram_addr_t phys_flash; + + if (!cpu_model) { + cpu_model = "sa1110"; + } + + s = sa1110_init(collie_binfo.ram_size, cpu_model); + + phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000); + dinfo = drive_get(IF_PFLASH, 0, 0); + pflash_cfi01_register(SA_CS0, phys_flash, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000); + dinfo = drive_get(IF_PFLASH, 0, 1); + pflash_cfi01_register(SA_CS1, phys_flash, + dinfo ? dinfo->bdrv : NULL, (64 * 1024), + 512, 4, 0x00, 0x00, 0x00, 0x00, 0); + + sysbus_create_simple("scoop", 0x40800000, NULL); + + collie_binfo.kernel_filename = kernel_filename; + collie_binfo.kernel_cmdline = kernel_cmdline; + collie_binfo.initrd_filename = initrd_filename; + collie_binfo.board_id = 0x208; + arm_load_kernel(s->env, &collie_binfo); +} + +static QEMUMachine collie_machine = { + .name = "collie", + .desc = "Collie PDA (SA-1110)", + .init = collie_init, +}; + +static void collie_machine_init(void) +{ + qemu_register_machine(&collie_machine); +} + +machine_init(collie_machine_init) From 756ba3b0127fea2bfb538d256c76f19aec126732 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 19 Apr 2011 16:32:34 +0100 Subject: [PATCH 240/386] hw/arm_boot.c: move initrd load address up to accommodate large kernels Newer kernels are large enough that they can overlap the address where qemu places the initrd. Move the initrd up so that there is enough space for the kernel again. Unfortunately it's not possible to automatically determine the size of the kernel if it is compressed, so this is the best we can do. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/arm_boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 41e99d1332..bfac982e65 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -15,7 +15,7 @@ #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00800000 +#define INITRD_LOAD_ADDR 0x00d00000 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ static uint32_t bootloader[] = { From ec444452b8753a372de30b22d9b4765a799db612 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 19 Apr 2011 17:30:55 +0100 Subject: [PATCH 241/386] target-arm: Set Invalid flag for NaN in float-to-int conversions When we catch the special case of an input NaN in ARM float to int helper functions, set the Invalid flag as well as returning the correct result. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index bf843353e0..62ae72ec27 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2551,6 +2551,7 @@ float64 VFP_HELPER(sito, d)(uint32_t x, CPUState *env) uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_uint32(x, &env->vfp.fp_status); @@ -2559,6 +2560,7 @@ uint32_t VFP_HELPER(toui, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_uint32(x, &env->vfp.fp_status); @@ -2567,6 +2569,7 @@ uint32_t VFP_HELPER(toui, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_int32(x, &env->vfp.fp_status); @@ -2575,6 +2578,7 @@ uint32_t VFP_HELPER(tosi, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_int32(x, &env->vfp.fp_status); @@ -2583,6 +2587,7 @@ uint32_t VFP_HELPER(tosi, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_uint32_round_to_zero(x, &env->vfp.fp_status); @@ -2591,6 +2596,7 @@ uint32_t VFP_HELPER(touiz, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_uint32_round_to_zero(x, &env->vfp.fp_status); @@ -2599,6 +2605,7 @@ uint32_t VFP_HELPER(touiz, d)(float64 x, CPUState *env) uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env) { if (float32_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float32_to_int32_round_to_zero(x, &env->vfp.fp_status); @@ -2607,6 +2614,7 @@ uint32_t VFP_HELPER(tosiz, s)(float32 x, CPUState *env) uint32_t VFP_HELPER(tosiz, d)(float64 x, CPUState *env) { if (float64_is_any_nan(x)) { + float_raise(float_flag_invalid, &env->vfp.fp_status); return 0; } return float64_to_int32_round_to_zero(x, &env->vfp.fp_status); @@ -2645,6 +2653,7 @@ uint##fsz##_t VFP_HELPER(to##name, p)(float##fsz x, uint32_t shift, \ { \ float##fsz tmp; \ if (float##fsz##_is_any_nan(x)) { \ + float_raise(float_flag_invalid, &env->vfp.fp_status); \ return 0; \ } \ tmp = float##fsz##_scalbn(x, shift, &env->vfp.fp_status); \ From 1f1f0600aa8a233ceb1b90e9f47386849bdb11ed Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 21:54:04 +0100 Subject: [PATCH 242/386] vmstate: port adb_kbd Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/adb.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 99b30f6bc7..fbf5080167 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -261,30 +261,19 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } -static void adb_kbd_save(QEMUFile *f, void *opaque) -{ - KBDState *s = (KBDState *)opaque; - - qemu_put_buffer(f, s->data, sizeof(s->data)); - qemu_put_sbe32s(f, &s->rptr); - qemu_put_sbe32s(f, &s->wptr); - qemu_put_sbe32s(f, &s->count); -} - -static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id) -{ - KBDState *s = (KBDState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->data, sizeof(s->data)); - qemu_get_sbe32s(f, &s->rptr); - qemu_get_sbe32s(f, &s->wptr); - qemu_get_sbe32s(f, &s->count); - - return 0; -} +static const VMStateDescription vmstate_adb_kbd = { + .name = "adb_kbd", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BUFFER(data, KBDState), + VMSTATE_INT32(rptr, KBDState), + VMSTATE_INT32(wptr, KBDState), + VMSTATE_INT32(count, KBDState), + VMSTATE_END_OF_LIST() + } +}; static int adb_kbd_reset(ADBDevice *d) { @@ -305,8 +294,7 @@ void adb_kbd_init(ADBBusState *bus) d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, adb_kbd_reset, s); qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); - register_savevm(NULL, "adb_kbd", -1, 1, adb_kbd_save, - adb_kbd_load, s); + vmstate_register(NULL, -1, &vmstate_adb_kbd, s); } /***************************************************************/ From 2b2cd5928d9fcad9f1941225f8b9598a2a954e11 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 21:56:35 +0100 Subject: [PATCH 243/386] vmstate: port adb_mouse Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/adb.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index fbf5080167..7499cdcef8 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -427,32 +427,20 @@ static int adb_mouse_reset(ADBDevice *d) return 0; } -static void adb_mouse_save(QEMUFile *f, void *opaque) -{ - MouseState *s = (MouseState *)opaque; - - qemu_put_sbe32s(f, &s->buttons_state); - qemu_put_sbe32s(f, &s->last_buttons_state); - qemu_put_sbe32s(f, &s->dx); - qemu_put_sbe32s(f, &s->dy); - qemu_put_sbe32s(f, &s->dz); -} - -static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id) -{ - MouseState *s = (MouseState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_sbe32s(f, &s->buttons_state); - qemu_get_sbe32s(f, &s->last_buttons_state); - qemu_get_sbe32s(f, &s->dx); - qemu_get_sbe32s(f, &s->dy); - qemu_get_sbe32s(f, &s->dz); - - return 0; -} +static const VMStateDescription vmstate_adb_mouse = { + .name = "adb_mouse", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(buttons_state, MouseState), + VMSTATE_INT32(last_buttons_state, MouseState), + VMSTATE_INT32(dx, MouseState), + VMSTATE_INT32(dy, MouseState), + VMSTATE_INT32(dz, MouseState), + VMSTATE_END_OF_LIST() + } +}; void adb_mouse_init(ADBBusState *bus) { @@ -463,6 +451,5 @@ void adb_mouse_init(ADBBusState *bus) d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, adb_mouse_reset, s); qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); - register_savevm(NULL, "adb_mouse", -1, 1, adb_mouse_save, - adb_mouse_load, s); + vmstate_register(NULL, -1, &vmstate_adb_mouse, s); } From aefe2129315c023413e7780d962016bda19f7f3a Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 22:03:06 +0100 Subject: [PATCH 244/386] vmstate: port ads7846 Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/ads7846.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/hw/ads7846.c b/hw/ads7846.c index b3bbeaf68e..9c58a5f59f 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -105,35 +105,30 @@ static void ads7846_ts_event(void *opaque, } } -static void ads7846_save(QEMUFile *f, void *opaque) +static int ads7856_post_load(void *opaque, int version_id) { - ADS7846State *s = (ADS7846State *) opaque; - int i; - - for (i = 0; i < 8; i ++) - qemu_put_be32(f, s->input[i]); - qemu_put_be32(f, s->noise); - qemu_put_be32(f, s->cycle); - qemu_put_be32(f, s->output); -} - -static int ads7846_load(QEMUFile *f, void *opaque, int version_id) -{ - ADS7846State *s = (ADS7846State *) opaque; - int i; - - for (i = 0; i < 8; i ++) - s->input[i] = qemu_get_be32(f); - s->noise = qemu_get_be32(f); - s->cycle = qemu_get_be32(f); - s->output = qemu_get_be32(f); + ADS7846State *s = opaque; s->pressure = 0; ads7846_int_update(s); - return 0; } +static const VMStateDescription vmstate_ads7846 = { + .name = "ads7846", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = ads7856_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT32_ARRAY(input, ADS7846State, 8), + VMSTATE_INT32(noise, ADS7846State), + VMSTATE_INT32(cycle, ADS7846State), + VMSTATE_INT32(output, ADS7846State), + VMSTATE_END_OF_LIST() + } +}; + static int ads7846_init(SSISlave *dev) { ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev); @@ -151,7 +146,7 @@ static int ads7846_init(SSISlave *dev) ads7846_int_update(s); - register_savevm(NULL, "ads7846", -1, 0, ads7846_save, ads7846_load, s); + vmstate_register(NULL, -1, &vmstate_ads7846, s); return 0; } From fd484ae494bbb38f832fb89a89c979ca6790b531 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 00:16:33 +0100 Subject: [PATCH 245/386] vmstate: port m48t59 Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/m48t59.c | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index 9f39d6bbf0..537c0f7b16 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -585,28 +585,18 @@ static CPUReadMemoryFunc * const nvram_read[] = { &nvram_readl, }; -static void m48t59_save(QEMUFile *f, void *opaque) -{ - M48t59State *s = opaque; - - qemu_put_8s(f, &s->lock); - qemu_put_be16s(f, &s->addr); - qemu_put_buffer(f, s->buffer, s->size); -} - -static int m48t59_load(QEMUFile *f, void *opaque, int version_id) -{ - M48t59State *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_8s(f, &s->lock); - qemu_get_be16s(f, &s->addr); - qemu_get_buffer(f, s->buffer, s->size); - - return 0; -} +static const VMStateDescription vmstate_m48t59 = { + .name = "m48t59", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(lock, M48t59State), + VMSTATE_UINT16(addr, M48t59State), + VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size), + VMSTATE_END_OF_LIST() + } +}; static void m48t59_reset_common(M48t59State *NVRAM) { @@ -696,7 +686,7 @@ static void m48t59_init_common(M48t59State *s) } qemu_get_timedate(&s->alarm, 0); - register_savevm(NULL, "m48t59", -1, 1, m48t59_save, m48t59_load, s); + vmstate_register(NULL, -1, &vmstate_m48t59, s); } static int m48t59_init_isa1(ISADevice *dev) From c7298ab251019b33d55a2ec9ff1880a9aabe33f8 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 23:02:56 +0100 Subject: [PATCH 246/386] vmstate: port mipsnet Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/mipsnet.c | 53 +++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/hw/mipsnet.c b/hw/mipsnet.c index c5e54ffc35..26aad51eab 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -202,44 +202,29 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static void mipsnet_save(QEMUFile *f, void *opaque) -{ - MIPSnetState *s = opaque; - - qemu_put_be32s(f, &s->busy); - qemu_put_be32s(f, &s->rx_count); - qemu_put_be32s(f, &s->rx_read); - qemu_put_be32s(f, &s->tx_count); - qemu_put_be32s(f, &s->tx_written); - qemu_put_be32s(f, &s->intctl); - qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); - qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); -} - -static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) -{ - MIPSnetState *s = opaque; - - if (version_id > 0) - return -EINVAL; - - qemu_get_be32s(f, &s->busy); - qemu_get_be32s(f, &s->rx_count); - qemu_get_be32s(f, &s->rx_read); - qemu_get_be32s(f, &s->tx_count); - qemu_get_be32s(f, &s->tx_written); - qemu_get_be32s(f, &s->intctl); - qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); - qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); - - return 0; -} +static const VMStateDescription vmstate_mipsnet = { + .name = "mipsnet", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(busy, MIPSnetState), + VMSTATE_UINT32(rx_count, MIPSnetState), + VMSTATE_UINT32(rx_read, MIPSnetState), + VMSTATE_UINT32(tx_count, MIPSnetState), + VMSTATE_UINT32(tx_written, MIPSnetState), + VMSTATE_UINT32(intctl, MIPSnetState), + VMSTATE_BUFFER(rx_buffer, MIPSnetState), + VMSTATE_BUFFER(tx_buffer, MIPSnetState), + VMSTATE_END_OF_LIST() + } +}; static void mipsnet_cleanup(VLANClientState *nc) { MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - unregister_savevm(NULL, "mipsnet", s); + vmstate_unregister(NULL, &vmstate_mipsnet, s); isa_unassign_ioport(s->io_base, 36); @@ -284,5 +269,5 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) } mipsnet_reset(s); - register_savevm(NULL, "mipsnet", 0, 0, mipsnet_save, mipsnet_load, s); + vmstate_register(NULL, 0, &vmstate_mipsnet, s); } From 81986ac4b66af8005fbe79558c319ba6a38561c2 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 23:12:32 +0100 Subject: [PATCH 247/386] vmstate: port arm sp804 Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/arm_timer.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 82f05dec84..cfd1ebe22f 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -235,24 +235,17 @@ static CPUWriteMemoryFunc * const sp804_writefn[] = { sp804_write }; -static void sp804_save(QEMUFile *f, void *opaque) -{ - sp804_state *s = (sp804_state *)opaque; - qemu_put_be32(f, s->level[0]); - qemu_put_be32(f, s->level[1]); -} -static int sp804_load(QEMUFile *f, void *opaque, int version_id) -{ - sp804_state *s = (sp804_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->level[0] = qemu_get_be32(f); - s->level[1] = qemu_get_be32(f); - return 0; -} +static const VMStateDescription vmstate_sp804 = { + .name = "sp804", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32_ARRAY(level, sp804_state, 2), + VMSTATE_END_OF_LIST() + } +}; static int sp804_init(SysBusDevice *dev) { @@ -271,7 +264,7 @@ static int sp804_init(SysBusDevice *dev) iomemtype = cpu_register_io_memory(sp804_readfn, sp804_writefn, s, DEVICE_NATIVE_ENDIAN); sysbus_init_mmio(dev, 0x1000, iomemtype); - register_savevm(&dev->qdev, "sp804", -1, 1, sp804_save, sp804_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_sp804, s); return 0; } From eecd33a57895a579bd4d2270b1bc758b608ae5a4 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 23:15:41 +0100 Subject: [PATCH 248/386] vmstate: port arm_timer Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/arm_timer.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/hw/arm_timer.c b/hw/arm_timer.c index cfd1ebe22f..dac9e70750 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -140,28 +140,19 @@ static void arm_timer_tick(void *opaque) arm_timer_update(s); } -static void arm_timer_save(QEMUFile *f, void *opaque) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - qemu_put_be32(f, s->control); - qemu_put_be32(f, s->limit); - qemu_put_be32(f, s->int_level); - qemu_put_ptimer(f, s->timer); -} - -static int arm_timer_load(QEMUFile *f, void *opaque, int version_id) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->control = qemu_get_be32(f); - s->limit = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - qemu_get_ptimer(f, s->timer); - return 0; -} +static const VMStateDescription vmstate_arm_timer = { + .name = "arm_timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(control, arm_timer_state), + VMSTATE_UINT32(limit, arm_timer_state), + VMSTATE_INT32(int_level, arm_timer_state), + VMSTATE_PTIMER(timer, arm_timer_state), + VMSTATE_END_OF_LIST() + } +}; static arm_timer_state *arm_timer_init(uint32_t freq) { @@ -174,7 +165,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) bh = qemu_bh_new(arm_timer_tick, s); s->timer = ptimer_init(bh); - register_savevm(NULL, "arm_timer", -1, 1, arm_timer_save, arm_timer_load, s); + vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } From 22a3faf507a9de2fab8988daf39ff41d09419bec Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 23:18:59 +0100 Subject: [PATCH 249/386] vmstate: port sysborg_timer Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/syborg_timer.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c index cedcd8ed47..50c813e969 100644 --- a/hw/syborg_timer.c +++ b/hw/syborg_timer.c @@ -174,34 +174,21 @@ static CPUWriteMemoryFunc * const syborg_timer_writefn[] = { syborg_timer_write }; -static void syborg_timer_save(QEMUFile *f, void *opaque) -{ - SyborgTimerState *s = opaque; - - qemu_put_be32(f, s->running); - qemu_put_be32(f, s->oneshot); - qemu_put_be32(f, s->limit); - qemu_put_be32(f, s->int_level); - qemu_put_be32(f, s->int_enabled); - qemu_put_ptimer(f, s->timer); -} - -static int syborg_timer_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgTimerState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - s->running = qemu_get_be32(f); - s->oneshot = qemu_get_be32(f); - s->limit = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - s->int_enabled = qemu_get_be32(f); - qemu_get_ptimer(f, s->timer); - - return 0; -} +static const VMStateDescription vmstate_syborg_timer = { + .name = "syborg_timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(running, SyborgTimerState), + VMSTATE_INT32(oneshot, SyborgTimerState), + VMSTATE_UINT32(limit, SyborgTimerState), + VMSTATE_UINT32(int_level, SyborgTimerState), + VMSTATE_UINT32(int_enabled, SyborgTimerState), + VMSTATE_PTIMER(timer, SyborgTimerState), + VMSTATE_END_OF_LIST() + } +}; static int syborg_timer_init(SysBusDevice *dev) { @@ -222,8 +209,7 @@ static int syborg_timer_init(SysBusDevice *dev) bh = qemu_bh_new(syborg_timer_tick, s); s->timer = ptimer_init(bh); ptimer_set_freq(s->timer, s->freq); - register_savevm(&dev->qdev, "syborg_timer", -1, 1, - syborg_timer_save, syborg_timer_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_timer, s); return 0; } From 852f771ec9e5cb5e57b4023209f37dd331d5dbdd Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 23:51:14 +0100 Subject: [PATCH 250/386] vmstate: port pmtimer It was a half conversion. Finish it. enabled can only get values of 0, 1 or 2, was declared as an int but sent as an unint8_t, change its type. Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/hw.h | 17 +++++++++------ hw/ptimer.c | 59 ++++++++++++++-------------------------------------- qemu-timer.h | 2 -- 3 files changed, 27 insertions(+), 51 deletions(-) diff --git a/hw/hw.h b/hw/hw.h index 1b090395ab..56447a735d 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -689,6 +689,17 @@ extern const VMStateDescription vmstate_usb_device; .offset = vmstate_offset_macaddr(_state, _field), \ } +extern const VMStateDescription vmstate_ptimer; + +#define VMSTATE_PTIMER(_field, _state) { \ + .name = (stringify(_field)), \ + .version_id = (1), \ + .vmsd = &vmstate_ptimer, \ + .size = sizeof(ptimer_state *), \ + .flags = VMS_STRUCT|VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, ptimer_state), \ +} + /* _f : field name _f_n : num of elements field_name _n : num of elements @@ -784,12 +795,6 @@ extern const VMStateDescription vmstate_usb_device; #define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) -#define VMSTATE_PTIMER_V(_f, _s, _v) \ - VMSTATE_POINTER(_f, _s, _v, vmstate_info_ptimer, ptimer_state *) - -#define VMSTATE_PTIMER(_f, _s) \ - VMSTATE_PTIMER_V(_f, _s, 0) - #define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool) diff --git a/hw/ptimer.c b/hw/ptimer.c index e68c1d1415..47964a67e1 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -11,7 +11,7 @@ struct ptimer_state { - int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ + uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ uint64_t limit; uint64_t delta; uint32_t period_frac; @@ -188,49 +188,22 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) } } -void qemu_put_ptimer(QEMUFile *f, ptimer_state *s) -{ - qemu_put_byte(f, s->enabled); - qemu_put_be64s(f, &s->limit); - qemu_put_be64s(f, &s->delta); - qemu_put_be32s(f, &s->period_frac); - qemu_put_sbe64s(f, &s->period); - qemu_put_sbe64s(f, &s->last_event); - qemu_put_sbe64s(f, &s->next_event); - qemu_put_timer(f, s->timer); -} - -void qemu_get_ptimer(QEMUFile *f, ptimer_state *s) -{ - s->enabled = qemu_get_byte(f); - qemu_get_be64s(f, &s->limit); - qemu_get_be64s(f, &s->delta); - qemu_get_be32s(f, &s->period_frac); - qemu_get_sbe64s(f, &s->period); - qemu_get_sbe64s(f, &s->last_event); - qemu_get_sbe64s(f, &s->next_event); - qemu_get_timer(f, s->timer); -} - -static int get_ptimer(QEMUFile *f, void *pv, size_t size) -{ - ptimer_state *v = pv; - - qemu_get_ptimer(f, v); - return 0; -} - -static void put_ptimer(QEMUFile *f, void *pv, size_t size) -{ - ptimer_state *v = pv; - - qemu_put_ptimer(f, v); -} - -const VMStateInfo vmstate_info_ptimer = { +const VMStateDescription vmstate_ptimer = { .name = "ptimer", - .get = get_ptimer, - .put = put_ptimer, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(enabled, ptimer_state), + VMSTATE_UINT64(limit, ptimer_state), + VMSTATE_UINT64(delta, ptimer_state), + VMSTATE_UINT32(period_frac, ptimer_state), + VMSTATE_INT64(period, ptimer_state), + VMSTATE_INT64(last_event, ptimer_state), + VMSTATE_INT64(next_event, ptimer_state), + VMSTATE_TIMER(timer, ptimer_state), + VMSTATE_END_OF_LIST() + } }; ptimer_state *ptimer_init(QEMUBH *bh) diff --git a/qemu-timer.h b/qemu-timer.h index bbc3452bc3..2cacf65535 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -144,8 +144,6 @@ uint64_t ptimer_get_count(ptimer_state *s); void ptimer_set_count(ptimer_state *s, uint64_t count); void ptimer_run(ptimer_state *s, int oneshot); void ptimer_stop(ptimer_state *s); -void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); -void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); /* icount */ int64_t qemu_icount_round(int64_t count); From 4ba673ce628ea554a0c095c432813debe6ec339a Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 00:44:28 +0100 Subject: [PATCH 251/386] vmstate: port syborg_rtc Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/syborg_rtc.c | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c index 16d8f9edb8..69f6ccf29c 100644 --- a/hw/syborg_rtc.c +++ b/hw/syborg_rtc.c @@ -102,26 +102,17 @@ static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = { syborg_rtc_write }; -static void syborg_rtc_save(QEMUFile *f, void *opaque) -{ - SyborgRTCState *s = opaque; - - qemu_put_be64(f, s->offset); - qemu_put_be64(f, s->data); -} - -static int syborg_rtc_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgRTCState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - s->offset = qemu_get_be64(f); - s->data = qemu_get_be64(f); - - return 0; -} +static const VMStateDescription vmstate_syborg_rtc = { + .name = "syborg_keyboard", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(offset, SyborgRTCState), + VMSTATE_INT64(data, SyborgRTCState), + VMSTATE_END_OF_LIST() + } +}; static int syborg_rtc_init(SysBusDevice *dev) { @@ -137,8 +128,7 @@ static int syborg_rtc_init(SysBusDevice *dev) qemu_get_timedate(&tm, 0); s->offset = (uint64_t)mktime(&tm) * 1000000000; - register_savevm(&dev->qdev, "syborg_rtc", -1, 1, - syborg_rtc_save, syborg_rtc_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s); return 0; } From 25f5a1b7df5b55aa850326673e30560f294577c7 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 01:06:08 +0100 Subject: [PATCH 252/386] vmstate: port pxa2xx_keypad Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx_keypad.c | 53 +++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index d77dbf1793..10ef154aa1 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -289,40 +289,22 @@ static CPUWriteMemoryFunc * const pxa2xx_keypad_writefn[] = { pxa2xx_keypad_write }; -static void pxa2xx_keypad_save(QEMUFile *f, void *opaque) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - - qemu_put_be32s(f, &s->kpc); - qemu_put_be32s(f, &s->kpdk); - qemu_put_be32s(f, &s->kprec); - qemu_put_be32s(f, &s->kpmk); - qemu_put_be32s(f, &s->kpas); - qemu_put_be32s(f, &s->kpasmkp[0]); - qemu_put_be32s(f, &s->kpasmkp[1]); - qemu_put_be32s(f, &s->kpasmkp[2]); - qemu_put_be32s(f, &s->kpasmkp[3]); - qemu_put_be32s(f, &s->kpkdi); - -} - -static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; - - qemu_get_be32s(f, &s->kpc); - qemu_get_be32s(f, &s->kpdk); - qemu_get_be32s(f, &s->kprec); - qemu_get_be32s(f, &s->kpmk); - qemu_get_be32s(f, &s->kpas); - qemu_get_be32s(f, &s->kpasmkp[0]); - qemu_get_be32s(f, &s->kpasmkp[1]); - qemu_get_be32s(f, &s->kpasmkp[2]); - qemu_get_be32s(f, &s->kpasmkp[3]); - qemu_get_be32s(f, &s->kpkdi); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_keypad = { + .name = "pxa2xx_keypad", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(kpc, PXA2xxKeyPadState), + VMSTATE_UINT32(kpdk, PXA2xxKeyPadState), + VMSTATE_UINT32(kprec, PXA2xxKeyPadState), + VMSTATE_UINT32(kpmk, PXA2xxKeyPadState), + VMSTATE_UINT32(kpas, PXA2xxKeyPadState), + VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4), + VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState), + VMSTATE_END_OF_LIST() + } +}; PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base, qemu_irq irq) @@ -337,8 +319,7 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base, pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x00100000, iomemtype); - register_savevm(NULL, "pxa2xx_keypad", 0, 0, - pxa2xx_keypad_save, pxa2xx_keypad_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s); return s; } From 02b687579578a1df9f5733023544c21a8446d3a3 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 01:50:33 +0100 Subject: [PATCH 253/386] vmstate: port pl011 Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pl011.c | 76 ++++++++++++++++++------------------------------------ 1 file changed, 25 insertions(+), 51 deletions(-) diff --git a/hw/pl011.c b/hw/pl011.c index 77f0dbf137..3b94b14cb9 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -235,56 +235,30 @@ static CPUWriteMemoryFunc * const pl011_writefn[] = { pl011_write }; -static void pl011_save(QEMUFile *f, void *opaque) -{ - pl011_state *s = (pl011_state *)opaque; - int i; - - qemu_put_be32(f, s->readbuff); - qemu_put_be32(f, s->flags); - qemu_put_be32(f, s->lcr); - qemu_put_be32(f, s->cr); - qemu_put_be32(f, s->dmacr); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->int_level); - for (i = 0; i < 16; i++) - qemu_put_be32(f, s->read_fifo[i]); - qemu_put_be32(f, s->ilpr); - qemu_put_be32(f, s->ibrd); - qemu_put_be32(f, s->fbrd); - qemu_put_be32(f, s->ifl); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - qemu_put_be32(f, s->read_trigger); -} - -static int pl011_load(QEMUFile *f, void *opaque, int version_id) -{ - pl011_state *s = (pl011_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->readbuff = qemu_get_be32(f); - s->flags = qemu_get_be32(f); - s->lcr = qemu_get_be32(f); - s->cr = qemu_get_be32(f); - s->dmacr = qemu_get_be32(f); - s->int_enabled = qemu_get_be32(f); - s->int_level = qemu_get_be32(f); - for (i = 0; i < 16; i++) - s->read_fifo[i] = qemu_get_be32(f); - s->ilpr = qemu_get_be32(f); - s->ibrd = qemu_get_be32(f); - s->fbrd = qemu_get_be32(f); - s->ifl = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - s->read_trigger = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_pl011 = { + .name = "pl011", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(readbuff, pl011_state), + VMSTATE_UINT32(flags, pl011_state), + VMSTATE_UINT32(lcr, pl011_state), + VMSTATE_UINT32(cr, pl011_state), + VMSTATE_UINT32(dmacr, pl011_state), + VMSTATE_UINT32(int_enabled, pl011_state), + VMSTATE_UINT32(int_level, pl011_state), + VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16), + VMSTATE_UINT32(ilpr, pl011_state), + VMSTATE_UINT32(ibrd, pl011_state), + VMSTATE_UINT32(fbrd, pl011_state), + VMSTATE_UINT32(ifl, pl011_state), + VMSTATE_INT32(read_pos, pl011_state), + VMSTATE_INT32(read_count, pl011_state), + VMSTATE_INT32(read_trigger, pl011_state), + VMSTATE_END_OF_LIST() + } +}; static int pl011_init(SysBusDevice *dev, const unsigned char *id) { @@ -307,7 +281,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, pl011_event, s); } - register_savevm(&dev->qdev, "pl011_uart", -1, 1, pl011_save, pl011_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); return 0; } From 0797226c56ea51a72ebbf7dcecfd2c1e44147cf0 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 02:17:33 +0100 Subject: [PATCH 254/386] vmstate: port armv7m nvic Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/armv7m_nvic.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index ffe16b8a61..d06eec9b39 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -365,30 +365,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) } } -static void nvic_save(QEMUFile *f, void *opaque) -{ - nvic_state *s = (nvic_state *)opaque; - - qemu_put_be32(f, s->systick.control); - qemu_put_be32(f, s->systick.reload); - qemu_put_be64(f, s->systick.tick); - qemu_put_timer(f, s->systick.timer); -} - -static int nvic_load(QEMUFile *f, void *opaque, int version_id) -{ - nvic_state *s = (nvic_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->systick.control = qemu_get_be32(f); - s->systick.reload = qemu_get_be32(f); - s->systick.tick = qemu_get_be64(f); - qemu_get_timer(f, s->systick.timer); - - return 0; -} +static const VMStateDescription vmstate_nvic = { + .name = "armv7m_nvic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(systick.control, nvic_state), + VMSTATE_UINT32(systick.reload, nvic_state), + VMSTATE_INT64(systick.tick, nvic_state), + VMSTATE_TIMER(systick.timer, nvic_state), + VMSTATE_END_OF_LIST() + } +}; static int armv7m_nvic_init(SysBusDevice *dev) { @@ -397,7 +386,7 @@ static int armv7m_nvic_init(SysBusDevice *dev) gic_init(&s->gic); cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype); s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); - register_savevm(&dev->qdev, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_nvic, s); return 0; } From ff269cd041d33cded58bc734f88456720dcc1864 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 02:48:43 +0100 Subject: [PATCH 255/386] vmstate: port stellaris i2c Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 7932c24576..d0b1588393 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -843,36 +843,22 @@ static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = { stellaris_i2c_write }; -static void stellaris_i2c_save(QEMUFile *f, void *opaque) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - qemu_put_be32(f, s->msa); - qemu_put_be32(f, s->mcs); - qemu_put_be32(f, s->mdr); - qemu_put_be32(f, s->mtpr); - qemu_put_be32(f, s->mimr); - qemu_put_be32(f, s->mris); - qemu_put_be32(f, s->mcr); -} - -static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->msa = qemu_get_be32(f); - s->mcs = qemu_get_be32(f); - s->mdr = qemu_get_be32(f); - s->mtpr = qemu_get_be32(f); - s->mimr = qemu_get_be32(f); - s->mris = qemu_get_be32(f); - s->mcr = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_stellaris_i2c = { + .name = "stellaris_i2c", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(msa, stellaris_i2c_state), + VMSTATE_UINT32(mcs, stellaris_i2c_state), + VMSTATE_UINT32(mdr, stellaris_i2c_state), + VMSTATE_UINT32(mtpr, stellaris_i2c_state), + VMSTATE_UINT32(mimr, stellaris_i2c_state), + VMSTATE_UINT32(mris, stellaris_i2c_state), + VMSTATE_UINT32(mcr, stellaris_i2c_state), + VMSTATE_END_OF_LIST() + } +}; static int stellaris_i2c_init(SysBusDevice * dev) { @@ -890,8 +876,7 @@ static int stellaris_i2c_init(SysBusDevice * dev) sysbus_init_mmio(dev, 0x1000, iomemtype); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); - register_savevm(&dev->qdev, "stellaris_i2c", -1, 1, - stellaris_i2c_save, stellaris_i2c_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s); return 0; } From a4dec1d0d423443d3e5a026a1776fb41b33c06eb Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 02:51:29 +0100 Subject: [PATCH 256/386] vmstate: port stellaris ssi bus Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index d0b1588393..00efb36037 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1218,24 +1218,16 @@ static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) return ssi_transfer(s->bus[s->current_dev], val); } -static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - qemu_put_be32(f, s->current_dev); -} - -static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->current_dev = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_stellaris_ssi_bus = { + .name = "stellaris_ssi_bus", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(current_dev, stellaris_ssi_bus_state), + VMSTATE_END_OF_LIST() + } +}; static int stellaris_ssi_bus_init(SSISlave *dev) { @@ -1245,8 +1237,7 @@ static int stellaris_ssi_bus_init(SSISlave *dev) s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); - register_savevm(&dev->qdev, "stellaris_ssi_bus", -1, 1, - stellaris_ssi_bus_save, stellaris_ssi_bus_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s); return 0; } From 293c16aa372fcdfed3be460cf657aced56327195 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 03:03:11 +0100 Subject: [PATCH 257/386] vmstate: port stellaris sys Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 71 ++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 00efb36037..11d618d87a 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -604,58 +604,37 @@ static void ssys_reset(void *opaque) s->dcgc[0] = 1; } -static void ssys_save(QEMUFile *f, void *opaque) +static int stellaris_sys_post_load(void *opaque, int version_id) { - ssys_state *s = (ssys_state *)opaque; + ssys_state *s = opaque; - qemu_put_be32(f, s->pborctl); - qemu_put_be32(f, s->ldopctl); - qemu_put_be32(f, s->int_mask); - qemu_put_be32(f, s->int_status); - qemu_put_be32(f, s->resc); - qemu_put_be32(f, s->rcc); - qemu_put_be32(f, s->rcgc[0]); - qemu_put_be32(f, s->rcgc[1]); - qemu_put_be32(f, s->rcgc[2]); - qemu_put_be32(f, s->scgc[0]); - qemu_put_be32(f, s->scgc[1]); - qemu_put_be32(f, s->scgc[2]); - qemu_put_be32(f, s->dcgc[0]); - qemu_put_be32(f, s->dcgc[1]); - qemu_put_be32(f, s->dcgc[2]); - qemu_put_be32(f, s->clkvclr); - qemu_put_be32(f, s->ldoarst); -} - -static int ssys_load(QEMUFile *f, void *opaque, int version_id) -{ - ssys_state *s = (ssys_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->pborctl = qemu_get_be32(f); - s->ldopctl = qemu_get_be32(f); - s->int_mask = qemu_get_be32(f); - s->int_status = qemu_get_be32(f); - s->resc = qemu_get_be32(f); - s->rcc = qemu_get_be32(f); - s->rcgc[0] = qemu_get_be32(f); - s->rcgc[1] = qemu_get_be32(f); - s->rcgc[2] = qemu_get_be32(f); - s->scgc[0] = qemu_get_be32(f); - s->scgc[1] = qemu_get_be32(f); - s->scgc[2] = qemu_get_be32(f); - s->dcgc[0] = qemu_get_be32(f); - s->dcgc[1] = qemu_get_be32(f); - s->dcgc[2] = qemu_get_be32(f); - s->clkvclr = qemu_get_be32(f); - s->ldoarst = qemu_get_be32(f); ssys_calculate_system_clock(s); return 0; } +static const VMStateDescription vmstate_stellaris_sys = { + .name = "stellaris_sys", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = stellaris_sys_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pborctl, ssys_state), + VMSTATE_UINT32(ldopctl, ssys_state), + VMSTATE_UINT32(int_mask, ssys_state), + VMSTATE_UINT32(int_status, ssys_state), + VMSTATE_UINT32(resc, ssys_state), + VMSTATE_UINT32(rcc, ssys_state), + VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3), + VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3), + VMSTATE_UINT32(clkvclr, ssys_state), + VMSTATE_UINT32(ldoarst, ssys_state), + VMSTATE_END_OF_LIST() + } +}; + static int stellaris_sys_init(uint32_t base, qemu_irq irq, stellaris_board_info * board, uint8_t *macaddr) @@ -675,7 +654,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x00001000, iomemtype); ssys_reset(s); - register_savevm(NULL, "stellaris_sys", -1, 1, ssys_save, ssys_load, s); + vmstate_register(NULL, -1, &vmstate_stellaris_sys, s); return 0; } From 075790c2c24f0dee15c584ae5c49903a52343bd4 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 12:43:50 +0100 Subject: [PATCH 258/386] vmstate: port pl022 ssp Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pl022.c | 84 +++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/hw/pl022.c b/hw/pl022.c index ffe05ab747..00e494a0de 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -239,54 +239,42 @@ static CPUWriteMemoryFunc * const pl022_writefn[] = { pl022_write }; -static void pl022_save(QEMUFile *f, void *opaque) -{ - pl022_state *s = (pl022_state *)opaque; - int i; - - qemu_put_be32(f, s->cr0); - qemu_put_be32(f, s->cr1); - qemu_put_be32(f, s->bitmask); - qemu_put_be32(f, s->sr); - qemu_put_be32(f, s->cpsr); - qemu_put_be32(f, s->is); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->tx_fifo_head); - qemu_put_be32(f, s->rx_fifo_head); - qemu_put_be32(f, s->tx_fifo_len); - qemu_put_be32(f, s->rx_fifo_len); - for (i = 0; i < 8; i++) { - qemu_put_be16(f, s->tx_fifo[i]); - qemu_put_be16(f, s->rx_fifo[i]); +static const VMStateDescription vmstate_pl022 = { + .name = "pl022_ssp", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr0, pl022_state), + VMSTATE_UINT32(cr1, pl022_state), + VMSTATE_UINT32(bitmask, pl022_state), + VMSTATE_UINT32(sr, pl022_state), + VMSTATE_UINT32(cpsr, pl022_state), + VMSTATE_UINT32(is, pl022_state), + VMSTATE_UINT32(im, pl022_state), + VMSTATE_INT32(tx_fifo_head, pl022_state), + VMSTATE_INT32(rx_fifo_head, pl022_state), + VMSTATE_INT32(tx_fifo_len, pl022_state), + VMSTATE_INT32(rx_fifo_len, pl022_state), + VMSTATE_UINT16(tx_fifo[0], pl022_state), + VMSTATE_UINT16(rx_fifo[0], pl022_state), + VMSTATE_UINT16(tx_fifo[1], pl022_state), + VMSTATE_UINT16(rx_fifo[1], pl022_state), + VMSTATE_UINT16(tx_fifo[2], pl022_state), + VMSTATE_UINT16(rx_fifo[2], pl022_state), + VMSTATE_UINT16(tx_fifo[3], pl022_state), + VMSTATE_UINT16(rx_fifo[3], pl022_state), + VMSTATE_UINT16(tx_fifo[4], pl022_state), + VMSTATE_UINT16(rx_fifo[4], pl022_state), + VMSTATE_UINT16(tx_fifo[5], pl022_state), + VMSTATE_UINT16(rx_fifo[5], pl022_state), + VMSTATE_UINT16(tx_fifo[6], pl022_state), + VMSTATE_UINT16(rx_fifo[6], pl022_state), + VMSTATE_UINT16(tx_fifo[7], pl022_state), + VMSTATE_UINT16(rx_fifo[7], pl022_state), + VMSTATE_END_OF_LIST() } -} - -static int pl022_load(QEMUFile *f, void *opaque, int version_id) -{ - pl022_state *s = (pl022_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->cr0 = qemu_get_be32(f); - s->cr1 = qemu_get_be32(f); - s->bitmask = qemu_get_be32(f); - s->sr = qemu_get_be32(f); - s->cpsr = qemu_get_be32(f); - s->is = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->tx_fifo_head = qemu_get_be32(f); - s->rx_fifo_head = qemu_get_be32(f); - s->tx_fifo_len = qemu_get_be32(f); - s->rx_fifo_len = qemu_get_be32(f); - for (i = 0; i < 8; i++) { - s->tx_fifo[i] = qemu_get_be16(f); - s->rx_fifo[i] = qemu_get_be16(f); - } - - return 0; -} +}; static int pl022_init(SysBusDevice *dev) { @@ -300,7 +288,7 @@ static int pl022_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->ssi = ssi_create_bus(&dev->qdev, "ssi"); pl022_reset(s); - register_savevm(&dev->qdev, "pl022_ssp", -1, 1, pl022_save, pl022_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_pl022, s); return 0; } From 4acd38cef07820238e9d76ae68f14689f9764ef0 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 13:17:23 +0100 Subject: [PATCH 259/386] vmstate: port heathrow_pic Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/heathrow_pic.c | 62 +++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index b19b754b31..5fd71a0f71 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -159,42 +159,31 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level) heathrow_pic_update(s); } -static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s) -{ - qemu_put_be32s(f, &s->events); - qemu_put_be32s(f, &s->mask); - qemu_put_be32s(f, &s->levels); - qemu_put_be32s(f, &s->level_triggered); -} +static const VMStateDescription vmstate_heathrow_pic_one = { + .name = "heathrow_pic_one", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(events, HeathrowPIC), + VMSTATE_UINT32(mask, HeathrowPIC), + VMSTATE_UINT32(levels, HeathrowPIC), + VMSTATE_UINT32(level_triggered, HeathrowPIC), + VMSTATE_END_OF_LIST() + } +}; -static void heathrow_pic_save(QEMUFile *f, void *opaque) -{ - HeathrowPICS *s = (HeathrowPICS *)opaque; - - heathrow_pic_save_one(f, &s->pics[0]); - heathrow_pic_save_one(f, &s->pics[1]); -} - -static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s) -{ - qemu_get_be32s(f, &s->events); - qemu_get_be32s(f, &s->mask); - qemu_get_be32s(f, &s->levels); - qemu_get_be32s(f, &s->level_triggered); -} - -static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id) -{ - HeathrowPICS *s = (HeathrowPICS *)opaque; - - if (version_id != 1) - return -EINVAL; - - heathrow_pic_load_one(f, &s->pics[0]); - heathrow_pic_load_one(f, &s->pics[1]); - - return 0; -} +static const VMStateDescription vmstate_heathrow_pic = { + .name = "heathrow_pic", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1, + vmstate_heathrow_pic_one, HeathrowPIC), + VMSTATE_END_OF_LIST() + } +}; static void heathrow_pic_reset_one(HeathrowPIC *s) { @@ -223,8 +212,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index, *pmem_index = cpu_register_io_memory(pic_read, pic_write, s, DEVICE_LITTLE_ENDIAN); - register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save, - heathrow_pic_load, s); + vmstate_register(NULL, -1, &vmstate_heathrow_pic, s); qemu_register_reset(heathrow_pic_reset, s); return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); } From c0a93a9efabae3c9a8500bf2f14ffb06e313dc73 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 13:53:24 +0100 Subject: [PATCH 260/386] vmstate: port cuda Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/cuda.c | 118 ++++++++++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 71 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 37aa3f47fc..065c362aef 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -644,80 +644,56 @@ static CPUReadMemoryFunc * const cuda_read[] = { &cuda_readl, }; -static void cuda_save_timer(QEMUFile *f, CUDATimer *s) +static bool cuda_timer_exist(void *opaque, int version_id) { - qemu_put_be16s(f, &s->latch); - qemu_put_be16s(f, &s->counter_value); - qemu_put_sbe64s(f, &s->load_time); - qemu_put_sbe64s(f, &s->next_irq_time); - if (s->timer) - qemu_put_timer(f, s->timer); + CUDATimer *s = opaque; + + return s->timer != NULL; } -static void cuda_save(QEMUFile *f, void *opaque) -{ - CUDAState *s = (CUDAState *)opaque; +static const VMStateDescription vmstate_cuda_timer = { + .name = "cuda_timer", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT16(latch, CUDATimer), + VMSTATE_UINT16(counter_value, CUDATimer), + VMSTATE_INT64(load_time, CUDATimer), + VMSTATE_INT64(next_irq_time, CUDATimer), + VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist), + VMSTATE_END_OF_LIST() + } +}; - qemu_put_ubyte(f, s->b); - qemu_put_ubyte(f, s->a); - qemu_put_ubyte(f, s->dirb); - qemu_put_ubyte(f, s->dira); - qemu_put_ubyte(f, s->sr); - qemu_put_ubyte(f, s->acr); - qemu_put_ubyte(f, s->pcr); - qemu_put_ubyte(f, s->ifr); - qemu_put_ubyte(f, s->ier); - qemu_put_ubyte(f, s->anh); - qemu_put_sbe32s(f, &s->data_in_size); - qemu_put_sbe32s(f, &s->data_in_index); - qemu_put_sbe32s(f, &s->data_out_index); - qemu_put_ubyte(f, s->autopoll); - qemu_put_buffer(f, s->data_in, sizeof(s->data_in)); - qemu_put_buffer(f, s->data_out, sizeof(s->data_out)); - qemu_put_be32s(f, &s->tick_offset); - cuda_save_timer(f, &s->timers[0]); - cuda_save_timer(f, &s->timers[1]); -} - -static void cuda_load_timer(QEMUFile *f, CUDATimer *s) -{ - qemu_get_be16s(f, &s->latch); - qemu_get_be16s(f, &s->counter_value); - qemu_get_sbe64s(f, &s->load_time); - qemu_get_sbe64s(f, &s->next_irq_time); - if (s->timer) - qemu_get_timer(f, s->timer); -} - -static int cuda_load(QEMUFile *f, void *opaque, int version_id) -{ - CUDAState *s = (CUDAState *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->b = qemu_get_ubyte(f); - s->a = qemu_get_ubyte(f); - s->dirb = qemu_get_ubyte(f); - s->dira = qemu_get_ubyte(f); - s->sr = qemu_get_ubyte(f); - s->acr = qemu_get_ubyte(f); - s->pcr = qemu_get_ubyte(f); - s->ifr = qemu_get_ubyte(f); - s->ier = qemu_get_ubyte(f); - s->anh = qemu_get_ubyte(f); - qemu_get_sbe32s(f, &s->data_in_size); - qemu_get_sbe32s(f, &s->data_in_index); - qemu_get_sbe32s(f, &s->data_out_index); - s->autopoll = qemu_get_ubyte(f); - qemu_get_buffer(f, s->data_in, sizeof(s->data_in)); - qemu_get_buffer(f, s->data_out, sizeof(s->data_out)); - qemu_get_be32s(f, &s->tick_offset); - cuda_load_timer(f, &s->timers[0]); - cuda_load_timer(f, &s->timers[1]); - - return 0; -} +static const VMStateDescription vmstate_cuda = { + .name = "cuda", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(a, CUDAState), + VMSTATE_UINT8(b, CUDAState), + VMSTATE_UINT8(dira, CUDAState), + VMSTATE_UINT8(dirb, CUDAState), + VMSTATE_UINT8(sr, CUDAState), + VMSTATE_UINT8(acr, CUDAState), + VMSTATE_UINT8(pcr, CUDAState), + VMSTATE_UINT8(ifr, CUDAState), + VMSTATE_UINT8(ier, CUDAState), + VMSTATE_UINT8(anh, CUDAState), + VMSTATE_INT32(data_in_size, CUDAState), + VMSTATE_INT32(data_in_index, CUDAState), + VMSTATE_INT32(data_out_index, CUDAState), + VMSTATE_UINT8(autopoll, CUDAState), + VMSTATE_BUFFER(data_in, CUDAState), + VMSTATE_BUFFER(data_out, CUDAState), + VMSTATE_UINT32(tick_offset, CUDAState), + VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1, + vmstate_cuda_timer, CUDATimer), + VMSTATE_END_OF_LIST() + } +}; static void cuda_reset(void *opaque) { @@ -764,6 +740,6 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq) s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s); *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s, DEVICE_NATIVE_ENDIAN); - register_savevm(NULL, "cuda", -1, 1, cuda_save, cuda_load, s); + vmstate_register(NULL, -1, &vmstate_cuda, s); qemu_register_reset(cuda_reset, s); } From 10f85a2934eb0b59470015b1243acc9369f71fd0 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:07:01 +0100 Subject: [PATCH 261/386] vmstate: port stellaris gptm Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 84 +++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 11d618d87a..31aa102d14 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -279,64 +279,29 @@ static CPUWriteMemoryFunc * const gptm_writefn[] = { gptm_write }; -static void gptm_save(QEMUFile *f, void *opaque) -{ - gptm_state *s = (gptm_state *)opaque; - - qemu_put_be32(f, s->config); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->mode[1]); - qemu_put_be32(f, s->control); - qemu_put_be32(f, s->state); - qemu_put_be32(f, s->mask); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->mode[0]); - qemu_put_be32(f, s->load[0]); - qemu_put_be32(f, s->load[1]); - qemu_put_be32(f, s->match[0]); - qemu_put_be32(f, s->match[1]); - qemu_put_be32(f, s->prescale[0]); - qemu_put_be32(f, s->prescale[1]); - qemu_put_be32(f, s->match_prescale[0]); - qemu_put_be32(f, s->match_prescale[1]); - qemu_put_be32(f, s->rtc); - qemu_put_be64(f, s->tick[0]); - qemu_put_be64(f, s->tick[1]); - qemu_put_timer(f, s->timer[0]); - qemu_put_timer(f, s->timer[1]); -} - -static int gptm_load(QEMUFile *f, void *opaque, int version_id) -{ - gptm_state *s = (gptm_state *)opaque; - - if (version_id != 1) - return -EINVAL; - - s->config = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->mode[1] = qemu_get_be32(f); - s->control = qemu_get_be32(f); - s->state = qemu_get_be32(f); - s->mask = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->mode[0] = qemu_get_be32(f); - s->load[0] = qemu_get_be32(f); - s->load[1] = qemu_get_be32(f); - s->match[0] = qemu_get_be32(f); - s->match[1] = qemu_get_be32(f); - s->prescale[0] = qemu_get_be32(f); - s->prescale[1] = qemu_get_be32(f); - s->match_prescale[0] = qemu_get_be32(f); - s->match_prescale[1] = qemu_get_be32(f); - s->rtc = qemu_get_be32(f); - s->tick[0] = qemu_get_be64(f); - s->tick[1] = qemu_get_be64(f); - qemu_get_timer(f, s->timer[0]); - qemu_get_timer(f, s->timer[1]); - - return 0; -} +static const VMStateDescription vmstate_stellaris_gptm = { + .name = "stellaris_gptm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(config, gptm_state), + VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), + VMSTATE_UINT32(control, gptm_state), + VMSTATE_UINT32(state, gptm_state), + VMSTATE_UINT32(mask, gptm_state), + VMSTATE_UINT32(mode[0], gptm_state), + VMSTATE_UINT32(mode[0], gptm_state), + VMSTATE_UINT32_ARRAY(load, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match, gptm_state, 2), + VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), + VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2), + VMSTATE_UINT32(rtc, gptm_state), + VMSTATE_INT64_ARRAY(tick, gptm_state, 2), + VMSTATE_TIMER_ARRAY(timer, gptm_state, 2), + VMSTATE_END_OF_LIST() + } +}; static int stellaris_gptm_init(SysBusDevice *dev) { @@ -354,8 +319,7 @@ static int stellaris_gptm_init(SysBusDevice *dev) s->opaque[0] = s->opaque[1] = s; s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]); s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]); - register_savevm(&dev->qdev, "stellaris_gptm", -1, 1, - gptm_save, gptm_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s); return 0; } From 9f5dfe298bbbf539b7a4ee802f274adff52b8648 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:14:56 +0100 Subject: [PATCH 262/386] vmstate: port pxa2xx_i2s Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx.c | 53 ++++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 9b95e2c8e2..96932ef829 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1748,39 +1748,23 @@ static CPUWriteMemoryFunc * const pxa2xx_i2s_writefn[] = { pxa2xx_i2s_write, }; -static void pxa2xx_i2s_save(QEMUFile *f, void *opaque) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - qemu_put_be32s(f, &s->control[0]); - qemu_put_be32s(f, &s->control[1]); - qemu_put_be32s(f, &s->status); - qemu_put_be32s(f, &s->mask); - qemu_put_be32s(f, &s->clk); - - qemu_put_be32(f, s->enable); - qemu_put_be32(f, s->rx_len); - qemu_put_be32(f, s->tx_len); - qemu_put_be32(f, s->fifo_len); -} - -static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; - - qemu_get_be32s(f, &s->control[0]); - qemu_get_be32s(f, &s->control[1]); - qemu_get_be32s(f, &s->status); - qemu_get_be32s(f, &s->mask); - qemu_get_be32s(f, &s->clk); - - s->enable = qemu_get_be32(f); - s->rx_len = qemu_get_be32(f); - s->tx_len = qemu_get_be32(f); - s->fifo_len = qemu_get_be32(f); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_i2s = { + .name = "pxa2xx_i2s", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), + VMSTATE_UINT32(status, PXA2xxI2SState), + VMSTATE_UINT32(mask, PXA2xxI2SState), + VMSTATE_UINT32(clk, PXA2xxI2SState), + VMSTATE_INT32(enable, PXA2xxI2SState), + VMSTATE_INT32(rx_len, PXA2xxI2SState), + VMSTATE_INT32(tx_len, PXA2xxI2SState), + VMSTATE_INT32(fifo_len, PXA2xxI2SState), + VMSTATE_END_OF_LIST() + } +}; static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) { @@ -1822,8 +1806,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(base, 0x100000, iomemtype); - register_savevm(NULL, "pxa2xx_i2s", base, 0, - pxa2xx_i2s_save, pxa2xx_i2s_load, s); + vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s); return s; } From ae1f90de0664475cd1f12c5b229f0cb99bd8fcc3 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:31:14 +0100 Subject: [PATCH 263/386] vmstate: port pxa2xx_cm Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 96932ef829..a824c22e65 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -227,29 +227,18 @@ static CPUWriteMemoryFunc * const pxa2xx_cm_writefn[] = { pxa2xx_cm_write, }; -static void pxa2xx_cm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 4; i ++) - qemu_put_be32s(f, &s->cm_regs[i]); - qemu_put_be32s(f, &s->clkcfg); - qemu_put_be32s(f, &s->pmnc); -} - -static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 4; i ++) - qemu_get_be32s(f, &s->cm_regs[i]); - qemu_get_be32s(f, &s->clkcfg); - qemu_get_be32s(f, &s->pmnc); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_cm = { + .name = "pxa2xx_cm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), + VMSTATE_UINT32(clkcfg, PXA2xxState), + VMSTATE_UINT32(pmnc, PXA2xxState), + VMSTATE_END_OF_LIST() + } +}; static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) { @@ -2171,7 +2160,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2307,7 +2296,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); From d102d49545273661016f66646a9f56ee52b2aee5 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:36:57 +0100 Subject: [PATCH 264/386] vmstate: port pxa2xx_mm Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index a824c22e65..e174c20d47 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -516,25 +516,16 @@ static CPUWriteMemoryFunc * const pxa2xx_mm_writefn[] = { pxa2xx_mm_write, }; -static void pxa2xx_mm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x1a; i ++) - qemu_put_be32s(f, &s->mm_regs[i]); -} - -static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x1a; i ++) - qemu_get_be32s(f, &s->mm_regs[i]); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_mm = { + .name = "pxa2xx_mm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), + VMSTATE_END_OF_LIST() + } +}; /* Synchronous Serial Ports */ typedef struct { @@ -2171,7 +2162,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, @@ -2307,7 +2298,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); - register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, From f0ab24ce69347f71a5952b105777bfe22665259a Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:54:38 +0100 Subject: [PATCH 265/386] vmstate: port pxa2xx_pm Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index e174c20d47..ac5d95d718 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -146,25 +146,16 @@ static CPUWriteMemoryFunc * const pxa2xx_pm_writefn[] = { pxa2xx_pm_write, }; -static void pxa2xx_pm_save(QEMUFile *f, void *opaque) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x40; i ++) - qemu_put_be32s(f, &s->pm_regs[i]); -} - -static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxState *s = (PXA2xxState *) opaque; - int i; - - for (i = 0; i < 0x40; i ++) - qemu_get_be32s(f, &s->pm_regs[i]); - - return 0; -} +static const VMStateDescription vmstate_pxa2xx_pm = { + .name = "pxa2xx_pm", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), + VMSTATE_END_OF_LIST() + } +}; #define CCCR 0x00 /* Core Clock Configuration register */ #define CKEN 0x04 /* Clock Enable register */ @@ -2168,7 +2159,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); - register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i); @@ -2304,7 +2295,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); - register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s); for (i = 0; pxa255_ssp[i].io_base; i ++); s->ssp = (SSIBus **)qemu_mallocz(sizeof(SSIBus *) * i); From e0433ecc6ead41f1581113eb892f744235f12120 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 15:29:42 +0100 Subject: [PATCH 266/386] vmstate: port ppce500_pci Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/ppce500_pci.c | 87 ++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 2fc879236a..83a20e4620 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -216,56 +216,49 @@ static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static void ppce500_pci_save(QEMUFile *f, void *opaque) -{ - PPCE500PCIState *controller = opaque; - int i; - - pci_device_save(controller->pci_dev, f); - - for (i = 0; i < PPCE500_PCI_NR_POBS; i++) { - qemu_put_be32s(f, &controller->pob[i].potar); - qemu_put_be32s(f, &controller->pob[i].potear); - qemu_put_be32s(f, &controller->pob[i].powbar); - qemu_put_be32s(f, &controller->pob[i].powar); +static const VMStateDescription vmstate_pci_outbound = { + .name = "pci_outbound", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(potar, struct pci_outbound), + VMSTATE_UINT32(potear, struct pci_outbound), + VMSTATE_UINT32(powbar, struct pci_outbound), + VMSTATE_UINT32(powar, struct pci_outbound), + VMSTATE_END_OF_LIST() } +}; - for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) { - qemu_put_be32s(f, &controller->pib[i].pitar); - qemu_put_be32s(f, &controller->pib[i].piwbar); - qemu_put_be32s(f, &controller->pib[i].piwbear); - qemu_put_be32s(f, &controller->pib[i].piwar); +static const VMStateDescription vmstate_pci_inbound = { + .name = "pci_inbound", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(pitar, struct pci_inbound), + VMSTATE_UINT32(piwbar, struct pci_inbound), + VMSTATE_UINT32(piwbear, struct pci_inbound), + VMSTATE_UINT32(piwar, struct pci_inbound), + VMSTATE_END_OF_LIST() } - qemu_put_be32s(f, &controller->gasket_time); -} +}; -static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id) -{ - PPCE500PCIState *controller = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - pci_device_load(controller->pci_dev, f); - - for (i = 0; i < PPCE500_PCI_NR_POBS; i++) { - qemu_get_be32s(f, &controller->pob[i].potar); - qemu_get_be32s(f, &controller->pob[i].potear); - qemu_get_be32s(f, &controller->pob[i].powbar); - qemu_get_be32s(f, &controller->pob[i].powar); +static const VMStateDescription vmstate_ppce500_pci = { + .name = "ppce500_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState), + VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1, + vmstate_pci_outbound, struct pci_outbound), + VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1, + vmstate_pci_outbound, struct pci_inbound), + VMSTATE_UINT32(gasket_time, PPCE500PCIState), + VMSTATE_END_OF_LIST() } - - for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) { - qemu_get_be32s(f, &controller->pib[i].pitar); - qemu_get_be32s(f, &controller->pib[i].piwbar); - qemu_get_be32s(f, &controller->pib[i].piwbear); - qemu_get_be32s(f, &controller->pib[i].piwar); - } - qemu_get_be32s(f, &controller->gasket_time); - - return 0; -} +}; PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) { @@ -314,8 +307,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) PCIE500_REG_SIZE, index); /* XXX load/save code not tested. */ - register_savevm(&d->qdev, "ppce500_pci", ppce500_pci_id++, - 1, ppce500_pci_save, ppce500_pci_load, controller); + vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci, + controller); return controller->pci_state.bus; From b605f22212875d95e9c5f82369d48fe5cd8d10e4 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 17:27:49 +0100 Subject: [PATCH 267/386] vmstate: port ppc4xx_pci Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/ppc4xx_pci.c | 80 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index f62f1f91d5..299473c4b5 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -285,50 +285,48 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pci_irqs[irq_num], level); } -static void ppc4xx_pci_save(QEMUFile *f, void *opaque) -{ - PPC4xxPCIState *controller = opaque; - int i; - - pci_device_save(controller->pci_dev, f); - - for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) { - qemu_put_be32s(f, &controller->pmm[i].la); - qemu_put_be32s(f, &controller->pmm[i].ma); - qemu_put_be32s(f, &controller->pmm[i].pcila); - qemu_put_be32s(f, &controller->pmm[i].pciha); +static const VMStateDescription vmstate_pci_master_map = { + .name = "pci_master_map", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(la, struct PCIMasterMap), + VMSTATE_UINT32(ma, struct PCIMasterMap), + VMSTATE_UINT32(pcila, struct PCIMasterMap), + VMSTATE_UINT32(pciha, struct PCIMasterMap), + VMSTATE_END_OF_LIST() } +}; - for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) { - qemu_put_be32s(f, &controller->ptm[i].ms); - qemu_put_be32s(f, &controller->ptm[i].la); +static const VMStateDescription vmstate_pci_target_map = { + .name = "pci_target_map", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ms, struct PCITargetMap), + VMSTATE_UINT32(la, struct PCITargetMap), + VMSTATE_END_OF_LIST() } -} +}; -static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id) -{ - PPC4xxPCIState *controller = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - pci_device_load(controller->pci_dev, f); - - for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) { - qemu_get_be32s(f, &controller->pmm[i].la); - qemu_get_be32s(f, &controller->pmm[i].ma); - qemu_get_be32s(f, &controller->pmm[i].pcila); - qemu_get_be32s(f, &controller->pmm[i].pciha); +static const VMStateDescription vmstate_ppc4xx_pci = { + .name = "ppc4xx_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState), + VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1, + vmstate_pci_master_map, + struct PCIMasterMap), + VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1, + vmstate_pci_target_map, + struct PCITargetMap), + VMSTATE_END_OF_LIST() } - - for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) { - qemu_get_be32s(f, &controller->ptm[i].ms); - qemu_get_be32s(f, &controller->ptm[i].la); - } - - return 0; -} +}; /* XXX Interrupt acknowledge cycles not supported. */ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], @@ -381,8 +379,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], qemu_register_reset(ppc4xx_pci_reset, controller); /* XXX load/save code not tested. */ - register_savevm(&controller->pci_dev->qdev, "ppc4xx_pci", ppc4xx_pci_id++, - 1, ppc4xx_pci_save, ppc4xx_pci_load, controller); + vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++, + &vmstate_ppc4xx_pci, controller); return controller->pci_state.bus; From 80a526802c39e95ea0e65b879c91f240185889f2 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 00:37:35 +0100 Subject: [PATCH 268/386] vmstate: port syborg_pointer Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/syborg_pointer.c | 73 +++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c index a886888467..2f99707040 100644 --- a/hw/syborg_pointer.c +++ b/hw/syborg_pointer.c @@ -152,52 +152,36 @@ static void syborg_pointer_event(void *opaque, int dx, int dy, int dz, syborg_pointer_update(s); } -static void syborg_pointer_save(QEMUFile *f, void *opaque) -{ - SyborgPointerState *s = (SyborgPointerState *)opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->absolute); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->event_fifo[i].x); - qemu_put_be32(f, s->event_fifo[i].y); - qemu_put_be32(f, s->event_fifo[i].z); - qemu_put_be32(f, s->event_fifo[i].pointer_buttons); +static const VMStateDescription vmstate_event_data = { + .name = "dbma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_INT32(x, event_data), + VMSTATE_INT32(y, event_data), + VMSTATE_INT32(z, event_data), + VMSTATE_INT32(pointer_buttons, event_data), + VMSTATE_END_OF_LIST() } -} +}; -static int syborg_pointer_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgPointerState *s = (SyborgPointerState *)opaque; - uint32_t val; - int i; - - if (version_id != 1) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->fifo_size) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->absolute) - return -EINVAL; - - s->int_enabled = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->event_fifo[i].x = qemu_get_be32(f); - s->event_fifo[i].y = qemu_get_be32(f); - s->event_fifo[i].z = qemu_get_be32(f); - s->event_fifo[i].pointer_buttons = qemu_get_be32(f); +static const VMStateDescription vmstate_syborg_pointer = { + .name = "syborg_pointer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState), + VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState), + VMSTATE_INT32(int_enabled, SyborgPointerState), + VMSTATE_INT32(read_pos, SyborgPointerState), + VMSTATE_INT32(read_count, SyborgPointerState), + VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size, + 1, vmstate_event_data, event_data), + VMSTATE_END_OF_LIST() } - return 0; -} +}; static int syborg_pointer_init(SysBusDevice *dev) { @@ -219,8 +203,7 @@ static int syborg_pointer_init(SysBusDevice *dev) qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute, "Syborg Pointer"); - register_savevm(&dev->qdev, "syborg_pointer", -1, 1, - syborg_pointer_save, syborg_pointer_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s); return 0; } From cf1d31dc5cd3a98199af6169d80a1a6d191d8e55 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:27:58 +0100 Subject: [PATCH 269/386] vmstate: port stellaris_adc Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 89 +++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 31aa102d14..58aec190ec 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1057,60 +1057,40 @@ static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = { stellaris_adc_write }; -static void stellaris_adc_save(QEMUFile *f, void *opaque) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int i; - int j; - - qemu_put_be32(f, s->actss); - qemu_put_be32(f, s->ris); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->emux); - qemu_put_be32(f, s->ostat); - qemu_put_be32(f, s->ustat); - qemu_put_be32(f, s->sspri); - qemu_put_be32(f, s->sac); - for (i = 0; i < 4; i++) { - qemu_put_be32(f, s->fifo[i].state); - for (j = 0; j < 16; j++) { - qemu_put_be32(f, s->fifo[i].data[j]); - } - qemu_put_be32(f, s->ssmux[i]); - qemu_put_be32(f, s->ssctl[i]); +static const VMStateDescription vmstate_stellaris_adc = { + .name = "stellaris_adc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(actss, stellaris_adc_state), + VMSTATE_UINT32(ris, stellaris_adc_state), + VMSTATE_UINT32(im, stellaris_adc_state), + VMSTATE_UINT32(emux, stellaris_adc_state), + VMSTATE_UINT32(ostat, stellaris_adc_state), + VMSTATE_UINT32(ustat, stellaris_adc_state), + VMSTATE_UINT32(sspri, stellaris_adc_state), + VMSTATE_UINT32(sac, stellaris_adc_state), + VMSTATE_UINT32(fifo[0].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[0], stellaris_adc_state), + VMSTATE_UINT32(ssctl[0], stellaris_adc_state), + VMSTATE_UINT32(fifo[1].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[1], stellaris_adc_state), + VMSTATE_UINT32(ssctl[1], stellaris_adc_state), + VMSTATE_UINT32(fifo[2].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[2], stellaris_adc_state), + VMSTATE_UINT32(ssctl[2], stellaris_adc_state), + VMSTATE_UINT32(fifo[3].state, stellaris_adc_state), + VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16), + VMSTATE_UINT32(ssmux[3], stellaris_adc_state), + VMSTATE_UINT32(ssctl[3], stellaris_adc_state), + VMSTATE_UINT32(noise, stellaris_adc_state), + VMSTATE_END_OF_LIST() } - qemu_put_be32(f, s->noise); -} - -static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_adc_state *s = (stellaris_adc_state *)opaque; - int i; - int j; - - if (version_id != 1) - return -EINVAL; - - s->actss = qemu_get_be32(f); - s->ris = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->emux = qemu_get_be32(f); - s->ostat = qemu_get_be32(f); - s->ustat = qemu_get_be32(f); - s->sspri = qemu_get_be32(f); - s->sac = qemu_get_be32(f); - for (i = 0; i < 4; i++) { - s->fifo[i].state = qemu_get_be32(f); - for (j = 0; j < 16; j++) { - s->fifo[i].data[j] = qemu_get_be32(f); - } - s->ssmux[i] = qemu_get_be32(f); - s->ssctl[i] = qemu_get_be32(f); - } - s->noise = qemu_get_be32(f); - - return 0; -} +}; static int stellaris_adc_init(SysBusDevice *dev) { @@ -1128,8 +1108,7 @@ static int stellaris_adc_init(SysBusDevice *dev) sysbus_init_mmio(dev, 0x1000, iomemtype); stellaris_adc_reset(s); qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1); - register_savevm(&dev->qdev, "stellaris_adc", -1, 1, - stellaris_adc_save, stellaris_adc_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s); return 0; } From 8dc5907090fd35fd80e643534ab02092b73ec9cd Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 02:10:53 +0100 Subject: [PATCH 270/386] vmstate: port syborg_serial Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/syborg_serial.c | 60 ++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c index 34ce076d45..df2950fe88 100644 --- a/hw/syborg_serial.c +++ b/hw/syborg_serial.c @@ -273,47 +273,24 @@ static CPUWriteMemoryFunc * const syborg_serial_writefn[] = { syborg_serial_write }; -static void syborg_serial_save(QEMUFile *f, void *opaque) -{ - SyborgSerialState *s = opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->int_enable); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - qemu_put_be32(f, s->dma_tx_ptr); - qemu_put_be32(f, s->dma_rx_ptr); - qemu_put_be32(f, s->dma_rx_size); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->read_fifo[i]); +static const VMStateDescription vmstate_syborg_serial = { + .name = "syborg_serial", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgSerialState), + VMSTATE_UINT32(int_enable, SyborgSerialState), + VMSTATE_INT32(read_pos, SyborgSerialState), + VMSTATE_INT32(read_count, SyborgSerialState), + VMSTATE_UINT32(dma_tx_ptr, SyborgSerialState), + VMSTATE_UINT32(dma_rx_ptr, SyborgSerialState), + VMSTATE_UINT32(dma_rx_size, SyborgSerialState), + VMSTATE_VARRAY_UINT32(read_fifo, SyborgSerialState, fifo_size, 1, + vmstate_info_uint32, uint32), + VMSTATE_END_OF_LIST() } -} - -static int syborg_serial_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgSerialState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - i = qemu_get_be32(f); - if (s->fifo_size != i) - return -EINVAL; - - s->int_enable = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - s->dma_tx_ptr = qemu_get_be32(f); - s->dma_rx_ptr = qemu_get_be32(f); - s->dma_rx_size = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->read_fifo[i] = qemu_get_be32(f); - } - - return 0; -} +}; static int syborg_serial_init(SysBusDevice *dev) { @@ -336,8 +313,6 @@ static int syborg_serial_init(SysBusDevice *dev) } s->read_fifo = qemu_mallocz(s->fifo_size * sizeof(s->read_fifo[0])); - register_savevm(&dev->qdev, "syborg_serial", -1, 1, - syborg_serial_save, syborg_serial_load, s); return 0; } @@ -345,6 +320,7 @@ static SysBusDeviceInfo syborg_serial_info = { .init = syborg_serial_init, .qdev.name = "syborg,serial", .qdev.size = sizeof(SyborgSerialState), + .qdev.vmsd = &vmstate_syborg_serial, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("fifo-size", SyborgSerialState, fifo_size, 16), DEFINE_PROP_END_OF_LIST(), From 0c067bbb26e3dae03807ba7eeb4bfd697f5f01c4 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Wed, 1 Dec 2010 22:51:07 +0100 Subject: [PATCH 271/386] vmstate: port syborg_keyboard Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/syborg_keyboard.c | 57 +++++++++++++------------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c index d295e99ebd..706a03966f 100644 --- a/hw/syborg_keyboard.c +++ b/hw/syborg_keyboard.c @@ -51,11 +51,11 @@ enum { typedef struct { SysBusDevice busdev; - int int_enabled; + uint32_t int_enabled; int extension_bit; uint32_t fifo_size; uint32_t *key_fifo; - int read_pos, read_count; + uint32_t read_pos, read_count; qemu_irq irq; } SyborgKeyboardState; @@ -165,43 +165,21 @@ static void syborg_keyboard_event(void *opaque, int keycode) syborg_keyboard_update(s); } -static void syborg_keyboard_save(QEMUFile *f, void *opaque) -{ - SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; - int i; - - qemu_put_be32(f, s->fifo_size); - qemu_put_be32(f, s->int_enabled); - qemu_put_be32(f, s->extension_bit); - qemu_put_be32(f, s->read_pos); - qemu_put_be32(f, s->read_count); - for (i = 0; i < s->fifo_size; i++) { - qemu_put_be32(f, s->key_fifo[i]); +static const VMStateDescription vmstate_syborg_keyboard = { + .name = "syborg_keyboard", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState), + VMSTATE_UINT32(int_enabled, SyborgKeyboardState), + VMSTATE_UINT32(read_pos, SyborgKeyboardState), + VMSTATE_UINT32(read_count, SyborgKeyboardState), + VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1, + vmstate_info_uint32, uint32), + VMSTATE_END_OF_LIST() } -} - -static int syborg_keyboard_load(QEMUFile *f, void *opaque, int version_id) -{ - SyborgKeyboardState *s = (SyborgKeyboardState *)opaque; - uint32_t val; - int i; - - if (version_id != 1) - return -EINVAL; - - val = qemu_get_be32(f); - if (val != s->fifo_size) - return -EINVAL; - - s->int_enabled = qemu_get_be32(f); - s->extension_bit = qemu_get_be32(f); - s->read_pos = qemu_get_be32(f); - s->read_count = qemu_get_be32(f); - for (i = 0; i < s->fifo_size; i++) { - s->key_fifo[i] = qemu_get_be32(f); - } - return 0; -} +}; static int syborg_keyboard_init(SysBusDevice *dev) { @@ -221,8 +199,7 @@ static int syborg_keyboard_init(SysBusDevice *dev) qemu_add_kbd_event_handler(syborg_keyboard_event, s); - register_savevm(&dev->qdev, "syborg_keyboard", -1, 1, - syborg_keyboard_save, syborg_keyboard_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s); return 0; } From 4483c7ac31f76e91fe69bf7f2346e77a10ac427e Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 02:36:38 +0100 Subject: [PATCH 272/386] vmstate: port stellaris gamepad Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris_input.c | 50 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 16aae96f2f..06c5f9d955 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -13,7 +13,7 @@ typedef struct { qemu_irq irq; int keycode; - int pressed; + uint8_t pressed; } gamepad_button; typedef struct { @@ -47,30 +47,29 @@ static void stellaris_gamepad_put_key(void * opaque, int keycode) s->extension = 0; } -static void stellaris_gamepad_save(QEMUFile *f, void *opaque) -{ - gamepad_state *s = (gamepad_state *)opaque; - int i; +static const VMStateDescription vmstate_stellaris_button = { + .name = "stellaris_button", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(pressed, gamepad_button), + VMSTATE_END_OF_LIST() + } +}; - qemu_put_be32(f, s->extension); - for (i = 0; i < s->num_buttons; i++) - qemu_put_byte(f, s->buttons[i].pressed); -} - -static int stellaris_gamepad_load(QEMUFile *f, void *opaque, int version_id) -{ - gamepad_state *s = (gamepad_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->extension = qemu_get_be32(f); - for (i = 0; i < s->num_buttons; i++) - s->buttons[i].pressed = qemu_get_byte(f); - - return 0; -} +static const VMStateDescription vmstate_stellaris_gamepad = { + .name = "stellaris_gamepad", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(extension, gamepad_state), + VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0, + vmstate_stellaris_button, gamepad_button), + VMSTATE_END_OF_LIST() + } +}; /* Returns an array 5 ouput slots. */ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) @@ -86,6 +85,5 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) } s->num_buttons = n; qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); - register_savevm(NULL, "stellaris_gamepad", -1, 1, - stellaris_gamepad_save, stellaris_gamepad_load, s); + vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s); } From dd8a4dcda4c985cfa313cfe70ab0385c07341480 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 14:07:44 +0100 Subject: [PATCH 273/386] vmstate: stellaris use unused for placeholder entries Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/stellaris.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 58aec190ec..ac9fcc1f38 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -290,8 +290,7 @@ static const VMStateDescription vmstate_stellaris_gptm = { VMSTATE_UINT32(control, gptm_state), VMSTATE_UINT32(state, gptm_state), VMSTATE_UINT32(mask, gptm_state), - VMSTATE_UINT32(mode[0], gptm_state), - VMSTATE_UINT32(mode[0], gptm_state), + VMSTATE_UNUSED(8), VMSTATE_UINT32_ARRAY(load, gptm_state, 2), VMSTATE_UINT32_ARRAY(match, gptm_state, 2), VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2), From 2b7251e0f2e9414f2440e9b485e95f337b869d53 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 15:56:04 +0100 Subject: [PATCH 274/386] pxa2xx_lcd: name anonymous struct Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx_lcd.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 5b2b07e02c..9a193474e0 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -15,6 +15,20 @@ #include "sysemu.h" #include "framebuffer.h" +struct DMAChannel { + target_phys_addr_t branch; + int up; + uint8_t palette[1024]; + uint8_t pbuffer[1024]; + void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, + int *miny, int *maxy); + + target_phys_addr_t descriptor; + target_phys_addr_t source; + uint32_t id; + uint32_t command; +}; + struct PXA2xxLCDState { qemu_irq irq; int irqlevel; @@ -50,19 +64,7 @@ struct PXA2xxLCDState { uint32_t liidr; uint8_t bscntr; - struct { - target_phys_addr_t branch; - int up; - uint8_t palette[1024]; - uint8_t pbuffer[1024]; - void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, - int *miny, int *maxy); - - target_phys_addr_t descriptor; - target_phys_addr_t source; - uint32_t id; - uint32_t command; - } dma_ch[7]; + struct DMAChannel dma_ch[7]; qemu_irq vsync_cb; int orientation; From 469954090ff1a11285a29c4e03df09c128ebc5bc Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 16:01:57 +0100 Subject: [PATCH 275/386] pxa2xx_lcd: up field is used as a bool and migrated as an uint8_t Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx_lcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 9a193474e0..55e95be766 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -17,7 +17,7 @@ struct DMAChannel { target_phys_addr_t branch; - int up; + uint8_t up; uint8_t palette[1024]; uint8_t pbuffer[1024]; void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, From 99838363ba37553321bc6a0274b08c4af65541ea Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 16:11:24 +0100 Subject: [PATCH 276/386] vmstate: port pxa2xx_lcd Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/pxa2xx_lcd.c | 110 +++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 55e95be766..e5248023f8 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -833,74 +833,26 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle) pxa2xx_lcdc_resize(s); } -static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque) -{ - PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - int i; - - qemu_put_be32(f, s->irqlevel); - qemu_put_be32(f, s->transp); - - for (i = 0; i < 6; i ++) - qemu_put_be32s(f, &s->control[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->status[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->ovl1c[i]); - for (i = 0; i < 2; i ++) - qemu_put_be32s(f, &s->ovl2c[i]); - qemu_put_be32s(f, &s->ccr); - qemu_put_be32s(f, &s->cmdcr); - qemu_put_be32s(f, &s->trgbr); - qemu_put_be32s(f, &s->tcr); - qemu_put_be32s(f, &s->liidr); - qemu_put_8s(f, &s->bscntr); - - for (i = 0; i < 7; i ++) { - qemu_put_betl(f, s->dma_ch[i].branch); - qemu_put_byte(f, s->dma_ch[i].up); - qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); - - qemu_put_betl(f, s->dma_ch[i].descriptor); - qemu_put_betl(f, s->dma_ch[i].source); - qemu_put_be32s(f, &s->dma_ch[i].id); - qemu_put_be32s(f, &s->dma_ch[i].command); +static const VMStateDescription vmstate_dma_channel = { + .name = "dma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINTTL(branch, struct DMAChannel), + VMSTATE_UINT8(up, struct DMAChannel), + VMSTATE_BUFFER(pbuffer, struct DMAChannel), + VMSTATE_UINTTL(descriptor, struct DMAChannel), + VMSTATE_UINTTL(source, struct DMAChannel), + VMSTATE_UINT32(id, struct DMAChannel), + VMSTATE_UINT32(command, struct DMAChannel), + VMSTATE_END_OF_LIST() } -} +}; -static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) +static int pxa2xx_lcdc_post_load(void *opaque, int version_id) { - PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - int i; - - s->irqlevel = qemu_get_be32(f); - s->transp = qemu_get_be32(f); - - for (i = 0; i < 6; i ++) - qemu_get_be32s(f, &s->control[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->status[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->ovl1c[i]); - for (i = 0; i < 2; i ++) - qemu_get_be32s(f, &s->ovl2c[i]); - qemu_get_be32s(f, &s->ccr); - qemu_get_be32s(f, &s->cmdcr); - qemu_get_be32s(f, &s->trgbr); - qemu_get_be32s(f, &s->tcr); - qemu_get_be32s(f, &s->liidr); - qemu_get_8s(f, &s->bscntr); - - for (i = 0; i < 7; i ++) { - s->dma_ch[i].branch = qemu_get_betl(f); - s->dma_ch[i].up = qemu_get_byte(f); - qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); - - s->dma_ch[i].descriptor = qemu_get_betl(f); - s->dma_ch[i].source = qemu_get_betl(f); - qemu_get_be32s(f, &s->dma_ch[i].id); - qemu_get_be32s(f, &s->dma_ch[i].command); - } + PXA2xxLCDState *s = opaque; s->bpp = LCCR3_BPP(s->control[3]); s->xres = s->yres = s->pal_for = -1; @@ -908,6 +860,31 @@ static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static const VMStateDescription vmstate_pxa2xx_lcdc = { + .name = "pxa2xx_lcdc", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = pxa2xx_lcdc_post_load, + .fields = (VMStateField[]) { + VMSTATE_INT32(irqlevel, PXA2xxLCDState), + VMSTATE_INT32(transp, PXA2xxLCDState), + VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6), + VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2), + VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2), + VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2), + VMSTATE_UINT32(ccr, PXA2xxLCDState), + VMSTATE_UINT32(cmdcr, PXA2xxLCDState), + VMSTATE_UINT32(trgbr, PXA2xxLCDState), + VMSTATE_UINT32(tcr, PXA2xxLCDState), + VMSTATE_UINT32(liidr, PXA2xxLCDState), + VMSTATE_UINT8(bscntr, PXA2xxLCDState), + VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0, + vmstate_dma_channel, struct DMAChannel), + VMSTATE_END_OF_LIST() + } +}; + #define BITS 8 #include "pxa2xx_template.h" #define BITS 15 @@ -972,8 +949,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq) exit(1); } - register_savevm(NULL, "pxa2xx_lcdc", 0, 0, - pxa2xx_lcdc_save, pxa2xx_lcdc_load, s); + vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s); return s; } From 54d970d134f3bf820f51266113f1b7489b794fe2 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:03:10 +0100 Subject: [PATCH 277/386] max111x: input field is only used as uint8_t Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/max111x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/max111x.c b/hw/max111x.c index 2844665ba3..3adc3e4d2f 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -15,7 +15,7 @@ typedef struct { uint8_t tb1, rb2, rb3; int cycle; - int input[8]; + uint8_t input[8]; int inputs, com; } MAX111xState; From 38cb3aa9b4d5b9085ff4635415b6d3c673e2dc7d Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:03:59 +0100 Subject: [PATCH 278/386] vmstate: port max111x Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/max111x.c | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/hw/max111x.c b/hw/max111x.c index 3adc3e4d2f..70cd1af24f 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -94,36 +94,22 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) return max111x_read(s); } -static void max111x_save(QEMUFile *f, void *opaque) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_put_8s(f, &s->tb1); - qemu_put_8s(f, &s->rb2); - qemu_put_8s(f, &s->rb3); - qemu_put_be32(f, s->inputs); - qemu_put_be32(f, s->com); - for (i = 0; i < s->inputs; i ++) - qemu_put_byte(f, s->input[i]); -} - -static int max111x_load(QEMUFile *f, void *opaque, int version_id) -{ - MAX111xState *s = (MAX111xState *) opaque; - int i; - - qemu_get_8s(f, &s->tb1); - qemu_get_8s(f, &s->rb2); - qemu_get_8s(f, &s->rb3); - if (s->inputs != qemu_get_be32(f)) - return -EINVAL; - s->com = qemu_get_be32(f); - for (i = 0; i < s->inputs; i ++) - s->input[i] = qemu_get_byte(f); - - return 0; -} +static const VMStateDescription vmstate_max111x = { + .name = "max111x", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(tb1, MAX111xState), + VMSTATE_UINT8(rb2, MAX111xState), + VMSTATE_UINT8(rb3, MAX111xState), + VMSTATE_INT32_EQUAL(inputs, MAX111xState), + VMSTATE_INT32(com, MAX111xState), + VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs, + vmstate_info_uint8, uint8_t), + VMSTATE_END_OF_LIST() + } +}; static int max111x_init(SSISlave *dev, int inputs) { @@ -143,8 +129,7 @@ static int max111x_init(SSISlave *dev, int inputs) s->input[7] = 0x80; s->com = 0; - register_savevm(&dev->qdev, "max111x", -1, 0, - max111x_save, max111x_load, s); + vmstate_register(&dev->qdev, -1, &vmstate_max111x, s); return 0; } From 51db57f7e8ef46743cb3380bfd430d3ee1877866 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:39:22 +0100 Subject: [PATCH 279/386] nand: pin values are uint8_t Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/flash.h | 4 ++-- hw/nand.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/flash.h b/hw/flash.h index d7d103e66f..c22e1a922c 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -21,8 +21,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, typedef struct NANDFlashState NANDFlashState; NANDFlashState *nand_init(int manf_id, int chip_id); void nand_done(NANDFlashState *s); -void nand_setpins(NANDFlashState *s, - int cle, int ale, int ce, int wp, int gnd); +void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale, + uint8_t ce, uint8_t wp, uint8_t gnd); void nand_getpins(NANDFlashState *s, int *rb); void nand_setio(NANDFlashState *s, uint8_t value); uint8_t nand_getio(NANDFlashState *s); diff --git a/hw/nand.c b/hw/nand.c index f414aa139b..9f978d875a 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -52,7 +52,7 @@ struct NANDFlashState { BlockDriverState *bdrv; int mem_oob; - int cle, ale, ce, wp, gnd; + uint8_t cle, ale, ce, wp, gnd; uint8_t io[MAX_PAGE + MAX_OOB + 0x400]; uint8_t *ioaddr; @@ -329,8 +329,8 @@ static int nand_load(QEMUFile *f, void *opaque, int version_id) * * CE, WP and R/B are active low. */ -void nand_setpins(NANDFlashState *s, - int cle, int ale, int ce, int wp, int gnd) +void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale, + uint8_t ce, uint8_t wp, uint8_t gnd) { s->cle = cle; s->ale = ale; From 7b9a3d86c1c5ed508ab07b536f44a308732b9069 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:50:10 +0100 Subject: [PATCH 280/386] vmstate: port nand Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/nand.c | 73 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/hw/nand.c b/hw/nand.c index 9f978d875a..37e51d7140 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -66,6 +66,8 @@ struct NANDFlashState { void (*blk_write)(NANDFlashState *s); void (*blk_erase)(NANDFlashState *s); void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset); + + uint32_t ioaddr_vmstate; }; # define NAND_NO_AUTOINCR 0x00000001 @@ -281,48 +283,51 @@ static void nand_command(NANDFlashState *s) } } -static void nand_save(QEMUFile *f, void *opaque) +static void nand_pre_save(void *opaque) { - NANDFlashState *s = (NANDFlashState *) opaque; - qemu_put_byte(f, s->cle); - qemu_put_byte(f, s->ale); - qemu_put_byte(f, s->ce); - qemu_put_byte(f, s->wp); - qemu_put_byte(f, s->gnd); - qemu_put_buffer(f, s->io, sizeof(s->io)); - qemu_put_be32(f, s->ioaddr - s->io); - qemu_put_be32(f, s->iolen); + NANDFlashState *s = opaque; - qemu_put_be32s(f, &s->cmd); - qemu_put_be32s(f, &s->addr); - qemu_put_be32(f, s->addrlen); - qemu_put_be32(f, s->status); - qemu_put_be32(f, s->offset); - /* XXX: do we want to save s->storage too? */ + s->ioaddr_vmstate = s->ioaddr - s->io; } -static int nand_load(QEMUFile *f, void *opaque, int version_id) +static int nand_post_load(void *opaque, int version_id) { - NANDFlashState *s = (NANDFlashState *) opaque; - s->cle = qemu_get_byte(f); - s->ale = qemu_get_byte(f); - s->ce = qemu_get_byte(f); - s->wp = qemu_get_byte(f); - s->gnd = qemu_get_byte(f); - qemu_get_buffer(f, s->io, sizeof(s->io)); - s->ioaddr = s->io + qemu_get_be32(f); - s->iolen = qemu_get_be32(f); - if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io) - return -EINVAL; + NANDFlashState *s = opaque; + + if (s->ioaddr_vmstate > sizeof(s->io)) { + return -EINVAL; + } + s->ioaddr = s->io + s->ioaddr_vmstate; - qemu_get_be32s(f, &s->cmd); - qemu_get_be32s(f, &s->addr); - s->addrlen = qemu_get_be32(f); - s->status = qemu_get_be32(f); - s->offset = qemu_get_be32(f); return 0; } +static const VMStateDescription vmstate_nand = { + .name = "nand", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = nand_pre_save, + .post_load = nand_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(cle, NANDFlashState), + VMSTATE_UINT8(ale, NANDFlashState), + VMSTATE_UINT8(ce, NANDFlashState), + VMSTATE_UINT8(wp, NANDFlashState), + VMSTATE_UINT8(gnd, NANDFlashState), + VMSTATE_BUFFER(io, NANDFlashState), + VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState), + VMSTATE_INT32(iolen, NANDFlashState), + VMSTATE_UINT32(cmd, NANDFlashState), + VMSTATE_UINT32(addr, NANDFlashState), + VMSTATE_INT32(addrlen, NANDFlashState), + VMSTATE_INT32(status, NANDFlashState), + VMSTATE_INT32(offset, NANDFlashState), + /* XXX: do we want to save s->storage too? */ + VMSTATE_END_OF_LIST() + } +}; + /* * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip * outputs are R/B and eight I/O pins. @@ -502,7 +507,7 @@ NANDFlashState *nand_init(int manf_id, int chip_id) is used. */ s->ioaddr = s->io; - register_savevm(NULL, "nand", -1, 0, nand_save, nand_load, s); + vmstate_register(NULL, -1, &vmstate_nand, s); return s; } From 8a11f43bd5d42462c7d6a9321cefa59e78c69d51 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:54:21 +0100 Subject: [PATCH 281/386] mac_nvram: size is a size, no need to be a target dependent type Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/mac_nvram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index c2a2fc21e4..64f0192b22 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -38,7 +38,7 @@ #endif struct MacIONVRAMState { - target_phys_addr_t size; + uint32_t size; int mem_index; unsigned int it_shift; uint8_t *data; From 8e470f8a77f6dfb0ca4bb087010b4bcd920a1d21 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 01:59:09 +0100 Subject: [PATCH 282/386] vmstate: port mac_nvram Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/mac_nvram.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 64f0192b22..61e53d28b4 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -105,24 +105,17 @@ static CPUReadMemoryFunc * const nvram_read[] = { &macio_nvram_readb, }; -static void macio_nvram_save(QEMUFile *f, void *opaque) -{ - MacIONVRAMState *s = (MacIONVRAMState *)opaque; +static const VMStateDescription vmstate_macio_nvram = { + .name = "macio_nvram", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size), + VMSTATE_END_OF_LIST() + } +}; - qemu_put_buffer(f, s->data, s->size); -} - -static int macio_nvram_load(QEMUFile *f, void *opaque, int version_id) -{ - MacIONVRAMState *s = (MacIONVRAMState *)opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->data, s->size); - - return 0; -} static void macio_nvram_reset(void *opaque) { @@ -141,8 +134,7 @@ MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size, s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s, DEVICE_NATIVE_ENDIAN); *mem_index = s->mem_index; - register_savevm(NULL, "macio_nvram", -1, 1, macio_nvram_save, - macio_nvram_load, s); + vmstate_register(NULL, -1, &vmstate_macio_nvram, s); qemu_register_reset(macio_nvram_reset, s); return s; From 1fc7cee0b40e23d3d8a7384df69c07e5dd5954ed Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 16:26:56 +0100 Subject: [PATCH 283/386] piix4: create PIIX4State It only contains a PCIDevice by know, but it makes easy to use migration code Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/piix4.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/hw/piix4.c b/hw/piix4.c index 72073cd0a0..40cd91a32f 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -30,10 +30,14 @@ PCIDevice *piix4_dev; +typedef struct PIIX4State { + PCIDevice dev; +} PIIX4State; + static void piix4_reset(void *opaque) { - PCIDevice *d = opaque; - uint8_t *pci_conf = d->config; + PIIX4State *d = opaque; + uint8_t *pci_conf = d->dev.config; pci_conf[0x04] = 0x07; // master, memory and I/O pci_conf[0x05] = 0x00; @@ -70,31 +74,32 @@ static void piix4_reset(void *opaque) static void piix_save(QEMUFile* f, void *opaque) { - PCIDevice *d = opaque; - pci_device_save(d, f); + PIIX4State *d = opaque; + pci_device_save(&d->dev, f); } static int piix_load(QEMUFile* f, void *opaque, int version_id) { - PCIDevice *d = opaque; + PIIX4State *d = opaque; if (version_id != 2) return -EINVAL; - return pci_device_load(d, f); + return pci_device_load(&d->dev, f); } -static int piix4_initfn(PCIDevice *d) +static int piix4_initfn(PCIDevice *dev) { + PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev); uint8_t *pci_conf; - isa_bus_new(&d->qdev); - register_savevm(&d->qdev, "PIIX4", 0, 2, piix_save, piix_load, d); + isa_bus_new(&d->dev.qdev); + register_savevm(&d->dev.qdev, "PIIX4", 0, 2, piix_save, piix_load, d); - pci_conf = d->config; + pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA); - piix4_dev = d; + piix4_dev = &d->dev; qemu_register_reset(piix4_reset, d); return 0; } @@ -111,7 +116,7 @@ static PCIDeviceInfo piix4_info[] = { { .qdev.name = "PIIX4", .qdev.desc = "ISA bridge", - .qdev.size = sizeof(PCIDevice), + .qdev.size = sizeof(PIIX4State), .qdev.no_user = 1, .no_hotplug = 1, .init = piix4_initfn, From 9039d78e64648e6dca2aa7fe38c59ac2f5bac32b Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Thu, 2 Dec 2010 16:59:33 +0100 Subject: [PATCH 284/386] vmstate: port piix4 Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/piix4.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/hw/piix4.c b/hw/piix4.c index 40cd91a32f..71f1f84dc0 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -72,19 +72,16 @@ static void piix4_reset(void *opaque) pci_conf[0xae] = 0x00; } -static void piix_save(QEMUFile* f, void *opaque) -{ - PIIX4State *d = opaque; - pci_device_save(&d->dev, f); -} - -static int piix_load(QEMUFile* f, void *opaque, int version_id) -{ - PIIX4State *d = opaque; - if (version_id != 2) - return -EINVAL; - return pci_device_load(&d->dev, f); -} +static const VMStateDescription vmstate_piix4 = { + .name = "PIIX4", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PIIX4State), + VMSTATE_END_OF_LIST() + } +}; static int piix4_initfn(PCIDevice *dev) { @@ -92,7 +89,6 @@ static int piix4_initfn(PCIDevice *dev) uint8_t *pci_conf; isa_bus_new(&d->dev.qdev); - register_savevm(&d->dev.qdev, "PIIX4", 0, 2, piix_save, piix_load, d); pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); @@ -117,6 +113,7 @@ static PCIDeviceInfo piix4_info[] = { .qdev.name = "PIIX4", .qdev.desc = "ISA bridge", .qdev.size = sizeof(PIIX4State), + .qdev.vmsd = &vmstate_piix4, .qdev.no_user = 1, .no_hotplug = 1, .init = piix4_initfn, From c20df14b1336b409c48fbbbfeb448f0043df75d5 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 00:04:02 +0100 Subject: [PATCH 285/386] mac_dbdma: create DBDMAState instead of passing one array around Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/mac_dbdma.c | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 5680fa9c1c..c108aeee7d 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -165,6 +165,10 @@ typedef struct DBDMA_channel { int processing; } DBDMA_channel; +typedef struct { + DBDMA_channel channels[DBDMA_CHANNELS]; +} DBDMAState; + #ifdef DEBUG_DBDMA static void dump_dbdma_cmd(dbdma_cmd *cmd) { @@ -617,31 +621,34 @@ static void channel_run(DBDMA_channel *ch) } } -static void DBDMA_run (DBDMA_channel *ch) +static void DBDMA_run(DBDMAState *s) { int channel; - for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) { - uint32_t status = ch->regs[DBDMA_STATUS]; - if (!ch->processing && (status & RUN) && (status & ACTIVE)) - channel_run(ch); + for (channel = 0; channel < DBDMA_CHANNELS; channel++) { + DBDMA_channel *ch = &s->channels[channel]; + uint32_t status = ch->regs[DBDMA_STATUS]; + if (!ch->processing && (status & RUN) && (status & ACTIVE)) { + channel_run(ch); + } } } static void DBDMA_run_bh(void *opaque) { - DBDMA_channel *ch = opaque; + DBDMAState *s = opaque; DBDMA_DPRINTF("DBDMA_run_bh\n"); - DBDMA_run(ch); + DBDMA_run(s); } void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque) { - DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; + DBDMAState *s = dbdma; + DBDMA_channel *ch = &s->channels[nchan]; DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan); @@ -700,7 +707,8 @@ static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { int channel = addr >> DBDMA_CHANNEL_SHIFT; - DBDMA_channel *ch = (DBDMA_channel *)opaque + channel; + DBDMAState *s = opaque; + DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value); @@ -749,7 +757,8 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) { uint32_t value; int channel = addr >> DBDMA_CHANNEL_SHIFT; - DBDMA_channel *ch = (DBDMA_channel *)opaque + channel; + DBDMAState *s = opaque; + DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; value = ch->regs[reg]; @@ -803,17 +812,17 @@ static CPUReadMemoryFunc * const dbdma_read[] = { static void dbdma_save(QEMUFile *f, void *opaque) { - DBDMA_channel *s = opaque; + DBDMAState *s = opaque; unsigned int i, j; for (i = 0; i < DBDMA_CHANNELS; i++) for (j = 0; j < DBDMA_REGS; j++) - qemu_put_be32s(f, &s[i].regs[j]); + qemu_put_be32s(f, &s->channels[i].regs[j]); } static int dbdma_load(QEMUFile *f, void *opaque, int version_id) { - DBDMA_channel *s = opaque; + DBDMAState *s = opaque; unsigned int i, j; if (version_id != 2) @@ -821,25 +830,25 @@ static int dbdma_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < DBDMA_CHANNELS; i++) for (j = 0; j < DBDMA_REGS; j++) - qemu_get_be32s(f, &s[i].regs[j]); + qemu_get_be32s(f, &s->channels[i].regs[j]); return 0; } static void dbdma_reset(void *opaque) { - DBDMA_channel *s = opaque; + DBDMAState *s = opaque; int i; for (i = 0; i < DBDMA_CHANNELS; i++) - memset(s[i].regs, 0, DBDMA_SIZE); + memset(s->channels[i].regs, 0, DBDMA_SIZE); } void* DBDMA_init (int *dbdma_mem_index) { - DBDMA_channel *s; + DBDMAState *s; - s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS); + s = qemu_mallocz(sizeof(DBDMAState)); *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s, DEVICE_LITTLE_ENDIAN); From da26fdc3145fc990762133beb8ad6bd67742a147 Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Fri, 3 Dec 2010 00:07:26 +0100 Subject: [PATCH 286/386] vmstate: port mac_dbdma Signed-off-by: Juan Quintela <quintela@redhat.com> --- hw/mac_dbdma.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index c108aeee7d..ed4458e3bb 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -810,30 +810,28 @@ static CPUReadMemoryFunc * const dbdma_read[] = { dbdma_readl, }; -static void dbdma_save(QEMUFile *f, void *opaque) -{ - DBDMAState *s = opaque; - unsigned int i, j; +static const VMStateDescription vmstate_dbdma_channel = { + .name = "dbdma_channel", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), + VMSTATE_END_OF_LIST() + } +}; - for (i = 0; i < DBDMA_CHANNELS; i++) - for (j = 0; j < DBDMA_REGS; j++) - qemu_put_be32s(f, &s->channels[i].regs[j]); -} - -static int dbdma_load(QEMUFile *f, void *opaque, int version_id) -{ - DBDMAState *s = opaque; - unsigned int i, j; - - if (version_id != 2) - return -EINVAL; - - for (i = 0; i < DBDMA_CHANNELS; i++) - for (j = 0; j < DBDMA_REGS; j++) - qemu_get_be32s(f, &s->channels[i].regs[j]); - - return 0; -} +static const VMStateDescription vmstate_dbdma = { + .name = "dbdma", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, + vmstate_dbdma_channel, DBDMA_channel), + VMSTATE_END_OF_LIST() + } +}; static void dbdma_reset(void *opaque) { @@ -852,7 +850,7 @@ void* DBDMA_init (int *dbdma_mem_index) *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s, DEVICE_LITTLE_ENDIAN); - register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s); + vmstate_register(NULL, -1, &vmstate_dbdma, s); qemu_register_reset(dbdma_reset, s); dbdma_bh = qemu_bh_new(DBDMA_run_bh, s); From e2f422047b6fd04c28630f80ab1161dbce07c6b7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 287/386] softfloat: fix floatx80 handling of NaN The floatx80 format uses an explicit bit that should be taken into account when converting to and from commonNaN format. When converting to commonNaN, the explicit bit should be removed if it is a 1, and a default NaN should be used if it is 0. When converting from commonNan, the explicit bit should be added. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-specialize.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index b1101872af..9d68aae9d5 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -603,9 +603,15 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) commonNaNT z; if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a.high>>15; - z.low = 0; - z.high = a.low; + if ( a.low >> 63 ) { + z.sign = a.high >> 15; + z.low = 0; + z.high = a.low << 1; + } else { + z.sign = floatx80_default_nan_high >> 15; + z.low = 0; + z.high = floatx80_default_nan_low << 1; + } return z; } @@ -624,11 +630,14 @@ static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM) return z; } - if (a.high) - z.low = a.high; - else + if (a.high >> 1) { + z.low = LIT64( 0x8000000000000000 ) | a.high >> 1; + z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF; + } else { z.low = floatx80_default_nan_low; - z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF; + z.high = floatx80_default_nan_high; + } + return z; } From b76235e400be0e4f2c87ac4b678384f43a932181 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 288/386] softfloat: fix floatx80_is_infinity() With floatx80, the explicit bit is set for infinity. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 340f0a9f2e..336312839a 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -566,7 +566,7 @@ INLINE floatx80 floatx80_chs(floatx80 a) INLINE int floatx80_is_infinity(floatx80 a) { - return (a.high & 0x7fff) == 0x7fff && a.low == 0; + return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL; } INLINE int floatx80_is_neg(floatx80 a) From f3218a8df0365e515f2100c92016217826811200 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 289/386] softfloat: add floatx80 constants Add floatx80 constants similarly to float32 or float64. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 336312839a..90e0c41210 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -154,6 +154,7 @@ typedef struct { uint64_t low; uint16_t high; } floatx80; +#define make_floatx80(exp, mant) ((floatx80) { mant, exp }) #endif #ifdef FLOAT128 typedef struct { @@ -584,6 +585,12 @@ INLINE int floatx80_is_any_nan(floatx80 a) return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } +#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) +#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) +#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL) +#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL) +#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL) + /*---------------------------------------------------------------------------- | The pattern for a default generated extended double-precision NaN. The | `high' and `low' values hold the most- and least-significant bits, From c4b4c77a80cec85206e502578887d8c82b70d6af Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 290/386] softfloat: add pi constants Add a pi constant for float32, float64, floatx80. It will be used by target-i386 and later by the trigonometric functions. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 90e0c41210..7b3b88f1b1 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -387,6 +387,7 @@ INLINE float32 float32_set_sign(float32 a, int sign) #define float32_zero make_float32(0) #define float32_one make_float32(0x3f800000) #define float32_ln2 make_float32(0x3f317218) +#define float32_pi make_float32(0x40490fdb) #define float32_half make_float32(0x3f000000) #define float32_infinity make_float32(0x7f800000) @@ -499,6 +500,7 @@ INLINE float64 float64_set_sign(float64 a, int sign) #define float64_zero make_float64(0) #define float64_one make_float64(0x3ff0000000000000LL) #define float64_ln2 make_float64(0x3fe62e42fefa39efLL) +#define float64_pi make_float64(0x400921fb54442d18LL) #define float64_half make_float64(0x3fe0000000000000LL) #define float64_infinity make_float64(0x7ff0000000000000LL) @@ -588,6 +590,7 @@ INLINE int floatx80_is_any_nan(floatx80 a) #define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) #define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) #define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL) +#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL) #define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL) #define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL) From d2b1027d5ffe7c6832bd50f167751171ed168ed0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 291/386] softfloat-native: add a few constant values Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index ea7a15e1c4..97fb3c7a5c 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -171,6 +171,15 @@ floatx80 int64_to_floatx80( int64_t STATUS_PARAM); float128 int64_to_float128( int64_t STATUS_PARAM); #endif +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float32_zero (0.0) +#define float32_one (1.0) +#define float32_ln2 (0.6931471) +#define float32_pi (3.1415926) +#define float32_half (0.5) + /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -279,6 +288,15 @@ INLINE float32 float32_scalbn(float32 a, int n) return scalbnf(a, n); } +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float64_zero (0.0) +#define float64_one (1.0) +#define float64_ln2 (0.693147180559945) +#define float64_pi (3.141592653589793) +#define float64_half (0.5) + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -393,6 +411,15 @@ INLINE float64 float64_scalbn(float64 a, int n) #ifdef FLOATX80 +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define floatx80_zero (0.0L) +#define floatx80_one (1.0L) +#define floatx80_ln2 (0.69314718055994530943L) +#define floatx80_pi (3.14159265358979323851L) +#define floatx80_half (0.5L) + /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ From f6714d365da068481d83787b4044134ae2ec5dfd Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 292/386] softfloat: add floatx80_compare*() functions Add floatx80_compare() and floatx80_compare_quiet() functions to match the softfloat-native ones. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6ce0b61c19..4368069dd6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -6190,6 +6190,52 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) +INLINE int floatx80_compare_internal( floatx80 a, floatx80 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloatx80Exp( a ) == 0x7fff ) && + ( extractFloatx80Frac( a )<<1 ) ) || + ( ( extractFloatx80Exp( b ) == 0x7fff ) && + ( extractFloatx80Frac( b )<<1 ) )) { + if (!is_quiet || + floatx80_is_signaling_nan( a ) || + floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + + if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) && + ( ( a.low | b.low ) == 0 ) ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 0 STATUS_VAR); +} + +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 1 STATUS_VAR); +} + INLINE int float128_compare_internal( float128 a, float128 b, int is_quiet STATUS_PARAM ) { diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 7b3b88f1b1..5eff0858f1 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -550,6 +550,8 @@ int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); floatx80 floatx80_maybe_silence_nan( floatx80 ); From 326b9e98a391d542cc33c4c91782ff4ba51edfc5 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:22 +0200 Subject: [PATCH 293/386] softfloat: fix float*_scalnb() corner cases float*_scalnb() were not taking into account all cases. This patch fixes some corner cases: - NaN values in input were not properly propagated and the invalid flag not correctly raised. Use propagateFloat*NaN() for that. - NaN or infinite values in input of floatx80_scalnb() were not correctly detected due to a typo. - The sum of exponent and n could overflow, leading to strange results. Additionally having int16 defined to int make that happening for a very small range of values. Fix that by saturating n to the maximum exponent range, and using an explicit wider type if needed. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 4368069dd6..baba1dc44b 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -6333,7 +6333,7 @@ MINMAX(64, 0x7ff) float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int16_t aExp; uint32_t aSig; a = float32_squash_input_denormal(a STATUS_VAR); @@ -6342,6 +6342,9 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { + if ( aSig ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6349,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x200) { + n = 0x200; + } else if (n < -0x200) { + n = -0x200; + } + aExp += n - 1; aSig <<= 7; return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); @@ -6357,7 +6366,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) float64 float64_scalbn( float64 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int16_t aExp; uint64_t aSig; a = float64_squash_input_denormal(a STATUS_VAR); @@ -6366,6 +6375,9 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { + if ( aSig ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6373,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x1000) { + n = 0x1000; + } else if (n < -0x1000) { + n = -0x1000; + } + aExp += n - 1; aSig <<= 10; return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); @@ -6382,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; + int32_t aExp; uint64_t aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( aExp == 0x7FF ) { + if ( aExp == 0x7FFF ) { + if ( aSig<<1 ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } return a; } + if (aExp == 0 && aSig == 0) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n; return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), aSign, aExp, aSig, 0 STATUS_VAR ); @@ -6405,7 +6433,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) float128 float128_scalbn( float128 a, int n STATUS_PARAM ) { flag aSign; - int32 aExp; + int32_t aExp; uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); @@ -6413,6 +6441,9 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -6420,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) else if ( aSig0 == 0 && aSig1 == 0 ) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n - 1; return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 STATUS_VAR ); From d6882cf01fd9e3e1c9dee38ff7dae0d8d377c8f7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 294/386] softfloat-native: fix float*_scalbn() functions float*_scalbn() should be able to take a status parameter. Fix that. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 97fb3c7a5c..f497e64239 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -283,7 +283,7 @@ INLINE float32 float32_is_zero(float32 a) return fpclassify(a) == FP_ZERO; } -INLINE float32 float32_scalbn(float32 a, int n) +INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM) { return scalbnf(a, n); } @@ -404,7 +404,7 @@ INLINE float64 float64_is_zero(float64 a) return fpclassify(a) == FP_ZERO; } -INLINE float64 float64_scalbn(float64 a, int n) +INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM) { return scalbn(a, n); } @@ -520,7 +520,7 @@ INLINE floatx80 floatx80_is_zero(floatx80 a) return fpclassify(a) == FP_ZERO; } -INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM) { return scalbnl(a, n); } From 4cc5383f807a7d70942de51326a8dddad7331fa5 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 295/386] softfloat-native: add float*_is_any_nan() functions Add float*_is_any_nan() functions to match the softfloat API. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- fpu/softfloat-native.c | 26 ++++++++++++++++++++++++++ fpu/softfloat-native.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 50355a4c3f..88486511ee 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -263,6 +263,15 @@ int float32_is_quiet_nan( float32 a1 ) return ( 0xFF800000 < ( a<<1 ) ); } +int float32_is_any_nan( float32 a1 ) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return (a & ~(1 << 31)) > 0x7f800000U; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -422,6 +431,16 @@ int float64_is_quiet_nan( float64 a1 ) } +int float64_is_any_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 ); +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -511,4 +530,11 @@ int floatx80_is_quiet_nan( floatx80 a1 ) return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 ); } +int floatx80_is_any_nan( floatx80 a1 ) +{ + floatx80u u; + u.f = a1; + return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 ); +} + #endif diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index f497e64239..6afb74a152 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -255,6 +255,7 @@ int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); int float32_is_signaling_nan( float32 ); int float32_is_quiet_nan( float32 ); +int float32_is_any_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -375,6 +376,7 @@ INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM) int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); int float64_is_signaling_nan( float64 ); +int float64_is_any_nan( float64 ); int float64_is_quiet_nan( float64 ); INLINE float64 float64_abs(float64 a) @@ -492,6 +494,7 @@ int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_signaling_nan( floatx80 ); int floatx80_is_quiet_nan( floatx80 ); +int floatx80_is_any_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { From be1c17c7fdc16d9cb88f4092f23a494b942b68d7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 296/386] target-i386: fix helper_fscale() wrt softfloat Use the scalbn softfloat function to implement helper_fscale(). This fixes corner cases (e.g. NaN) and makes a few more GNU libc math tests to pass. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 4 ++++ target-i386/op_helper.c | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index ae6b94740f..211cc8c28e 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -115,9 +115,11 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_sub floatx80_sub #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs +#define floatx_scalbn floatx80_scalbn #define floatx_round_to_int floatx80_round_to_int #define floatx_compare floatx80_compare #define floatx_compare_quiet floatx80_compare_quiet +#define floatx_is_any_nan floatx80_is_any_nan #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 @@ -134,9 +136,11 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_sub float64_sub #define floatx_abs float64_abs #define floatx_chs float64_chs +#define floatx_scalbn float64_scalbn #define floatx_round_to_int float64_round_to_int #define floatx_compare float64_compare #define floatx_compare_quiet float64_compare_quiet +#define floatx_is_any_nan float64_is_any_nan #endif #define RC_MASK 0xc00 diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index fba536f0fb..dce28fa054 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4174,7 +4174,12 @@ void helper_frndint(void) void helper_fscale(void) { - ST0 = ldexp (ST0, (int)(ST1)); + if (floatx_is_any_nan(ST1)) { + ST0 = ST1; + } else { + int n = floatx_to_int32_round_to_zero(ST1, &env->fp_status); + ST0 = floatx_scalbn(ST0, n, &env->fp_status); + } } void helper_fsin(void) From 788e733664aab69e65bf5d5d228767cf4371f3ab Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 297/386] target-i386: fix helper_fbld_ST0() wrt softfloat Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index dce28fa054..943d217e6e 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -3920,9 +3920,10 @@ void helper_fbld_ST0(target_ulong ptr) v = ldub(ptr + i); val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); } - tmp = val; - if (ldub(ptr + 9) & 0x80) - tmp = -tmp; + tmp = int64_to_floatx(val, &env->fp_status); + if (ldub(ptr + 9) & 0x80) { + floatx_chs(tmp); + } fpush(); ST0 = tmp; } From c9ad19c57b4e35dda507ec636443069048a4ad72 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 298/386] target-i386: fix helper_fxtract() wrt softfloat With softfloat it's not possible to play with the overflow of an unsigned value to get the 0 case partially correct. Use a special case for that. Using a division to generate an infinity is the easiest way that works for both softfloat and softfloat-native. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 943d217e6e..4850c63699 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4005,15 +4005,24 @@ void helper_fpatan(void) void helper_fxtract(void) { CPU86_LDoubleU temp; - unsigned int expdif; temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; + + if (floatx_is_zero(ST0)) { + /* Easy way to generate -inf and raising division by 0 exception */ + ST0 = floatx_div(floatx_chs(floatx_one), floatx_zero, &env->fp_status); + fpush(); + ST0 = temp.d; + } else { + int expdif; + + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = int32_to_floatx(expdif, &env->fp_status); + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; + } } void helper_fprem1(void) From 13822781d4732f847555a2f60560c71c531c9f98 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 299/386] target-i386: fix helper_fdiv() wrt softfloat Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 4 ++++ target-i386/op_helper.c | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 211cc8c28e..b2af8945c5 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -111,6 +111,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_to_float32 floatx80_to_float32 #define floatx_to_float64 floatx80_to_float64 #define floatx_add floatx80_add +#define floatx_div floatx80_div #define floatx_mul floatx80_mul #define floatx_sub floatx80_sub #define floatx_abs floatx80_abs @@ -120,6 +121,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_compare floatx80_compare #define floatx_compare_quiet floatx80_compare_quiet #define floatx_is_any_nan floatx80_is_any_nan +#define floatx_is_zero floatx80_is_zero #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 @@ -132,6 +134,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_to_float32 float64_to_float32 #define floatx_to_float64(x, e) (x) #define floatx_add float64_add +#define floatx_div float64_div #define floatx_mul float64_mul #define floatx_sub float64_sub #define floatx_abs float64_abs @@ -141,6 +144,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_compare float64_compare #define floatx_compare_quiet float64_compare_quiet #define floatx_is_any_nan float64_is_any_nan +#define floatx_is_zero float64_is_zero #endif #define RC_MASK 0xc00 diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 4850c63699..bd24d8c442 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -3440,9 +3440,10 @@ static void fpu_set_exception(int mask) static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) { - if (b == 0.0) + if (floatx_is_zero(b)) { fpu_set_exception(FPUS_ZE); - return a / b; + } + return floatx_div(a, b, &env->fp_status); } static void fpu_raise_exception(void) From fec05e429943a2486ebe4c65da7b46a90f2dcfb2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 300/386] target-i386: fix helper_fsqrt() wrt softfloat Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 4 ++++ target-i386/op_helper.c | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index b2af8945c5..292e0de325 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -114,6 +114,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_div floatx80_div #define floatx_mul floatx80_mul #define floatx_sub floatx80_sub +#define floatx_sqrt floatx80_sqrt #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs #define floatx_scalbn floatx80_scalbn @@ -121,6 +122,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_compare floatx80_compare #define floatx_compare_quiet floatx80_compare_quiet #define floatx_is_any_nan floatx80_is_any_nan +#define floatx_is_neg floatx80_is_neg #define floatx_is_zero floatx80_is_zero #else #define floatx_to_int32 float64_to_int32 @@ -137,6 +139,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_div float64_div #define floatx_mul float64_mul #define floatx_sub float64_sub +#define floatx_sqrt float64_sqrt #define floatx_abs float64_abs #define floatx_chs float64_chs #define floatx_scalbn float64_scalbn @@ -144,6 +147,7 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_compare float64_compare #define floatx_compare_quiet float64_compare_quiet #define floatx_is_any_nan float64_is_any_nan +#define floatx_is_neg float64_is_neg #define floatx_is_zero float64_is_zero #endif diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index bd24d8c442..589a68bc71 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4152,14 +4152,11 @@ void helper_fyl2xp1(void) void helper_fsqrt(void) { - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { + if (floatx_is_neg(ST0)) { env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ env->fpus |= 0x400; } - ST0 = sqrt(fptemp); + ST0 = floatx_sqrt(ST0, &env->fp_status); } void helper_fsincos(void) From c2ef9a83be8a176802c33db7f826ff30a18b50f3 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 301/386] target-i386: replace approx_rsqrt and approx_rcp by softfloat ops Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 10 ---------- target-i386/ops_sse.h | 36 ++++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 589a68bc71..f7cdaaa222 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4794,16 +4794,6 @@ void helper_boundl(target_ulong a0, int v) } } -static float approx_rsqrt(float a) -{ - return 1.0 / sqrt(a); -} - -static float approx_rcp(float a) -{ - return 1.0 / a; -} - #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index ac0f150070..703be99cd2 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -778,28 +778,38 @@ int64_t helper_cvttsd2sq(XMMReg *s) void helper_rsqrtps(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); - d->XMM_S(1) = approx_rsqrt(s->XMM_S(1)); - d->XMM_S(2) = approx_rsqrt(s->XMM_S(2)); - d->XMM_S(3) = approx_rsqrt(s->XMM_S(3)); + d->XMM_S(0) = float32_div(float32_one, + float32_sqrt(s->XMM_S(0), &env->sse_status), + &env->sse_status); + d->XMM_S(1) = float32_div(float32_one, + float32_sqrt(s->XMM_S(1), &env->sse_status), + &env->sse_status); + d->XMM_S(2) = float32_div(float32_one, + float32_sqrt(s->XMM_S(2), &env->sse_status), + &env->sse_status); + d->XMM_S(3) = float32_div(float32_one, + float32_sqrt(s->XMM_S(3), &env->sse_status), + &env->sse_status); } void helper_rsqrtss(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); + d->XMM_S(0) = float32_div(float32_one, + float32_sqrt(s->XMM_S(0), &env->sse_status), + &env->sse_status); } void helper_rcpps(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rcp(s->XMM_S(0)); - d->XMM_S(1) = approx_rcp(s->XMM_S(1)); - d->XMM_S(2) = approx_rcp(s->XMM_S(2)); - d->XMM_S(3) = approx_rcp(s->XMM_S(3)); + d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status); + d->XMM_S(1) = float32_div(float32_one, s->XMM_S(1), &env->sse_status); + d->XMM_S(2) = float32_div(float32_one, s->XMM_S(2), &env->sse_status); + d->XMM_S(3) = float32_div(float32_one, s->XMM_S(3), &env->sse_status); } void helper_rcpss(XMMReg *d, XMMReg *s) { - d->XMM_S(0) = approx_rcp(s->XMM_S(0)); + d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status); } static inline uint64_t helper_extrq(uint64_t src, int shift, int len) @@ -1272,14 +1282,16 @@ void helper_pfpnacc(MMXReg *d, MMXReg *s) void helper_pfrcp(MMXReg *d, MMXReg *s) { - d->MMX_S(0) = approx_rcp(s->MMX_S(0)); + d->MMX_S(0) = float32_div(float32_one, s->MMX_S(0), &env->mmx_status); d->MMX_S(1) = d->MMX_S(0); } void helper_pfrsqrt(MMXReg *d, MMXReg *s) { d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff; - d->MMX_S(1) = approx_rsqrt(d->MMX_S(1)); + d->MMX_S(1) = float32_div(float32_one, + float32_sqrt(d->MMX_S(1), &env->mmx_status), + &env->mmx_status); d->MMX_L(1) |= s->MMX_L(0) & 0x80000000; d->MMX_L(0) = d->MMX_L(1); } From 47c0143cdde080101e97a1b39f3ff13e33b5726c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 302/386] target-i386: add CPU86_LDouble <-> double conversion functions Add functions to convert CPU86_LDouble to double and vice versa. They are going to be used to implement logarithmic and trigonometric function until softfloat implement them. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index f7cdaaa222..64c0bbf0ce 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -3431,6 +3431,28 @@ void helper_verw(target_ulong selector1) /* x87 FPU helpers */ +static inline double CPU86_LDouble_to_double(CPU86_LDouble a) +{ + union { + float64 f64; + double d; + } u; + + u.f64 = floatx_to_float64(a, &env->fp_status); + return u.d; +} + +static inline CPU86_LDouble double_to_CPU86_LDouble(double a) +{ + union { + float64 f64; + double d; + } u; + + u.d = a; + return float64_to_floatx(u.f64, &env->fp_status); +} + static void fpu_set_exception(int mask) { env->fpus |= mask; From a2c9ed3cbfde4ce521b6b9672afc4fd8cf67ab8e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 303/386] target-i386: fix logarithmic and trigonometric helpers wrt softfloat Use the new CPU86_LDouble <-> double conversion functions to make logarithmic and trigonometric helpers working with softfloat. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 64c0bbf0ce..fd9d8d3117 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include <math.h> #include "exec.h" #include "exec-all.h" #include "host-utils.h" @@ -3981,17 +3982,19 @@ void helper_fbst_ST0(target_ulong ptr) void helper_f2xm1(void) { - ST0 = pow(2.0,ST0) - 1.0; + double val = CPU86_LDouble_to_double(ST0); + val = pow(2.0, val) - 1.0; + ST0 = double_to_CPU86_LDouble(val); } void helper_fyl2x(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + fptemp *= CPU86_LDouble_to_double(ST1); + ST1 = double_to_CPU86_LDouble(fptemp); fpop(); } else { env->fpus &= (~0x4700); @@ -4001,15 +4004,15 @@ void helper_fyl2x(void) void helper_fptan(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = tan(fptemp); + fptemp = tan(fptemp); + ST0 = double_to_CPU86_LDouble(fptemp); fpush(); - ST0 = 1.0; + ST0 = floatx_one; env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**52 only */ } @@ -4017,11 +4020,11 @@ void helper_fptan(void) void helper_fpatan(void) { - CPU86_LDouble fptemp, fpsrcop; + double fptemp, fpsrcop; - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); + fpsrcop = CPU86_LDouble_to_double(ST1); + fptemp = CPU86_LDouble_to_double(ST0); + ST1 = double_to_CPU86_LDouble(atan2(fpsrcop, fptemp)); fpop(); } @@ -4159,12 +4162,12 @@ void helper_fprem(void) void helper_fyl2xp1(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp+1.0)>0.0) { fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; + fptemp *= CPU86_LDouble_to_double(ST1); + ST1 = double_to_CPU86_LDouble(fptemp); fpop(); } else { env->fpus &= (~0x4700); @@ -4183,15 +4186,14 @@ void helper_fsqrt(void) void helper_fsincos(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = sin(fptemp); + ST0 = double_to_CPU86_LDouble(sin(fptemp)); fpush(); - ST0 = cos(fptemp); + ST0 = double_to_CPU86_LDouble(cos(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**63 only */ } @@ -4214,13 +4216,12 @@ void helper_fscale(void) void helper_fsin(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = sin(fptemp); + ST0 = double_to_CPU86_LDouble(sin(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg| < 2**53 only */ } @@ -4228,13 +4229,12 @@ void helper_fsin(void) void helper_fcos(void) { - CPU86_LDouble fptemp; + double fptemp = CPU86_LDouble_to_double(ST0); - fptemp = ST0; if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { env->fpus |= 0x400; } else { - ST0 = cos(fptemp); + ST0 = double_to_CPU86_LDouble(cos(fptemp)); env->fpus &= (~0x400); /* C2 <-- 0 */ /* the above code is for |arg5 < 2**63 only */ } From bcb5fec5af5d543f6ea0efa513c00503a2ada5b6 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 304/386] target-i386: fix helper_fprem() and helper_fprem1() wrt softfloat Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/op_helper.c | 48 ++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index fd9d8d3117..334f1301fd 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -4053,21 +4053,24 @@ void helper_fxtract(void) void helper_fprem1(void) { - CPU86_LDouble dblq, fpsrcop, fptemp; + double st0, st1, dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; signed long long int q; - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ + st0 = CPU86_LDouble_to_double(ST0); + st1 = CPU86_LDouble_to_double(ST1); + + if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { + ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ return; } - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; + fpsrcop = st0; + fptemp = st1; + fpsrcop1.d = ST0; + fptemp1.d = ST1; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); if (expdif < 0) { @@ -4081,7 +4084,7 @@ void helper_fprem1(void) dblq = fpsrcop / fptemp; /* round dblq towards nearest integer */ dblq = rint(dblq); - ST0 = fpsrcop - fptemp * dblq; + st0 = fpsrcop - fptemp * dblq; /* convert dblq to q by truncating towards zero */ if (dblq < 0.0) @@ -4097,31 +4100,35 @@ void helper_fprem1(void) } else { env->fpus |= 0x400; /* C2 <-- 1 */ fptemp = pow(2.0, expdif - 50); - fpsrcop = (ST0 / ST1) / fptemp; + fpsrcop = (st0 / st1) / fptemp; /* fpsrcop = integer obtained by chopping */ fpsrcop = (fpsrcop < 0.0) ? -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); + st0 -= (st1 * fpsrcop * fptemp); } + ST0 = double_to_CPU86_LDouble(st0); } void helper_fprem(void) { - CPU86_LDouble dblq, fpsrcop, fptemp; + double st0, st1, dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; signed long long int q; - if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { - ST0 = 0.0 / 0.0; /* NaN */ + st0 = CPU86_LDouble_to_double(ST0); + st1 = CPU86_LDouble_to_double(ST1); + + if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) { + ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ return; } - fpsrcop = (CPU86_LDouble)ST0; - fptemp = (CPU86_LDouble)ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; + fpsrcop = st0; + fptemp = st1; + fpsrcop1.d = ST0; + fptemp1.d = ST1; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); if (expdif < 0) { @@ -4135,7 +4142,7 @@ void helper_fprem(void) dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; /* round dblq towards zero */ dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); - ST0 = fpsrcop/*ST0*/ - fptemp * dblq; + st0 = fpsrcop/*ST0*/ - fptemp * dblq; /* convert dblq to q by truncating towards zero */ if (dblq < 0.0) @@ -4152,12 +4159,13 @@ void helper_fprem(void) int N = 32 + (expdif % 32); /* as per AMD docs */ env->fpus |= 0x400; /* C2 <-- 1 */ fptemp = pow(2.0, (double)(expdif - N)); - fpsrcop = (ST0 / ST1) / fptemp; + fpsrcop = (st0 / st1) / fptemp; /* fpsrcop = integer obtained by chopping */ fpsrcop = (fpsrcop < 0.0) ? -(floor(fabs(fpsrcop))) : floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); + st0 -= (st1 * fpsrcop * fptemp); } + ST0 = double_to_CPU86_LDouble(st0); } void helper_fyl2xp1(void) From a1d8db07fb46e1da410ca7b4ce24a997707d4a53 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 305/386] target-i386: fix constants wrt softfloat Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-i386/exec.h | 8 ++++++++ target-i386/op_helper.c | 24 +++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 292e0de325..ee36a7181a 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -124,6 +124,10 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_is_any_nan floatx80_is_any_nan #define floatx_is_neg floatx80_is_neg #define floatx_is_zero floatx80_is_zero +#define floatx_zero floatx80_zero +#define floatx_one floatx80_one +#define floatx_ln2 floatx80_ln2 +#define floatx_pi floatx80_pi #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 @@ -149,6 +153,10 @@ static inline void svm_check_intercept(uint32_t type) #define floatx_is_any_nan float64_is_any_nan #define floatx_is_neg float64_is_neg #define floatx_is_zero float64_is_zero +#define floatx_zero float64_zero +#define floatx_one float64_one +#define floatx_ln2 float64_ln2 +#define floatx_pi float64_pi #endif #define RC_MASK 0xc00 diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index 334f1301fd..3c539f37cf 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -95,15 +95,25 @@ static const uint8_t rclb_table[32] = { 6, 7, 8, 0, 1, 2, 3, 4, }; +#if defined(CONFIG_SOFTFLOAT) +# define floatx_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL ) +# define floatx_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL ) +# define floatx_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL ) +#else +# define floatx_lg2 (0.30102999566398119523L) +# define floatx_l2e (1.44269504088896340739L) +# define floatx_l2t (3.32192809488736234781L) +#endif + static const CPU86_LDouble f15rk[7] = { - 0.00000000000000000000L, - 1.00000000000000000000L, - 3.14159265358979323851L, /*pi*/ - 0.30102999566398119523L, /*lg2*/ - 0.69314718055994530943L, /*ln2*/ - 1.44269504088896340739L, /*l2e*/ - 3.32192809488736234781L, /*l2t*/ + floatx_zero, + floatx_one, + floatx_pi, + floatx_lg2, + floatx_ln2, + floatx_l2e, + floatx_l2t, }; /* broken thread support */ From 347ac8e35661eff1c2b5ec74d11ee152f2a61856 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno <aurelien@aurel32.net> Date: Wed, 20 Apr 2011 13:04:23 +0200 Subject: [PATCH 306/386] target-i386: switch to softfloat This increase the correctness (precision, NaN values, corner cases) on non-x86 machines, and add the possibility to handle the exception correctly. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/configure b/configure index da2da04059..f2eab308b2 100755 --- a/configure +++ b/configure @@ -3275,14 +3275,7 @@ if test ! -z "$gdb_xml_files" ; then echo "TARGET_XML_FILES=$list" >> $config_target_mak fi -case "$target_arch2" in - i386|x86_64) - echo "CONFIG_NOSOFTFLOAT=y" >> $config_target_mak - ;; - *) - echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak - ;; -esac +echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then echo "TARGET_HAS_BFLT=y" >> $config_target_mak From 93262b1625ecb9c6ff22d5a51f38e312b5b7725a Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 18 Apr 2011 19:07:11 +0100 Subject: [PATCH 307/386] target-arm: Handle UNDEFs for Neon single element load/stores Handle the UNDEF and UNPREDICTABLE cases for Neon "single element to one lane" VLD and "single element from one lane" VST. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index e1bda57e81..80b25ac5c4 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3975,6 +3975,7 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) stride = (1 << size) * nregs; } else { /* Single element. */ + int idx = (insn >> 4) & 0xf; pass = (insn >> 7) & 1; switch (size) { case 0: @@ -3993,6 +3994,39 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) abort(); } nregs = ((insn >> 8) & 3) + 1; + /* Catch the UNDEF cases. This is unavoidably a bit messy. */ + switch (nregs) { + case 1: + if (((idx & (1 << size)) != 0) || + (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) { + return 1; + } + break; + case 3: + if ((idx & 1) != 0) { + return 1; + } + /* fall through */ + case 2: + if (size == 2 && (idx & 2) != 0) { + return 1; + } + break; + case 4: + if ((size == 2) && ((idx & 3) == 3)) { + return 1; + } + break; + default: + abort(); + } + if ((rd + stride * (nregs - 1)) > 31) { + /* Attempts to write off the end of the register file + * are UNPREDICTABLE; we choose to UNDEF because otherwise + * the neon_load_reg() would write off the end of the array. + */ + return 1; + } addr = tcg_temp_new_i32(); load_reg_var(s, addr, rn); for (reg = 0; reg < nregs; reg++) { From f2dd89d0c7e5d39237f43392ccaed79bda47a71e Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Mon, 18 Apr 2011 19:07:12 +0100 Subject: [PATCH 308/386] target-arm: Handle UNDEF cases for Neon VLD/VST multiple-structures Correctly UNDEF for Neon VLD/VST "multiple structures" forms where the align field is not valid. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index 80b25ac5c4..8b309d48b8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3830,6 +3830,21 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) size = (insn >> 6) & 3; if (op > 10) return 1; + /* Catch UNDEF cases for bad values of align field */ + switch (op & 0xc) { + case 4: + if (((insn >> 5) & 1) == 1) { + return 1; + } + break; + case 8: + if (((insn >> 4) & 3) == 3) { + return 1; + } + break; + default: + break; + } nregs = neon_ls_element_type[op].nregs; interleave = neon_ls_element_type[op].interleave; spacing = neon_ls_element_type[op].spacing; From 7cb4db8f41d20d2c9d9c9a6830a362eebaeb42ed Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Wed, 20 Apr 2011 11:19:15 +0100 Subject: [PATCH 309/386] linux-user/arm/nwfpe: rename REG_PC to ARM_REG_PC The REG_PC constant used in the ARM nwfpe code is fine in the kernel but when used in qemu can clash with a definition in the host system include files (in particular on Ubuntu Lucid SPARC, including signal.h will define a REG_PC). Rename the constant to avoid this issue. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- linux-user/arm/nwfpe/fpa11.c | 2 +- linux-user/arm/nwfpe/fpa11.h | 2 +- linux-user/arm/nwfpe/fpa11_cpdt.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 0a87c43133..eebd93fc00 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -144,7 +144,7 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) #if 0 fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", - opcode, qregs[REG_PC]); + opcode, qregs[ARM_REG_PC]); #endif fpa11 = GET_FPA11(); diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h index f17647bdb9..002b3cbb82 100644 --- a/linux-user/arm/nwfpe/fpa11.h +++ b/linux-user/arm/nwfpe/fpa11.h @@ -111,7 +111,7 @@ static inline void writeConditionCodes(unsigned int x) cpsr_write(user_registers,x,CPSR_NZCV); } -#define REG_PC 15 +#define ARM_REG_PC 15 unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs); diff --git a/linux-user/arm/nwfpe/fpa11_cpdt.c b/linux-user/arm/nwfpe/fpa11_cpdt.c index b12e27dcb0..3e7a938253 100644 --- a/linux-user/arm/nwfpe/fpa11_cpdt.c +++ b/linux-user/arm/nwfpe/fpa11_cpdt.c @@ -220,7 +220,7 @@ static unsigned int PerformLDF(const unsigned int opcode) //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); pBase = readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) + if (ARM_REG_PC == getRn(opcode)) { pBase += 8; write_back = 0; @@ -256,7 +256,7 @@ static unsigned int PerformSTF(const unsigned int opcode) SetRoundingMode(ROUND_TO_NEAREST); pBase = readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) + if (ARM_REG_PC == getRn(opcode)) { pBase += 8; write_back = 0; @@ -289,7 +289,7 @@ static unsigned int PerformLFM(const unsigned int opcode) target_ulong pBase, pAddress, pFinal; pBase = readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) + if (ARM_REG_PC == getRn(opcode)) { pBase += 8; write_back = 0; @@ -322,7 +322,7 @@ static unsigned int PerformSFM(const unsigned int opcode) target_ulong pBase, pAddress, pFinal; pBase = readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) + if (ARM_REG_PC == getRn(opcode)) { pBase += 8; write_back = 0; From afcd9c0dcd1d6ab14a72db6abde76142c6a0ac12 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier <benjamin.poirier@gmail.com> Date: Wed, 20 Apr 2011 19:39:00 -0400 Subject: [PATCH 310/386] rtl8139: use TARGET_FMT_plx in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents a compilation failure when DEBUG_RTL8139 is defined: CC libhw32/rtl8139.o cc1: warnings being treated as errors hw/rtl8139.c: In function ‘rtl8139_cplus_transmit_one’: hw/rtl8139.c:1960: error: format ‘%8lx’ expects type ‘long unsigned int’, but argument 5 has type ‘target_phys_addr_t’ make[1]: *** [rtl8139.o] Error 1 Signed-off-by: Benjamin Poirier <benjamin.poirier@gmail.com> Cc: Igor V. Kovalenko <igor.v.kovalenko@gmail.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/rtl8139.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 8790a00afb..a46416ef77 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -978,8 +978,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; - DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n", - descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc)); + DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from " + "host memory at %08x %08x = " TARGET_FMT_plx "\n", descriptor, + s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc)); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; @@ -1957,8 +1958,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; - DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", - descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); + DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host " + "memory at %08x0x%08x = 0x" TARGET_FMT_plx "\n", descriptor, + s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -2069,8 +2071,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* append more data to the packet */ - DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n", - txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset)); + DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host " + "memory at " TARGET_FMT_plx " to offset %d\n", txsize, tx_addr, + s->cplus_txbuffer_offset)); cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); s->cplus_txbuffer_offset += txsize; From 7cdeb319e46b8aeef866e17119093e1646e77b02 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier <benjamin.poirier@gmail.com> Date: Wed, 20 Apr 2011 19:39:01 -0400 Subject: [PATCH 311/386] rtl8139: use variadic macro for debug statements Removes double (( )) to make DEBUG_PRINT compatible with real function calls. Change the name to DPRINTF to be consistent with other DPRINTF macros throughout qemu. Include the "RTL8139: " prefix in the macro. This changes some debug output slightly since the prefix wasn't present on all lines. Part of the change was done using the "coccinelle" tool with the following small semantic match: @@ expression E; @@ - DEBUG_PRINT((E)) + DPRINTF(E) Signed-off-by: Benjamin Poirier <benjamin.poirier@gmail.com> Cc: Igor V. Kovalenko <igor.v.kovalenko@gmail.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/rtl8139.c | 435 +++++++++++++++++++++++++++------------------------ 1 file changed, 232 insertions(+), 203 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index a46416ef77..13b14e4e10 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -85,9 +85,10 @@ #define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN) #if defined (DEBUG_RTL8139) -# define DEBUG_PRINT(x) do { printf x ; } while (0) +# define DPRINTF(fmt, ...) \ + do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0) #else -# define DEBUG_PRINT(x) +# define DPRINTF(fmt, ...) do { } while (0) #endif /* Symbolic offsets to registers. */ @@ -510,7 +511,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time); static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { - DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); + DPRINTF("eeprom command 0x%02x\n", command); switch (command & Chip9346_op_mask) { @@ -521,8 +522,8 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->eedo = 0; eeprom->tick = 0; eeprom->mode = Chip9346_data_read; - DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output)); + DPRINTF("eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); } break; @@ -532,8 +533,8 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->input = 0; eeprom->tick = 0; eeprom->mode = Chip9346_none; /* Chip9346_data_write */ - DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", - eeprom->address)); + DPRINTF("eeprom begin write to address 0x%02x\n", + eeprom->address); } break; default: @@ -541,13 +542,13 @@ static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) switch (command & Chip9346_op_ext_mask) { case Chip9346_op_write_enable: - DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); + DPRINTF("eeprom write enabled\n"); break; case Chip9346_op_write_all: - DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); + DPRINTF("eeprom begin write all\n"); break; case Chip9346_op_write_disable: - DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); + DPRINTF("eeprom write disabled\n"); break; } break; @@ -560,7 +561,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) ++ eeprom->tick; - DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); + DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, + eeprom->eedo); switch (eeprom->mode) { @@ -570,7 +572,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->mode = Chip9346_read_command; eeprom->tick = 0; eeprom->input = 0; - DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); + DPRINTF("eeprom: +++ synchronized, begin command read\n"); } break; @@ -595,7 +597,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->input = 0; eeprom->tick = 0; - DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n")); + DPRINTF("eeprom: +++ end of read, awaiting next command\n"); #else // original behaviour ++eeprom->address; @@ -603,8 +605,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->output = eeprom->contents[eeprom->address]; eeprom->tick = 0; - DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output)); + DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); #endif } break; @@ -613,8 +615,8 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { - DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->input)); + DPRINTF("eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input); eeprom->contents[eeprom->address] = eeprom->input; eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ @@ -632,8 +634,7 @@ static void prom9346_shift_clock(EEprom9346 *eeprom) { eeprom->contents[i] = eeprom->input; } - DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", - eeprom->input)); + DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input); eeprom->mode = Chip9346_enter_command_mode; eeprom->tick = 0; @@ -666,8 +667,8 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->eesk = eesk; eeprom->eedi = eedi; - DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", - eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); + DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, + eeprom->eesk, eeprom->eedi, eeprom->eedo); if (!old_eecs && eecs) { @@ -677,12 +678,12 @@ static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->output = 0; eeprom->mode = Chip9346_enter_command_mode; - DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); + DPRINTF("=== eeprom: begin access, enter command mode\n"); } if (!eecs) { - DEBUG_PRINT(("=== eeprom: end access\n")); + DPRINTF("=== eeprom: end access\n"); return; } @@ -698,8 +699,8 @@ static void rtl8139_update_irq(RTL8139State *s) int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; - DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n", - isr ? 1 : 0, s->IntrStatus, s->IntrMask)); + DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus, + s->IntrMask); qemu_set_irq(s->dev.irq[0], (isr != 0)); } @@ -763,7 +764,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) /* write packet data */ if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s))) { - DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); + DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped); if (size > wrapped) { @@ -834,12 +835,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); + DPRINTF(">>> received len=%d\n", size); /* test if board clock is stopped */ if (!s->clock_enabled) { - DEBUG_PRINT(("RTL8139: stopped ==========================\n")); + DPRINTF("stopped ==========================\n"); return -1; } @@ -847,21 +848,21 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ if (!rtl8139_receiver_enabled(s)) { - DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); + DPRINTF("receiver disabled ================\n"); return -1; } /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ - DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); + DPRINTF(">>> packet received in promiscuous mode\n"); } else { if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->RxConfig & AcceptBroadcast)) { - DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); + DPRINTF(">>> broadcast packet rejected\n"); /* update tally counter */ ++s->tally_counters.RxERR; @@ -871,7 +872,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ packet_header |= RxBroadcast; - DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); + DPRINTF(">>> broadcast packet received\n"); /* update tally counter */ ++s->tally_counters.RxOkBrd; @@ -880,7 +881,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* multicast */ if (!(s->RxConfig & AcceptMulticast)) { - DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); + DPRINTF(">>> multicast packet rejected\n"); /* update tally counter */ ++s->tally_counters.RxERR; @@ -892,7 +893,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { - DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n")); + DPRINTF(">>> multicast address mismatch\n"); /* update tally counter */ ++s->tally_counters.RxERR; @@ -902,7 +903,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ packet_header |= RxMulticast; - DEBUG_PRINT((">>> RTL8139: multicast packet received\n")); + DPRINTF(">>> multicast packet received\n"); /* update tally counter */ ++s->tally_counters.RxOkMul; @@ -916,7 +917,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* match */ if (!(s->RxConfig & AcceptMyPhys)) { - DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n")); + DPRINTF(">>> rejecting physical address matching packet\n"); /* update tally counter */ ++s->tally_counters.RxERR; @@ -926,14 +927,14 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ packet_header |= RxPhysical; - DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n")); + DPRINTF(">>> physical address matching packet received\n"); /* update tally counter */ ++s->tally_counters.RxOkPhy; } else { - DEBUG_PRINT((">>> RTL8139: unknown packet\n")); + DPRINTF(">>> unknown packet\n"); /* update tally counter */ ++s->tally_counters.RxERR; @@ -955,7 +956,7 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ if (rtl8139_cp_receiver_enabled(s)) { - DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n")); + DPRINTF("in C+ Rx mode ================\n"); /* begin C+ receiver mode */ @@ -978,9 +979,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; - DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from " - "host memory at %08x %08x = " TARGET_FMT_plx "\n", descriptor, - s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc)); + DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at " + "%08x %08x = "TARGET_FMT_plx"\n", descriptor, s->RxRingAddrHI, + s->RxRingAddrLO, cplus_rx_ring_desc); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; @@ -993,13 +994,13 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); rxbufHI = le32_to_cpu(val); - DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", - descriptor, - rxdw0, rxdw1, rxbufLO, rxbufHI)); + DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI); if (!(rxdw0 & CP_RX_OWN)) { - DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor)); + DPRINTF("C+ Rx mode : descriptor %d is owned by host\n", + descriptor); s->IntrStatus |= RxOverflow; ++s->RxMissed; @@ -1029,9 +1030,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *) &dot1q_buf[ETHER_TYPE_LEN]); - DEBUG_PRINT(("RTL8139: C+ Rx mode : extracted vlan tag with tci: " - "%u\n", be16_to_cpup((uint16_t *) - &dot1q_buf[ETHER_TYPE_LEN]))); + DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n", + be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN])); } else { /* reset VLAN tag flag */ rxdw1 &= ~CP_RX_TAVA; @@ -1041,8 +1041,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ if (size+4 > rx_space) { - DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", - descriptor, rx_space, size)); + DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size); s->IntrStatus |= RxOverflow; ++s->RxMissed; @@ -1137,12 +1137,12 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ ++s->currCPlusRxDesc; } - DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n")); + DPRINTF("done C+ Rx mode ----------------\n"); } else { - DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n")); + DPRINTF("in ring Rx mode ================\n"); /* begin ring receiver mode */ int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); @@ -1151,8 +1151,9 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ if (avail != 0 && size + 8 >= avail) { - DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8)); + DPRINTF("rx overflow: rx buffer length %d head 0x%04x " + "read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); s->IntrStatus |= RxOverflow; ++s->RxMissed; @@ -1180,8 +1181,8 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_ /* now we can signal we have received something */ - DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); + DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); } s->IntrStatus |= RxOK; @@ -1375,22 +1376,22 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val)); + DPRINTF("ChipCmd write val=0x%08x\n", val); if (val & CmdReset) { - DEBUG_PRINT(("RTL8139: ChipCmd reset\n")); + DPRINTF("ChipCmd reset\n"); rtl8139_reset(&s->dev.qdev); } if (val & CmdRxEnb) { - DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); + DPRINTF("ChipCmd enable receiver\n"); s->currCPlusRxDesc = 0; } if (val & CmdTxEnb) { - DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); + DPRINTF("ChipCmd enable transmitter\n"); s->currCPlusTxDesc = 0; } @@ -1410,11 +1411,11 @@ static int rtl8139_RxBufferEmpty(RTL8139State *s) if (unread != 0) { - DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread)); + DPRINTF("receiver buffer data available 0x%04x\n", unread); return 0; } - DEBUG_PRINT(("RTL8139: receiver buffer is empty\n")); + DPRINTF("receiver buffer is empty\n"); return 1; } @@ -1426,7 +1427,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) if (rtl8139_RxBufferEmpty(s)) ret |= RxBufEmpty; - DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret)); + DPRINTF("ChipCmd read val=0x%04x\n", ret); return ret; } @@ -1435,7 +1436,7 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) { val &= 0xffff; - DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); + DPRINTF("C+ command register write(w) val=0x%04x\n", val); s->cplus_enabled = 1; @@ -1449,21 +1450,21 @@ static uint32_t rtl8139_CpCmd_read(RTL8139State *s) { uint32_t ret = s->CpCmd; - DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret)); + DPRINTF("C+ command register read(w) val=0x%04x\n", ret); return ret; } static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val)); + DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val); } static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) { uint32_t ret = 0; - DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret)); + DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret); return ret; } @@ -1475,7 +1476,7 @@ static int rtl8139_config_writeable(RTL8139State *s) return 1; } - DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n")); + DPRINTF("Configuration registers are write-protected\n"); return 0; } @@ -1484,7 +1485,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) { val &= 0xffff; - DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); + DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val); /* mask unwriteable bits */ uint32_t mask = 0x4cff; @@ -1506,7 +1507,7 @@ static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s) { uint32_t ret = s->BasicModeCtrl; - DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret)); + DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret); return ret; } @@ -1515,7 +1516,7 @@ static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val) { val &= 0xffff; - DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val)); + DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); @@ -1527,7 +1528,7 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) { uint32_t ret = s->BasicModeStatus; - DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret)); + DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret); return ret; } @@ -1536,7 +1537,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val)); + DPRINTF("Cfg9346 write val=0x%02x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0x31, s->Cfg9346); @@ -1579,7 +1580,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL8139State *s) } } - DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret)); + DPRINTF("Cfg9346 read val=0x%02x\n", ret); return ret; } @@ -1588,7 +1589,7 @@ static void rtl8139_Config0_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val)); + DPRINTF("Config0 write val=0x%02x\n", val); if (!rtl8139_config_writeable(s)) return; @@ -1603,7 +1604,7 @@ static uint32_t rtl8139_Config0_read(RTL8139State *s) { uint32_t ret = s->Config0; - DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret)); + DPRINTF("Config0 read val=0x%02x\n", ret); return ret; } @@ -1612,7 +1613,7 @@ static void rtl8139_Config1_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val)); + DPRINTF("Config1 write val=0x%02x\n", val); if (!rtl8139_config_writeable(s)) return; @@ -1627,7 +1628,7 @@ static uint32_t rtl8139_Config1_read(RTL8139State *s) { uint32_t ret = s->Config1; - DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret)); + DPRINTF("Config1 read val=0x%02x\n", ret); return ret; } @@ -1636,7 +1637,7 @@ static void rtl8139_Config3_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val)); + DPRINTF("Config3 write val=0x%02x\n", val); if (!rtl8139_config_writeable(s)) return; @@ -1651,7 +1652,7 @@ static uint32_t rtl8139_Config3_read(RTL8139State *s) { uint32_t ret = s->Config3; - DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret)); + DPRINTF("Config3 read val=0x%02x\n", ret); return ret; } @@ -1660,7 +1661,7 @@ static void rtl8139_Config4_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val)); + DPRINTF("Config4 write val=0x%02x\n", val); if (!rtl8139_config_writeable(s)) return; @@ -1675,7 +1676,7 @@ static uint32_t rtl8139_Config4_read(RTL8139State *s) { uint32_t ret = s->Config4; - DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret)); + DPRINTF("Config4 read val=0x%02x\n", ret); return ret; } @@ -1684,7 +1685,7 @@ static void rtl8139_Config5_write(RTL8139State *s, uint32_t val) { val &= 0xff; - DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val)); + DPRINTF("Config5 write val=0x%02x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0x80, s->Config5); @@ -1696,7 +1697,7 @@ static uint32_t rtl8139_Config5_read(RTL8139State *s) { uint32_t ret = s->Config5; - DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret)); + DPRINTF("Config5 read val=0x%02x\n", ret); return ret; } @@ -1705,11 +1706,11 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) { if (!rtl8139_transmitter_enabled(s)) { - DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val)); + DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val); return; } - DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val)); + DPRINTF("TxConfig write val=0x%08x\n", val); val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); @@ -1718,7 +1719,7 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val)); + DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val); uint32_t tc = s->TxConfig; tc &= 0xFFFFFF00; @@ -1730,14 +1731,14 @@ static uint32_t rtl8139_TxConfig_read(RTL8139State *s) { uint32_t ret = s->TxConfig; - DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret)); + DPRINTF("TxConfig read val=0x%04x\n", ret); return ret; } static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val)); + DPRINTF("RxConfig write val=0x%08x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); @@ -1747,14 +1748,14 @@ static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) /* reset buffer size and read/write pointers */ rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); - DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize)); + DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize); } static uint32_t rtl8139_RxConfig_read(RTL8139State *s) { uint32_t ret = s->RxConfig; - DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret)); + DPRINTF("RxConfig read val=0x%08x\n", ret); return ret; } @@ -1766,7 +1767,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, if (!size) { - DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); + DPRINTF("+++ empty ethernet frame\n"); return; } @@ -1791,7 +1792,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, buf = buf2; } - DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); + DPRINTF("+++ transmit loopback mode\n"); rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt); if (iov) { @@ -1812,25 +1813,25 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) { if (!rtl8139_transmitter_enabled(s)) { - DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", - descriptor)); + DPRINTF("+++ cannot transmit from descriptor %d: transmitter " + "disabled\n", descriptor); return 0; } if (s->TxStatus[descriptor] & TxHostOwns) { - DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", - descriptor, s->TxStatus[descriptor])); + DPRINTF("+++ cannot transmit from descriptor %d: owned by host " + "(%08x)\n", descriptor, s->TxStatus[descriptor]); return 0; } - DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor)); + DPRINTF("+++ transmitting from descriptor %d\n", descriptor); int txsize = s->TxStatus[descriptor] & 0x1fff; uint8_t txbuffer[0x2000]; - DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", - txsize, s->TxAddr[descriptor])); + DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n", + txsize, s->TxAddr[descriptor]); cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); @@ -1840,7 +1841,8 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL); - DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); + DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize, + descriptor); /* update interrupt */ s->IntrStatus |= TxOK; @@ -1940,13 +1942,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (!rtl8139_transmitter_enabled(s)) { - DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n")); + DPRINTF("+++ C+ mode: transmitter disabled\n"); return 0; } if (!rtl8139_cp_transmitter_enabled(s)) { - DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n")); + DPRINTF("+++ C+ mode: C+ transmitter disabled\n"); return 0 ; } @@ -1958,9 +1960,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; - DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host " - "memory at %08x0x%08x = 0x" TARGET_FMT_plx "\n", descriptor, - s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); + DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at " + "%08x0x%08x = 0x"TARGET_FMT_plx"\n", descriptor, s->TxAddr[1], + s->TxAddr[0], cplus_tx_ring_desc); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -1973,9 +1975,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); - DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", - descriptor, - txdw0, txdw1, txbufLO, txbufHI)); + DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, + txdw0, txdw1, txbufLO, txbufHI); /* w0 ownership flag */ #define CP_TX_OWN (1<<31) @@ -2021,15 +2022,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if (!(txdw0 & CP_TX_OWN)) { - DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor)); + DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor); return 0 ; } - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor)); + DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor); if (txdw0 & CP_TX_FS) { - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor)); + DPRINTF("+++ C+ Tx mode : descriptor %d is first segment " + "descriptor\n", descriptor); /* reset internal buffer offset */ s->cplus_txbuffer_offset = 0; @@ -2045,7 +2047,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->cplus_txbuffer = qemu_malloc(s->cplus_txbuffer_len); s->cplus_txbuffer_offset = 0; - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); + DPRINTF("+++ C+ mode transmission buffer allocated space %d\n", + s->cplus_txbuffer_len); } while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) @@ -2053,14 +2056,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); + DPRINTF("+++ C+ mode transmission buffer space changed to %d\n", + s->cplus_txbuffer_len); } if (!s->cplus_txbuffer) { /* out of memory */ - DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len)); + DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n", + s->cplus_txbuffer_len); /* update tally counter */ ++s->tally_counters.TxERR; @@ -2071,9 +2076,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* append more data to the packet */ - DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host " - "memory at " TARGET_FMT_plx " to offset %d\n", txsize, tx_addr, - s->cplus_txbuffer_offset)); + DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at " + TARGET_FMT_plx" to offset %d\n", txsize, tx_addr, + s->cplus_txbuffer_offset); cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); s->cplus_txbuffer_offset += txsize; @@ -2110,7 +2115,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) uint8_t dot1q_buffer_space[VLAN_HLEN]; uint16_t *dot1q_buffer; - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor)); + DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n", + descriptor); /* can transfer fully assembled packet */ @@ -2122,8 +2128,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if (txdw1 & CP_TX_TAGC) { /* the vlan tag is in BE byte order in the descriptor * BE + le_to_cpu() + ~swap()~ = cpu */ - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : inserting vlan tag with " - "tci: %u\n", bswap16(txdw1 & CP_TX_VLAN_TAG_MASK))); + DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n", + bswap16(txdw1 & CP_TX_VLAN_TAG_MASK)); dot1q_buffer = (uint16_t *) dot1q_buffer_space; dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q); @@ -2140,7 +2146,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN)) { - DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); + DPRINTF("+++ C+ mode offloaded task checksum\n"); /* ip packet header */ ip_header *ip = NULL; @@ -2154,7 +2160,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); if (proto == ETH_P_IP) { - DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); + DPRINTF("+++ C+ mode has IP packet\n"); /* not aligned */ eth_payload_data = saved_buffer + ETH_HLEN; @@ -2163,7 +2169,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) ip = (ip_header*)eth_payload_data; if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { - DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4)); + DPRINTF("+++ C+ mode packet has bad IP version %d " + "expected %d\n", IP_HEADER_VERSION(ip), + IP_HEADER_VERSION_4); ip = NULL; } else { hlen = IP_HEADER_LENGTH(ip); @@ -2176,7 +2184,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (txdw0 & CP_TX_IPCS) { - DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); + DPRINTF("+++ C+ mode need IP checksum\n"); if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */ /* bad packet header len */ @@ -2186,7 +2194,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { ip->ip_sum = 0; ip->ip_sum = ip_checksum(ip, hlen); - DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", + hlen, ip->ip_sum); } } @@ -2195,8 +2204,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) #if defined (DEBUG_RTL8139) int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; #endif - DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", - ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); + DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " + "frame data %d specified MSS=%d\n", ETH_MTU, + ip_data_len, saved_size - ETH_HLEN, large_send_mss); int tcp_send_offset = 0; int send_count = 0; @@ -2220,8 +2230,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) int tcp_data_len = ip_data_len - tcp_hlen; int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", - ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); + DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " + "data len %d TCP chunk size %d\n", ip_data_len, + tcp_hlen, tcp_data_len, tcp_chunk_size); /* note the cycle below overwrites IP header data, but restores it from saved_ip_header before sending packet */ @@ -2239,13 +2250,16 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) chunk_size = tcp_data_len - tcp_send_offset; } - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); + DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", + be32_to_cpu(p_tcp_hdr->th_seq)); /* add 4 TCP pseudoheader fields */ /* copy IP source and destination fields */ memcpy(data_to_checksum, saved_ip_header + 12, 8); - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); + DPRINTF("+++ C+ mode TSO calculating TCP checksum for " + "packet with %d bytes data\n", tcp_hlen + + chunk_size); if (tcp_send_offset) { @@ -2267,7 +2281,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) p_tcp_hdr->th_sum = 0; int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); + DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", + tcp_checksum); p_tcp_hdr->th_sum = tcp_checksum; @@ -2282,10 +2297,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) ip->ip_sum = 0; ip->ip_sum = ip_checksum(eth_payload_data, hlen); - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + DPRINTF("+++ C+ mode TSO IP header len=%d " + "checksum=%04x\n", hlen, ip->ip_sum); int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); + DPRINTF("+++ C+ mode TSO transferring packet size " + "%d\n", tso_send_size); rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0, (uint8_t *) dot1q_buffer); @@ -2299,7 +2316,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) } else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) { - DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); /* maximum IP header length is 60 bytes */ uint8_t saved_ip_header[60]; @@ -2314,7 +2331,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) { - DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); + DPRINTF("+++ C+ mode calculating TCP checksum for " + "packet with %d bytes data\n", ip_data_len); ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; p_tcpip_hdr->zeros = 0; @@ -2326,13 +2344,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) p_tcp_hdr->th_sum = 0; int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); + DPRINTF("+++ C+ mode TCP checksum %04x\n", + tcp_checksum); p_tcp_hdr->th_sum = tcp_checksum; } else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) { - DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); + DPRINTF("+++ C+ mode calculating UDP checksum for " + "packet with %d bytes data\n", ip_data_len); ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; p_udpip_hdr->zeros = 0; @@ -2344,7 +2364,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) p_udp_hdr->uh_sum = 0; int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); + DPRINTF("+++ C+ mode UDP checksum %04x\n", + udp_checksum); p_udp_hdr->uh_sum = udp_checksum; } @@ -2358,7 +2379,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* update tally counter */ ++s->tally_counters.TxOk; - DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); + DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size); rtl8139_transfer_frame(s, saved_buffer, saved_size, 1, (uint8_t *) dot1q_buffer); @@ -2377,7 +2398,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) } else { - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n")); + DPRINTF("+++ C+ mode transmission continue to next descriptor\n"); } return 1; @@ -2395,8 +2416,8 @@ static void rtl8139_cplus_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { - DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", - s->currCPlusTxDesc)); + DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n", + s->currCPlusTxDesc); } else { @@ -2421,7 +2442,8 @@ static void rtl8139_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { - DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc)); + DPRINTF("transmitter queue stalled, current TxDesc = %d\n", + s->currTxDesc); } } @@ -2434,7 +2456,8 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 if (s->cplus_enabled) { - DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); + DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x " + "descriptor=%d\n", txRegOffset, val, descriptor); /* handle Dump Tally Counters command */ s->TxStatus[descriptor] = val; @@ -2453,7 +2476,8 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 return; } - DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); + DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", + txRegOffset, val, descriptor); /* mask only reserved bits */ val &= ~0xff00c000; /* these bits are reset on write */ @@ -2469,7 +2493,7 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset) { uint32_t ret = s->TxStatus[txRegOffset/4]; - DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret)); + DPRINTF("TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret); return ret; } @@ -2501,7 +2525,7 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s) |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; - DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); + DPRINTF("TSAD read val=0x%04x\n", ret); return ret; } @@ -2510,14 +2534,14 @@ static uint16_t rtl8139_CSCR_read(RTL8139State *s) { uint16_t ret = s->CSCR; - DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret)); + DPRINTF("CSCR read val=0x%04x\n", ret); return ret; } static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) { - DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); + DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val); s->TxAddr[txAddrOffset/4] = val; } @@ -2526,20 +2550,20 @@ static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) { uint32_t ret = s->TxAddr[txAddrOffset/4]; - DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); + DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret); return ret; } static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val)); + DPRINTF("RxBufPtr write val=0x%04x\n", val); /* this value is off by 16 */ s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); - DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); + DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); } static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) @@ -2547,7 +2571,7 @@ static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) /* this value is off by 16 */ uint32_t ret = s->RxBufPtr - 0x10; - DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret)); + DPRINTF("RxBufPtr read val=0x%04x\n", ret); return ret; } @@ -2557,14 +2581,14 @@ static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s) /* this value is NOT off by 16 */ uint32_t ret = s->RxBufAddr; - DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret)); + DPRINTF("RxBufAddr read val=0x%04x\n", ret); return ret; } static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val)); + DPRINTF("RxBuf write val=0x%08x\n", val); s->RxBuf = val; @@ -2575,14 +2599,14 @@ static uint32_t rtl8139_RxBuf_read(RTL8139State *s) { uint32_t ret = s->RxBuf; - DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret)); + DPRINTF("RxBuf read val=0x%08x\n", ret); return ret; } static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val)); + DPRINTF("IntrMask write(w) val=0x%04x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0x1e00, s->IntrMask); @@ -2598,14 +2622,14 @@ static uint32_t rtl8139_IntrMask_read(RTL8139State *s) { uint32_t ret = s->IntrMask; - DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret)); + DPRINTF("IntrMask read(w) val=0x%04x\n", ret); return ret; } static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val)); + DPRINTF("IntrStatus write(w) val=0x%04x\n", val); #if 0 @@ -2642,7 +2666,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) uint32_t ret = s->IntrStatus; - DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); + DPRINTF("IntrStatus read(w) val=0x%04x\n", ret); #if 0 @@ -2658,7 +2682,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) { - DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val)); + DPRINTF("MultiIntr write(w) val=0x%04x\n", val); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf000, s->MultiIntr); @@ -2670,7 +2694,7 @@ static uint32_t rtl8139_MultiIntr_read(RTL8139State *s) { uint32_t ret = s->MultiIntr; - DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret)); + DPRINTF("MultiIntr read(w) val=0x%04x\n", ret); return ret; } @@ -2718,11 +2742,12 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case MediaStatus: /* ignore */ - DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val)); + DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n", + val); break; case HltClk: - DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val)); + DPRINTF("HltClk write val=0x%08x\n", val); if (val == 'R') { s->clock_enabled = 1; @@ -2734,27 +2759,29 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case TxThresh: - DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val)); + DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val); s->TxThresh = val; break; case TxPoll: - DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val)); + DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val); if (val & (1 << 7)) { - DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n")); + DPRINTF("C+ TxPoll high priority transmission (not " + "implemented)\n"); //rtl8139_cplus_transmit(s); } if (val & (1 << 6)) { - DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n")); + DPRINTF("C+ TxPoll normal priority transmission\n"); rtl8139_cplus_transmit(s); } break; default: - DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val)); + DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr, + val); break; } } @@ -2790,14 +2817,14 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) rtl8139_BasicModeStatus_write(s, val); break; case NWayAdvert: - DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val)); + DPRINTF("NWayAdvert write(w) val=0x%04x\n", val); s->NWayAdvert = val; break; case NWayLPAR: - DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val)); + DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val); break; case NWayExpansion: - DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val)); + DPRINTF("NWayExpansion write(w) val=0x%04x\n", val); s->NWayExpansion = val; break; @@ -2810,7 +2837,8 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) break; default: - DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); + DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n", + addr, val); rtl8139_io_writeb(opaque, addr, val & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); @@ -2823,7 +2851,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time) int64_t pci_time, next_time; uint32_t low_pci; - DEBUG_PRINT(("RTL8139: entered rtl8139_set_next_tctr_time\n")); + DPRINTF("entered rtl8139_set_next_tctr_time\n"); if (s->TimerExpire && current_time >= s->TimerExpire) { s->IntrStatus |= PCSTimeout; @@ -2867,7 +2895,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) switch (addr) { case RxMissed: - DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n")); + DPRINTF("RxMissed clearing on write\n"); s->RxMissed = 0; break; @@ -2892,23 +2920,23 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) break; case RxRingAddrLO: - DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val)); + DPRINTF("C+ RxRing low bits write val=0x%08x\n", val); s->RxRingAddrLO = val; break; case RxRingAddrHI: - DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val)); + DPRINTF("C+ RxRing high bits write val=0x%08x\n", val); s->RxRingAddrHI = val; break; case Timer: - DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); + DPRINTF("TCTR Timer reset on write\n"); s->TCTR_base = qemu_get_clock_ns(vm_clock); rtl8139_set_next_tctr_time(s, s->TCTR_base); break; case FlashReg: - DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); + DPRINTF("FlashReg TimerInt write val=0x%08x\n", val); if (s->TimerInt != val) { s->TimerInt = val; rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock)); @@ -2916,7 +2944,8 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) break; default: - DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); + DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n", + addr, val); rtl8139_io_writeb(opaque, addr, val & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff); @@ -2967,31 +2996,31 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) case MediaStatus: ret = 0xd0; - DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret)); + DPRINTF("MediaStatus read 0x%x\n", ret); break; case HltClk: ret = s->clock_enabled; - DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret)); + DPRINTF("HltClk read 0x%x\n", ret); break; case PCIRevisionID: ret = RTL8139_PCI_REVID; - DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret)); + DPRINTF("PCI Revision ID read 0x%x\n", ret); break; case TxThresh: ret = s->TxThresh; - DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret)); + DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret); break; case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ ret = s->TxConfig >> 24; - DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret)); + DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret); break; default: - DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr)); + DPRINTF("not implemented read(b) addr=0x%x\n", addr); ret = 0; break; } @@ -3036,15 +3065,15 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; case NWayAdvert: ret = s->NWayAdvert; - DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret)); + DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret); break; case NWayLPAR: ret = s->NWayLPAR; - DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret)); + DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret); break; case NWayExpansion: ret = s->NWayExpansion; - DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret)); + DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret); break; case CpCmd: @@ -3064,12 +3093,12 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; default: - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); + DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr); ret = rtl8139_io_readb(opaque, addr); ret |= rtl8139_io_readb(opaque, addr + 1) << 8; - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); + DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret); break; } @@ -3088,7 +3117,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxMissed: ret = s->RxMissed; - DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret)); + DPRINTF("RxMissed read val=0x%08x\n", ret); break; case TxConfig: @@ -3113,34 +3142,34 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxRingAddrLO: ret = s->RxRingAddrLO; - DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret)); + DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret); break; case RxRingAddrHI: ret = s->RxRingAddrHI; - DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret)); + DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret); break; case Timer: ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base, PCI_FREQUENCY, get_ticks_per_sec()); - DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); + DPRINTF("TCTR Timer read val=0x%08x\n", ret); break; case FlashReg: ret = s->TimerInt; - DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret)); + DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret); break; default: - DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); + DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr); ret = rtl8139_io_readb(opaque, addr); ret |= rtl8139_io_readb(opaque, addr + 1) << 8; ret |= rtl8139_io_readb(opaque, addr + 2) << 16; ret |= rtl8139_io_readb(opaque, addr + 3) << 24; - DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); + DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret); break; } @@ -3385,7 +3414,7 @@ static void rtl8139_timer(void *opaque) if (!s->clock_enabled) { - DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); + DPRINTF(">>> timer: clock is not running\n"); return; } From ec48c7747acd1be25ca70586bc4e6640765e40c8 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier <benjamin.poirier@gmail.com> Date: Wed, 20 Apr 2011 19:39:02 -0400 Subject: [PATCH 312/386] rtl8139: add format attribute to DPRINTF gcc can check the format string for correctness even when debugging output is not enabled. Have to make sure arguments are always available. They are optimized out if unneeded. Signed-off-by: Benjamin Poirier <benjamin.poirier@gmail.com> Cc: Igor V. Kovalenko <igor.v.kovalenko@gmail.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/rtl8139.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 13b14e4e10..cbf667a301 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -88,7 +88,11 @@ # define DPRINTF(fmt, ...) \ do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0) #else -# define DPRINTF(fmt, ...) do { } while (0) +static inline __attribute__ ((format (printf, 1, 2))) + int DPRINTF(const char *fmt, ...) +{ + return 0; +} #endif /* Symbolic offsets to registers. */ @@ -2201,9 +2205,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) { -#if defined (DEBUG_RTL8139) int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; -#endif + DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " "frame data %d specified MSS=%d\n", ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss); From b0b36e5d2e4c8a96c2f6dbc0981a9fd0cde111d8 Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Sun, 24 Apr 2011 17:19:56 +1000 Subject: [PATCH 313/386] doc: fix slirp description net/slirp.c says: /* default settings according to historic slirp */ struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ Which I think is not what the documentation says. Signed-off-by: Brad Hards <bradh@frogmouth.net> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- qemu-options.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 677c550103..489df10c46 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1152,7 +1152,7 @@ Assign symbolic name for use in monitor commands. @item net=@var{addr}[/@var{mask}] Set IP network address the guest will see. Optionally specify the netmask, either in the form a.b.c.d or as number of valid top-most bits. Default is -10.0.2.0/8. +10.0.2.0/24. @item host=@var{addr} Specify the guest-visible address of the host. Default is the 2nd IP in the @@ -1168,7 +1168,7 @@ Specifies the client hostname reported by the builtin DHCP server. @item dhcpstart=@var{addr} Specify the first of the 16 IPs the built-in DHCP server can assign. Default -is the 16th to 31st IP in the guest network, i.e. x.x.x.16 to x.x.x.31. +is the 15th to 31st IP in the guest network, i.e. x.x.x.15 to x.x.x.31. @item dns=@var{addr} Specify the guest-visible address of the virtual nameserver. The address must From 05098a9315819621405eb662baddeec624127d7a Mon Sep 17 00:00:00 2001 From: Riku Voipio <riku.voipio@nokia.com> Date: Fri, 4 Mar 2011 15:27:29 +0200 Subject: [PATCH 314/386] [v2] linux-user: bigger default stack PTHREAD_STACK_MIN (16KB) is somewhat inadequate for a new stack for new QEMU threads. Set new limit to 256K which should be enough, yet doesn't increase memory pressure significantly. Signed-off-by: Riku Voipio <riku.voipio@nokia.com> Reviewed-by: Nathan Froyd <froydnj@codesourcery.com> --- linux-user/syscall.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bb0999d1ab..732f71a6a0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3690,9 +3690,9 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) #endif /* defined(TARGET_I386) */ -#if defined(CONFIG_USE_NPTL) +#define NEW_STACK_SIZE 0x40000 -#define NEW_STACK_SIZE PTHREAD_STACK_MIN +#if defined(CONFIG_USE_NPTL) static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER; typedef struct { @@ -3736,9 +3736,6 @@ static void *clone_func(void *arg) return NULL; } #else -/* this stack is the equivalent of the kernel stack associated with a - thread/process */ -#define NEW_STACK_SIZE 8192 static int clone_func(void *arg) { From 608e55921770bbae1609135aa0c351238f57fc5f Mon Sep 17 00:00:00 2001 From: Laurent Vivier <laurent@vivier.eu> Date: Thu, 7 Apr 2011 00:25:32 +0200 Subject: [PATCH 315/386] linux-user: improve traces Add trace details for getpid(), kill(), _llseek(), rt_sigaction(), rt_sigprocmask(), clone(). Signed-off-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/strace.c | 161 +++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 12 +-- 2 files changed, 167 insertions(+), 6 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 8dd398b9f2..5d9bb085c7 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -9,6 +9,7 @@ #include <sys/mount.h> #include <sys/mman.h> #include <unistd.h> +#include <sched.h> #include "qemu.h" int do_strace=0; @@ -63,6 +64,7 @@ UNUSED static void print_string(abi_long, int); UNUSED static void print_raw_param(const char *, abi_long, int); UNUSED static void print_timeval(abi_ulong, int); UNUSED static void print_number(abi_long, int); +UNUSED static void print_signal(abi_ulong, int); /* * Utility functions @@ -117,6 +119,37 @@ if( cmd == val ) { \ gemu_log("%d",cmd); } +static void +print_signal(abi_ulong arg, int last) +{ + const char *signal_name = NULL; + switch(arg) { + case TARGET_SIGHUP: signal_name = "SIGHUP"; break; + case TARGET_SIGINT: signal_name = "SIGINT"; break; + case TARGET_SIGQUIT: signal_name = "SIGQUIT"; break; + case TARGET_SIGILL: signal_name = "SIGILL"; break; + case TARGET_SIGABRT: signal_name = "SIGABRT"; break; + case TARGET_SIGFPE: signal_name = "SIGFPE"; break; + case TARGET_SIGKILL: signal_name = "SIGKILL"; break; + case TARGET_SIGSEGV: signal_name = "SIGSEGV"; break; + case TARGET_SIGPIPE: signal_name = "SIGPIPE"; break; + case TARGET_SIGALRM: signal_name = "SIGALRM"; break; + case TARGET_SIGTERM: signal_name = "SIGTERM"; break; + case TARGET_SIGUSR1: signal_name = "SIGUSR1"; break; + case TARGET_SIGUSR2: signal_name = "SIGUSR2"; break; + case TARGET_SIGCHLD: signal_name = "SIGCHLD"; break; + case TARGET_SIGCONT: signal_name = "SIGCONT"; break; + case TARGET_SIGSTOP: signal_name = "SIGSTOP"; break; + case TARGET_SIGTTIN: signal_name = "SIGTTIN"; break; + case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break; + } + if (signal_name == NULL) { + print_raw_param("%ld", arg, 1); + return; + } + gemu_log("%s%s", signal_name, get_comma(last)); +} + #ifdef TARGET_NR__newselect static void print_fdset(int n, abi_ulong target_fds_addr) @@ -427,6 +460,32 @@ UNUSED static struct flags fcntl_flags[] = { FLAG_END, }; +UNUSED static struct flags clone_flags[] = { + FLAG_GENERIC(CLONE_VM), + FLAG_GENERIC(CLONE_FS), + FLAG_GENERIC(CLONE_FILES), + FLAG_GENERIC(CLONE_SIGHAND), + FLAG_GENERIC(CLONE_PTRACE), + FLAG_GENERIC(CLONE_VFORK), + FLAG_GENERIC(CLONE_PARENT), + FLAG_GENERIC(CLONE_THREAD), + FLAG_GENERIC(CLONE_NEWNS), + FLAG_GENERIC(CLONE_SYSVSEM), + FLAG_GENERIC(CLONE_SETTLS), + FLAG_GENERIC(CLONE_PARENT_SETTID), + FLAG_GENERIC(CLONE_CHILD_CLEARTID), + FLAG_GENERIC(CLONE_DETACHED), + FLAG_GENERIC(CLONE_UNTRACED), + FLAG_GENERIC(CLONE_CHILD_SETTID), + FLAG_GENERIC(CLONE_NEWUTS), + FLAG_GENERIC(CLONE_NEWIPC), + FLAG_GENERIC(CLONE_NEWUSER), + FLAG_GENERIC(CLONE_NEWPID), + FLAG_GENERIC(CLONE_NEWNET), + FLAG_GENERIC(CLONE_IO), + FLAG_END, +}; + /* * print_xxx utility functions. These are used to print syscall * parameters in certain format. All of these have parameter @@ -669,6 +728,39 @@ print_chmod(const struct syscallname *name, } #endif +#ifdef TARGET_NR_clone +static void +print_clone(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); +#if defined(TARGET_M68K) + print_flags(clone_flags, arg0, 0); + print_raw_param("newsp=0x" TARGET_ABI_FMT_lx, arg1, 1); +#elif defined(TARGET_SH4) || defined(TARGET_ALPHA) + print_flags(clone_flags, arg0, 0); + print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0); + print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0); + print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg3, 0); + print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg4, 1); +#elif defined(TARGET_CRIS) + print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg0, 0); + print_flags(clone_flags, arg1, 0); + print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0); + print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0); + print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1); +#else + print_flags(clone_flags, arg0, 0); + print_raw_param("child_stack=0x" TARGET_ABI_FMT_lx, arg1, 0); + print_raw_param("parent_tidptr=0x" TARGET_ABI_FMT_lx, arg2, 0); + print_raw_param("tls=0x" TARGET_ABI_FMT_lx, arg3, 0); + print_raw_param("child_tidptr=0x" TARGET_ABI_FMT_lx, arg4, 1); +#endif + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_creat static void print_creat(const struct syscallname *name, @@ -805,6 +897,28 @@ print_linkat(const struct syscallname *name, } #endif +#ifdef TARGET_NR__llseek +static void +print__llseek(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + const char *whence = "UNKNOWN"; + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_raw_param("%ld", arg1, 0); + print_raw_param("%ld", arg2, 0); + print_pointer(arg3, 0); + switch(arg4) { + case SEEK_SET: whence = "SEEK_SET"; break; + case SEEK_CUR: whence = "SEEK_CUR"; break; + case SEEK_END: whence = "SEEK_END"; break; + } + gemu_log("%s",whence); + print_syscall_epilogue(name); +} +#endif + #if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) static void @@ -875,6 +989,40 @@ print_rmdir(const struct syscallname *name, } #endif +#ifdef TARGET_NR_rt_sigaction +static void +print_rt_sigaction(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_signal(arg0, 0); + print_pointer(arg1, 0); + print_pointer(arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_rt_sigprocmask +static void +print_rt_sigprocmask(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + const char *how = "UNKNOWN"; + print_syscall_prologue(name); + switch(arg0) { + case TARGET_SIG_BLOCK: how = "SIG_BLOCK"; break; + case TARGET_SIG_UNBLOCK: how = "SIG_UNBLOCK"; break; + case TARGET_SIG_SETMASK: how = "SIG_SETMASK"; break; + } + gemu_log("%s,",how); + print_pointer(arg1, 0); + print_pointer(arg2, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_mknod static void print_mknod(const struct syscallname *name, @@ -1298,6 +1446,19 @@ print_futex(const struct syscallname *name, } #endif +#ifdef TARGET_NR_kill +static void +print_kill(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", arg0, 0); + print_signal(arg1, 1); + print_syscall_epilogue(name); +} +#endif + /* * An array of all of the syscalls we know about */ diff --git a/linux-user/strace.list b/linux-user/strace.list index 563a67f0a2..a7eeaef99f 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -85,7 +85,7 @@ { TARGET_NR_clock_settime, "clock_settime" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_clone -{ TARGET_NR_clone, "clone" , NULL, NULL, NULL }, +{ TARGET_NR_clone, "clone" , NULL, print_clone, NULL }, #endif #ifdef TARGET_NR_close { TARGET_NR_close, "close" , "%s(%d)", NULL, NULL }, @@ -292,7 +292,7 @@ { TARGET_NR_getpgrp, "getpgrp" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_getpid -{ TARGET_NR_getpid, "getpid" , NULL, NULL, NULL }, +{ TARGET_NR_getpid, "getpid" , "%s()", NULL, NULL }, #endif #ifdef TARGET_NR_getpmsg { TARGET_NR_getpmsg, "getpmsg" , NULL, NULL, NULL }, @@ -418,7 +418,7 @@ { TARGET_NR_keyctl, "keyctl" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_kill -{ TARGET_NR_kill, "kill" , NULL, NULL, NULL }, +{ TARGET_NR_kill, "kill", NULL, print_kill, NULL }, #endif #ifdef TARGET_NR_lchown { TARGET_NR_lchown, "lchown" , NULL, NULL, NULL }, @@ -448,7 +448,7 @@ { TARGET_NR_llistxattr, "llistxattr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR__llseek -{ TARGET_NR__llseek, "_llseek" , NULL, NULL, NULL }, +{ TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL }, #endif #ifdef TARGET_NR_lock { TARGET_NR_lock, "lock" , NULL, NULL, NULL }, @@ -1063,13 +1063,13 @@ { TARGET_NR_rmdir, "rmdir" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_rt_sigaction -{ TARGET_NR_rt_sigaction, "rt_sigaction" , NULL, NULL, NULL }, +{ TARGET_NR_rt_sigaction, "rt_sigaction" , NULL, print_rt_sigaction, NULL }, #endif #ifdef TARGET_NR_rt_sigpending { TARGET_NR_rt_sigpending, "rt_sigpending" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_rt_sigprocmask -{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, NULL, NULL }, +{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask, NULL }, #endif #ifdef TARGET_NR_rt_sigqueueinfo { TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, NULL, NULL }, From 059c2f2cd773e0f3d7284a6eab662fd26f9cbad2 Mon Sep 17 00:00:00 2001 From: Laurent Vivier <laurent@vivier.eu> Date: Wed, 30 Mar 2011 00:12:12 +0200 Subject: [PATCH 316/386] linux-user: convert ioctl(SIOCGIFCONF, ...) result. The result needs to be converted as it is stored in an array of struct ifreq and sizeof(struct ifreq) differs according to target and host alignment rules. This patch allows to execute correctly the following program on arm and m68k: #include <stdio.h> #include <sys/ioctl.h> #include <net/if.h> #include <alloca.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void) { int s, ret; struct ifconf ifc; int i; memset( &ifc, 0, sizeof( struct ifconf ) ); ifc.ifc_len = 8 * sizeof(struct ifreq); ifc.ifc_buf = alloca(ifc.ifc_len); s = socket( AF_INET, SOCK_DGRAM, 0 ); if (s < 0) { perror("Cannot open socket"); return 1; } ret = ioctl( s, SIOCGIFCONF, &ifc ); if (s < 0) { perror("ioctl() failed"); return 1; } for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq) ; i ++) { struct sockaddr_in *s; s = (struct sockaddr_in*)&ifc.ifc_req[i].ifr_addr; printf("%s\n", ifc.ifc_req[i].ifr_name); printf("%s\n", inet_ntoa(s->sin_addr)); } } Signed-off-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/ioctls.h | 3 +- linux-user/syscall.c | 96 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 526aaa2a76..ab15b867ec 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -112,7 +112,8 @@ IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) IOCTL(SIOCSIFLINK, 0, TYPE_NULL) - IOCTL(SIOCGIFCONF, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifconf))) + IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf, + MK_PTR(MK_STRUCT(STRUCT_ifconf))) IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 732f71a6a0..123909f190 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -59,6 +59,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, //#include <sys/user.h> #include <netinet/ip.h> #include <netinet/tcp.h> +#include <net/if.h> #include <qemu-common.h> #ifdef TARGET_GPROF #include <sys/gmon.h> @@ -2970,7 +2971,6 @@ static abi_long do_ipc(unsigned int call, int first, #endif /* kernel structure types definitions */ -#define IFNAMSIZ 16 #define STRUCT(name, ...) STRUCT_ ## name, #define STRUCT_SPECIAL(name) STRUCT_ ## name, @@ -3095,6 +3095,100 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp, } #endif +static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg) +{ + const argtype *arg_type = ie->arg_type; + int target_size; + void *argptr; + int ret; + struct ifconf *host_ifconf; + uint32_t outbufsz; + const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) }; + int target_ifreq_size; + int nb_ifreq; + int free_buf = 0; + int i; + int target_ifc_len; + abi_long target_ifc_buf; + int host_ifc_len; + char *host_ifc_buf; + + assert(arg_type[0] == TYPE_PTR); + assert(ie->access == IOC_RW); + + arg_type++; + target_size = thunk_type_size(arg_type, 0); + + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + + host_ifconf = (struct ifconf *)(unsigned long)buf_temp; + target_ifc_len = host_ifconf->ifc_len; + target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf; + + target_ifreq_size = thunk_type_size(ifreq_arg_type, 0); + nb_ifreq = target_ifc_len / target_ifreq_size; + host_ifc_len = nb_ifreq * sizeof(struct ifreq); + + outbufsz = sizeof(*host_ifconf) + host_ifc_len; + if (outbufsz > MAX_STRUCT_SIZE) { + /* We can't fit all the extents into the fixed size buffer. + * Allocate one that is large enough and use it instead. + */ + host_ifconf = malloc(outbufsz); + if (!host_ifconf) { + return -TARGET_ENOMEM; + } + memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf)); + free_buf = 1; + } + host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf); + + host_ifconf->ifc_len = host_ifc_len; + host_ifconf->ifc_buf = host_ifc_buf; + + ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf)); + if (!is_error(ret)) { + /* convert host ifc_len to target ifc_len */ + + nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq); + target_ifc_len = nb_ifreq * target_ifreq_size; + host_ifconf->ifc_len = target_ifc_len; + + /* restore target ifc_buf */ + + host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf; + + /* copy struct ifconf to target user */ + + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; + thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + + /* copy ifreq[] to target user */ + + argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0); + for (i = 0; i < nb_ifreq ; i++) { + thunk_convert(argptr + i * target_ifreq_size, + host_ifc_buf + i * sizeof(struct ifreq), + ifreq_arg_type, THUNK_TARGET); + } + unlock_user(argptr, target_ifc_buf, target_ifc_len); + } + + if (free_buf) { + free(host_ifconf); + } + + return ret; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, From 86fcd9463240c256f00963440fbd084196eeb964 Mon Sep 17 00:00:00 2001 From: Laurent Vivier <laurent@vivier.eu> Date: Wed, 30 Mar 2011 01:35:23 +0200 Subject: [PATCH 317/386] linux-user: add ioctl(SIOCGIWNAME, ...) support. Allow to run properly following program from linux-user: /* cc -o wifi wifi.c */ #include <stdio.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <linux/wireless.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> int main(int argc, char **argv) { int ret; struct ifreq req; struct sockaddr_in *addr; int s; if (argc != 2) { fprintf(stderr, "Need an interface name (like wlan0)\n"); return 1; } s = socket( AF_INET, SOCK_DGRAM, 0 ); if (s < 0) { perror("Cannot open socket"); return 1; } strncpy(req.ifr_name, argv[1], sizeof(req.ifr_name)); ret = ioctl( s, SIOCGIWNAME, &req ); if (ret < 0) { fprintf(stderr, "No wireless extension\n"); return 1; } printf("%s\n", req.ifr_name); printf("%s\n", req.ifr_newname); return 0; } $ ./wifi eth0 No wireless extension $ ./wifi wlan0 wlan0 IEEE 802.11bg Signed-off-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/ioctls.h | 1 + linux-user/syscall.c | 2 +- linux-user/syscall_defs.h | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index ab15b867ec..42b3ae3725 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -122,6 +122,7 @@ IOCTL(SIOCDRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq))) IOCTL(CDROMPAUSE, 0, TYPE_NULL) IOCTL(CDROMSTART, 0, TYPE_NULL) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 123909f190..5f9061d498 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -59,7 +59,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, //#include <sys/user.h> #include <netinet/ip.h> #include <netinet/tcp.h> -#include <net/if.h> +#include <linux/wireless.h> #include <qemu-common.h> #ifdef TARGET_GPROF #include <sys/gmon.h> diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index bde89213de..527f31d0c3 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -765,6 +765,9 @@ struct target_pollfd { #define TARGET_SIOCADDDLCI 0x8980 /* Create new DLCI device */ #define TARGET_SIOCDELDLCI 0x8981 /* Delete DLCI device */ +/* From <linux/wireless.h> */ + +#define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ /* From <linux/fs.h> */ From 42a39fbe0cb6549e9cedfe63e706fdf951126626 Mon Sep 17 00:00:00 2001 From: Alexander Graf <agraf@suse.de> Date: Fri, 15 Apr 2011 17:32:45 +0200 Subject: [PATCH 318/386] linux-user: add s390x to llseek list We keep a list of host architectures that do llseek with the same syscall as lseek. S390x is one of them, so let's add it to the list. Original-patch-by: Ulrich Hecht <uli@suse.de> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5f9061d498..e7af2ea1c0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -197,7 +197,8 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR_sys_inotify_add_watch __NR_inotify_add_watch #define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \ + defined(__s390x__) #define __NR__llseek __NR_lseek #endif From 0c866a7ed47bc8a2df320e59bc669e4784d8ad2f Mon Sep 17 00:00:00 2001 From: Riku Voipio <riku.voipio@iki.fi> Date: Mon, 18 Apr 2011 15:23:06 +0300 Subject: [PATCH 319/386] linux-user: untie syscalls from UID16 Quite a number of uid/gid related syscalls are only defined on systems with USE_UID16 defined. This is apperently based on the idea that these system calls would never be called on non-UID16 systems. Make these syscalls available for all architectures that define them. drop alpha hack to support selected UID16 syscalls. MIPS and PowerPC were also defined as UID16, to get uid/gid syscalls available, drop this error as well. Change QEMU to reflect this. Cc: Ulrich Hecht <uli@suse.de> Cc: Richard Henderson <rth@twiddle.net> Cc: Alexander Graf <agraf@suse.de> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/alpha/syscall_nr.h | 7 ----- linux-user/syscall.c | 48 ++++++++++++++++++++++++++++------- linux-user/syscall_defs.h | 5 +++- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index 7182223381..e3127df4ac 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -412,10 +412,3 @@ #define TARGET_NR_timerfd 477 #define TARGET_NR_eventfd 478 -/* The following aliases are defined in order to match up with the - standard i386 syscalls implemented in syscalls.c. */ -#define TARGET_NR_chown32 TARGET_NR_chown -#define TARGET_NR_setuid32 TARGET_NR_setuid -#define TARGET_NR_setgid32 TARGET_NR_setgid -#define TARGET_NR_setfsuid32 TARGET_NR_setfsuid -#define TARGET_NR_setfsgid32 TARGET_NR_setfsgid diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e7af2ea1c0..e969d1b61d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -328,7 +328,7 @@ static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode) return (fchmodat(dirfd, pathname, mode, 0)); } #endif -#if defined(TARGET_NR_fchownat) && defined(USE_UID16) +#if defined(TARGET_NR_fchownat) static int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { @@ -437,7 +437,7 @@ _syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode) #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) _syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode) #endif -#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16) +#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, uid_t,owner,gid_t,group,int,flags) #endif @@ -4164,7 +4164,31 @@ static inline int low2highgid(int gid) else return gid; } - +static inline int tswapid(int id) +{ + return tswap16(id); +} +#else /* !USE_UID16 */ +static inline int high2lowuid(int uid) +{ + return uid; +} +static inline int high2lowgid(int gid) +{ + return gid; +} +static inline int low2highuid(int uid) +{ + return uid; +} +static inline int low2highgid(int gid) +{ + return gid; +} +static inline int tswapid(int id) +{ + return tswap32(id); +} #endif /* USE_UID16 */ void syscall_init(void) @@ -6765,25 +6789,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = host_to_target_stat64(cpu_env, arg3, &st); break; #endif -#ifdef USE_UID16 case TARGET_NR_lchown: if (!(p = lock_user_string(arg1))) goto efault; ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; +#ifdef TARGET_NR_getuid case TARGET_NR_getuid: ret = get_errno(high2lowuid(getuid())); break; +#endif +#ifdef TARGET_NR_getgid case TARGET_NR_getgid: ret = get_errno(high2lowgid(getgid())); break; +#endif +#ifdef TARGET_NR_geteuid case TARGET_NR_geteuid: ret = get_errno(high2lowuid(geteuid())); break; +#endif +#ifdef TARGET_NR_getegid case TARGET_NR_getegid: ret = get_errno(high2lowgid(getegid())); break; +#endif case TARGET_NR_setreuid: ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); break; @@ -6793,7 +6824,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_getgroups: { int gidsetsize = arg1; - uint16_t *target_grouplist; + target_id *target_grouplist; gid_t *grouplist; int i; @@ -6806,7 +6837,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!target_grouplist) goto efault; for(i = 0;i < ret; i++) - target_grouplist[i] = tswap16(grouplist[i]); + target_grouplist[i] = tswapid(high2lowgid(grouplist[i])); unlock_user(target_grouplist, arg2, gidsetsize * 2); } } @@ -6814,7 +6845,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_setgroups: { int gidsetsize = arg1; - uint16_t *target_grouplist; + target_id *target_grouplist; gid_t *grouplist; int i; @@ -6825,7 +6856,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto fail; } for(i = 0;i < gidsetsize; i++) - grouplist[i] = tswap16(target_grouplist[i]); + grouplist[i] = low2highgid(tswapid(target_grouplist[i])); unlock_user(target_grouplist, arg2, 0); ret = get_errno(setgroups(gidsetsize, grouplist)); } @@ -6901,7 +6932,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_setfsgid: ret = get_errno(setfsgid(arg1)); break; -#endif /* USE_UID16 */ #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 527f31d0c3..e05ddf9120 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -49,9 +49,12 @@ #define TARGET_IOC_TYPEBITS 8 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ - || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) || defined(TARGET_PPC) || defined(TARGET_MIPS) + || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) /* 16 bit uid wrappers emulation */ #define USE_UID16 +#define target_id uint16_t +#else +#define target_id uint32_t #endif #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ From 1a96dd472c37ceeefc0d488cb7722c6714d2f0b7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Fri, 15 Apr 2011 15:23:59 +0200 Subject: [PATCH 320/386] tracetool: allow ) in trace output string Be greedy in matching the trailing "\)*" pattern. Otherwise, all the text in the trace string up to the last closed parenthesis is taken as part of the prototype. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- scripts/tracetool | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tracetool b/scripts/tracetool index 412f695863..9912f368d2 100755 --- a/scripts/tracetool +++ b/scripts/tracetool @@ -51,7 +51,7 @@ get_args() { local args args=${1#*\(} - args=${args%\)*} + args=${args%%\)*} echo "$args" } From b4548fcc0314f5e118ed45b5774e9cd99f9a97d3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Thu, 14 Apr 2011 18:11:00 +0100 Subject: [PATCH 321/386] trace: Remove %s in grlib trace events Trace events cannot use %s in their format strings because trace backends vary in how they can deference pointers (if at all). Recording const char * values is not meaningful if their contents are not recorded too. Change grlib trace events that rely on strings so that they communicate similar information without using strings. A follow-up patch explains this limitation and updates docs/tracing.txt. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- hw/grlib_apbuart.c | 2 +- hw/grlib_gptimer.c | 29 ++++++++++++++--------------- hw/grlib_irqmp.c | 4 ++-- trace-events | 10 +++++----- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 101b150aa5..169a56eb1b 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -133,7 +133,7 @@ grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value) break; } - trace_grlib_apbuart_unknown_register("write", addr); + trace_grlib_apbuart_writel_unknown(addr, value); } static CPUReadMemoryFunc * const grlib_apbuart_read[] = { diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 596a9000a1..99e90336b6 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -165,15 +165,15 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr) /* Unit registers */ switch (addr) { case SCALER_OFFSET: - trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler); + trace_grlib_gptimer_readl(-1, addr, unit->scaler); return unit->scaler; case SCALER_RELOAD_OFFSET: - trace_grlib_gptimer_readl(-1, "reload:", unit->reload); + trace_grlib_gptimer_readl(-1, addr, unit->reload); return unit->reload; case CONFIG_OFFSET: - trace_grlib_gptimer_readl(-1, "config:", unit->config); + trace_grlib_gptimer_readl(-1, addr, unit->config); return unit->config; default: @@ -189,17 +189,16 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr) switch (timer_addr) { case COUNTER_OFFSET: value = ptimer_get_count(unit->timers[id].ptimer); - trace_grlib_gptimer_readl(id, "counter value:", value); + trace_grlib_gptimer_readl(id, addr, value); return value; case COUNTER_RELOAD_OFFSET: value = unit->timers[id].reload; - trace_grlib_gptimer_readl(id, "reload value:", value); + trace_grlib_gptimer_readl(id, addr, value); return value; case CONFIG_OFFSET: - trace_grlib_gptimer_readl(id, "scaler value:", - unit->timers[id].config); + trace_grlib_gptimer_readl(id, addr, unit->timers[id].config); return unit->timers[id].config; default: @@ -208,7 +207,7 @@ static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr) } - trace_grlib_gptimer_unknown_register("read", addr); + trace_grlib_gptimer_readl(-1, addr, 0); return 0; } @@ -226,19 +225,19 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value) case SCALER_OFFSET: value &= 0xFFFF; /* clean up the value */ unit->scaler = value; - trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler); + trace_grlib_gptimer_writel(-1, addr, unit->scaler); return; case SCALER_RELOAD_OFFSET: value &= 0xFFFF; /* clean up the value */ unit->reload = value; - trace_grlib_gptimer_writel(-1, "reload:", unit->reload); + trace_grlib_gptimer_writel(-1, addr, unit->reload); grlib_gptimer_set_scaler(unit, value); return; case CONFIG_OFFSET: /* Read Only (disable timer freeze not supported) */ - trace_grlib_gptimer_writel(-1, "config (Read Only):", 0); + trace_grlib_gptimer_writel(-1, addr, 0); return; default: @@ -253,18 +252,18 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value) /* GPTimer registers */ switch (timer_addr) { case COUNTER_OFFSET: - trace_grlib_gptimer_writel(id, "counter:", value); + trace_grlib_gptimer_writel(id, addr, value); unit->timers[id].counter = value; grlib_gptimer_enable(&unit->timers[id]); return; case COUNTER_RELOAD_OFFSET: - trace_grlib_gptimer_writel(id, "reload:", value); + trace_grlib_gptimer_writel(id, addr, value); unit->timers[id].reload = value; return; case CONFIG_OFFSET: - trace_grlib_gptimer_writel(id, "config:", value); + trace_grlib_gptimer_writel(id, addr, value); if (value & GPTIMER_INT_PENDING) { /* clear pending bit */ @@ -297,7 +296,7 @@ grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value) } - trace_grlib_gptimer_unknown_register("write", addr); + trace_grlib_gptimer_writel(-1, addr, value); } static CPUReadMemoryFunc * const grlib_gptimer_read[] = { diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index f47c491a48..b8738fc04d 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -220,7 +220,7 @@ static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr) return state->extended[cpu]; } - trace_grlib_irqmp_unknown_register("read", addr); + trace_grlib_irqmp_readl_unknown(addr); return 0; } @@ -308,7 +308,7 @@ grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value) return; } - trace_grlib_irqmp_unknown_register("write", addr); + trace_grlib_irqmp_writel_unknown(addr, value); } static CPUReadMemoryFunc * const grlib_irqmp_read[] = { diff --git a/trace-events b/trace-events index 703b745bc4..8272c86c6a 100644 --- a/trace-events +++ b/trace-events @@ -235,19 +235,19 @@ disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable disable grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x" disable grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x" disable grlib_gptimer_hit(int id) "timer:%d HIT" -disable grlib_gptimer_readl(int id, const char *s, uint32_t val) "timer:%d %s 0x%x" -disable grlib_gptimer_writel(int id, const char *s, uint32_t val) "timer:%d %s 0x%x" -disable grlib_gptimer_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64"" +disable grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" +disable grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" # hw/grlib_irqmp.c disable grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n" disable grlib_irqmp_ack(int intno) "interrupt:%d" disable grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d" -disable grlib_irqmp_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64"" +disable grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64"" +disable grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" # hw/grlib_apbuart.c disable grlib_apbuart_event(int event) "event:%d" -disable grlib_apbuart_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64"" +disable grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" # hw/leon3.c disable leon3_set_irq(int intno) "Set CPU IRQ %d" From e6a750aab57e4dccefd6291dba4fee6b9b3bf9ee Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Thu, 14 Apr 2011 18:24:50 +0100 Subject: [PATCH 322/386] docs: Trace events must not expect pointer dereferencing Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- docs/tracing.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/tracing.txt b/docs/tracing.txt index f15069c96b..905a0837db 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -69,6 +69,11 @@ Trace events should use types as follows: cannot include all user-defined struct declarations and it is therefore necessary to use void * for pointers to structs. + Pointers (including char *) cannot be dereferenced easily (or at all) in + some trace backends. If pointers are used, ensure they are meaningful by + themselves and do not assume the data they point to will be traced. Do + not pass in string arguments. + * For everything else, use primitive scalar types (char, int, long) with the appropriate signedness. From 7b92e5bc6d7a61e9e7669b679a87480a6d1ad1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs?= <xscript@gmx.net> Date: Wed, 6 Apr 2011 20:33:56 +0200 Subject: [PATCH 323/386] docs/tracing.txt: minor documentation fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: LluÃs Vilanova <vilanova@ac.upc.edu> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- docs/tracing.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/tracing.txt b/docs/tracing.txt index 905a0837db..c99a0f27cf 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -26,14 +26,14 @@ for debugging, profiling, and observing execution. == Trace events == -There is a set of static trace events declared in the trace-events source +There is a set of static trace events declared in the "trace-events" source file. Each trace event declaration names the event, its arguments, and the format string which can be used for pretty-printing: qemu_malloc(size_t size, void *ptr) "size %zu ptr %p" qemu_free(void *ptr) "ptr %p" -The trace-events file is processed by the tracetool script during build to +The "trace-events" file is processed by the "tracetool" script during build to generate code for the trace events. Trace events are invoked directly from source code like this: @@ -52,10 +52,10 @@ source code like this: === Declaring trace events === -The tracetool script produces the trace.h header file which is included by +The "tracetool" script produces the trace.h header file which is included by every source file that uses trace events. Since many source files include -trace.h, it uses a minimum of types and other header files included to keep -the namespace clean and compile times and dependencies down. +trace.h, it uses a minimum of types and other header files included to keep the +namespace clean and compile times and dependencies down. Trace events should use types as follows: @@ -110,10 +110,10 @@ portability macros, ensure they are preceded and followed by double quotes: == Trace backends == -The tracetool script automates tedious trace event code generation and also +The "tracetool" script automates tedious trace event code generation and also keeps the trace event declarations independent of the trace backend. The trace events are not tightly coupled to a specific trace backend, such as LTTng or -SystemTap. Support for trace backends can be added by extending the tracetool +SystemTap. Support for trace backends can be added by extending the "tracetool" script. The trace backend is chosen at configure time and only one trace backend can @@ -181,12 +181,12 @@ events at runtime inside QEMU: ==== Analyzing trace files ==== The "simple" backend produces binary trace files that can be formatted with the -simpletrace.py script. The script takes the trace-events file and the binary +simpletrace.py script. The script takes the "trace-events" file and the binary trace: ./simpletrace.py trace-events trace-12345 -You must ensure that the same trace-events file was used to build QEMU, +You must ensure that the same "trace-events" file was used to build QEMU, otherwise trace event declarations may have changed and output will not be consistent. From fa2d480a20345b8f10881712dbcf3f5f48b5905b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs?= <xscript@gmx.net> Date: Wed, 6 Apr 2011 20:34:03 +0200 Subject: [PATCH 324/386] trace: [ust] fix generation of 'trace.c' on events without args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: LluÃs Vilanova <vilanova@ac.upc.edu> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- scripts/tracetool | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/tracetool b/scripts/tracetool index 9912f368d2..2155a57df2 100755 --- a/scripts/tracetool +++ b/scripts/tracetool @@ -338,6 +338,7 @@ linetoc_ust() name=$(get_name "$1") args=$(get_args "$1") argnames=$(get_argnames "$1", ",") + [ -z "$argnames" ] || argnames=", $argnames" fmt=$(get_fmt "$1") cat <<EOF @@ -345,7 +346,7 @@ DEFINE_TRACE(ust_$name); static void ust_${name}_probe($args) { - trace_mark(ust, $name, "$fmt", $argnames); + trace_mark(ust, $name, "$fmt"$argnames); } EOF @@ -488,7 +489,7 @@ EOF cat <<EOF $arg = \$arg$i; EOF - i="$((i+1))" + i="$((i+1))" done cat <<EOF @@ -585,7 +586,7 @@ tracetostap() exit 1 fi if [ -z "$probeprefix" ]; then - probeprefix="qemu.$targettype.$targetarch"; + probeprefix="qemu.$targettype.$targetarch"; fi echo "/* This file is autogenerated by tracetool, do not edit. */" convert stap From 2b287af620ac634a156a1c4dd68e937aacbcb144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs?= <xscript@gmx.net> Date: Wed, 6 Apr 2011 20:34:11 +0200 Subject: [PATCH 325/386] trace: [trace-events] fix print formats in some events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: LluÃs Vilanova <vilanova@ac.upc.edu> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- trace-events | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trace-events b/trace-events index 8272c86c6a..77c96a5978 100644 --- a/trace-events +++ b/trace-events @@ -254,8 +254,8 @@ disable leon3_set_irq(int intno) "Set CPU IRQ %d" disable leon3_reset_irq(int intno) "Reset CPU IRQ %d" # spice-qemu-char.c -disable spice_vmc_write(ssize_t out, int len) "spice wrottn %lu of requested %zd" -disable spice_vmc_read(int bytes, int len) "spice read %lu of requested %zd" +disable spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d" +disable spice_vmc_read(int bytes, int len) "spice read %d of requested %d" disable spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" disable spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p" From 71785abaea26e185f7dc19ab376c0ed51d469d90 Mon Sep 17 00:00:00 2001 From: Brad Hards <bradh@frogmouth.net> Date: Sat, 23 Apr 2011 21:50:06 +1000 Subject: [PATCH 326/386] vl: trivial spelling fix Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 68c3b532bc..b46ee663bf 100644 --- a/vl.c +++ b/vl.c @@ -756,7 +756,7 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev, /* * This function returns null terminated string that consist of new line - * separated device pathes. + * separated device paths. * * memory pointed by "size" is assigned total length of the array in bytes * From 19e83f6bdf86f92ee90db77d606affe5b08f8b40 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 26 Apr 2011 16:56:40 +0100 Subject: [PATCH 327/386] configure: Make epoll_create1 test work around SPARC glibc bug Work around a SPARC glibc bug which caused the epoll_create1 configure test to wrongly claim that the function was present. Some versions of SPARC glibc provided the function in the library but didn't declare it in the include file; the result is that gcc warns about an implicit declaration but a link succeeds. So we reference the function as a value rather than a function call to induce a compile time error if the declaration was not present. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> --- configure | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure b/configure index de44bac1d6..2bbbbf5daa 100755 --- a/configure +++ b/configure @@ -2225,7 +2225,15 @@ cat > $TMPC << EOF int main(void) { - epoll_create1(0); + /* Note that we use epoll_create1 as a value, not as + * a function being called. This is necessary so that on + * old SPARC glibc versions where the function was present in + * the library but not declared in the header file we will + * fail the configure check. (Otherwise we will get a compiler + * warning but not an error, and will proceed to fail the + * qemu compile where we compile with -Werror.) + */ + epoll_create1; return 0; } EOF From de3a354a8323296f200a76c0de5984c4d14c0a9e Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Tue, 26 Apr 2011 00:24:07 +0200 Subject: [PATCH 328/386] configure: support target dependent linking This patch is the first attempt to make configure more intelligent with regard to how it links to libraries. It divides the softmmu libraries into two lists, a general one and a list which depends on the target architecture. Signed-off-by: Michael Walle <michael@walle.cc> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 2bbbbf5daa..2c957963e4 100755 --- a/configure +++ b/configure @@ -1946,11 +1946,11 @@ int main(void) { return 0; } EOF if compile_prog "" "$fdt_libs" ; then fdt=yes - libs_softmmu="$fdt_libs $libs_softmmu" else if test "$fdt" = "yes" ; then feature_not_found "fdt" fi + fdt_libs= fdt=no fi fi @@ -1967,11 +1967,11 @@ int main(void) { GL_VERSION; return 0; } EOF if compile_prog "" "-lGL" ; then opengl=yes - libs_softmmu="$opengl_libs $libs_softmmu" else if test "$opengl" = "yes" ; then feature_not_found "opengl" fi + opengl_libs= opengl=no fi fi @@ -3079,6 +3079,7 @@ target_short_alignment=2 target_int_alignment=4 target_long_alignment=4 target_llong_alignment=8 +target_libs_softmmu= TARGET_ARCH="$target_arch2" TARGET_BASE_ARCH="" @@ -3112,6 +3113,7 @@ case "$target_arch2" in ;; lm32) target_phys_bits=32 + target_libs_softmmu="$opengl_libs" ;; m68k) bflt="yes" @@ -3126,6 +3128,7 @@ case "$target_arch2" in bflt="yes" target_nptl="yes" target_phys_bits=32 + target_libs_softmmu="$fdt_libs" ;; mips|mipsel) TARGET_ARCH=mips @@ -3150,6 +3153,7 @@ case "$target_arch2" in gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=32 target_nptl="yes" + target_libs_softmmu="$fdt_libs" ;; ppcemb) TARGET_BASE_ARCH=ppc @@ -3157,6 +3161,7 @@ case "$target_arch2" in gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=64 target_nptl="yes" + target_libs_softmmu="$fdt_libs" ;; ppc64) TARGET_BASE_ARCH=ppc @@ -3164,6 +3169,7 @@ case "$target_arch2" in gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=64 target_long_alignment=8 + target_libs_softmmu="$fdt_libs" ;; ppc64abi32) TARGET_ARCH=ppc64 @@ -3172,6 +3178,7 @@ case "$target_arch2" in echo "TARGET_ABI32=y" >> $config_target_mak gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_phys_bits=64 + target_libs_softmmu="$fdt_libs" ;; sh4|sh4eb) TARGET_ARCH=sh4 @@ -3257,7 +3264,7 @@ fi if test "$target_softmmu" = "yes" ; then echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak echo "CONFIG_SOFTMMU=y" >> $config_target_mak - echo "LIBS+=$libs_softmmu" >> $config_target_mak + echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak echo "HWDIR=../libhw$target_phys_bits" >> $config_target_mak echo "subdir-$target: subdir-libhw$target_phys_bits" >> $config_host_mak fi From 430a3c18064fd3c007048d757e8bd0fff45fcc99 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Tue, 26 Apr 2011 00:09:01 +0200 Subject: [PATCH 329/386] configure: reenable opengl by default Because the opengl library is only linked to for the lm32 target, we can now safely enable opengl by default again. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 2c957963e4..35f7e8b7b2 100755 --- a/configure +++ b/configure @@ -177,7 +177,7 @@ spice="" rbd="" smartcard="" smartcard_nss="" -opengl="no" +opengl="" # parse CC options first for opt do From 9a9d9dba3ea45b2bd1539db021ff7c2d7bfc2a98 Mon Sep 17 00:00:00 2001 From: Anthony Liguori <aliguori@us.ibm.com> Date: Wed, 13 Apr 2011 15:51:47 +0100 Subject: [PATCH 330/386] qemu-img: allow rebase to a NULL backing file when unsafe QEMU can drop a backing file so that an image file no longer depends on the backing file, but this feature has not been exposed in qemu-img. This is useful in an image streaming usecase or when an image file has been fully allocated and no reads can hit the backing file anymore. Since the dropping the backing file can make the image unusable, only allow this when the unsafe flag has been set. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index d9c2c12fa0..ed5ba91117 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1240,7 +1240,7 @@ static int img_rebase(int argc, char **argv) } } - if ((optind >= argc) || !out_baseimg) { + if ((optind >= argc) || (!unsafe && !out_baseimg)) { help(); } filename = argv[optind++]; From 45c7b37fb9c452bcc6fce0ac429ea1d1aa1f9e51 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Thu, 24 Mar 2011 21:31:24 +0100 Subject: [PATCH 331/386] qemu-timer: Add and use new function qemu_timer_expired_ns This simply moves code which is used three times into a new function thus improving readability. Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- qemu-timer.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index b8c0c8870d..f771697574 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -183,6 +183,11 @@ struct qemu_alarm_timer { static struct qemu_alarm_timer *alarm_timer; +static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) +{ + return timer_head && (timer_head->expire_time <= current_time); +} + int qemu_alarm_pending(void) { return alarm_timer->pending; @@ -528,10 +533,9 @@ static void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) pt = &active_timers[ts->clock->type]; for(;;) { t = *pt; - if (!t) - break; - if (t->expire_time > expire_time) + if (!qemu_timer_expired_ns(t, expire_time)) { break; + } pt = &t->next; } ts->expire_time = expire_time; @@ -570,9 +574,7 @@ int qemu_timer_pending(QEMUTimer *ts) int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) { - if (!timer_head) - return 0; - return (timer_head->expire_time <= current_time * timer_head->scale); + return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale); } static void qemu_run_timers(QEMUClock *clock) @@ -587,8 +589,9 @@ static void qemu_run_timers(QEMUClock *clock) ptimer_head = &active_timers[clock->type]; for(;;) { ts = *ptimer_head; - if (!ts || ts->expire_time > current_time) + if (!qemu_timer_expired_ns(ts, current_time)) { break; + } /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; ts->next = NULL; From 2821d0f3abe408ea656898828efb8573ac60f4f4 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Wed, 6 Apr 2011 22:22:48 +0200 Subject: [PATCH 332/386] qemu-timer: Remove unneeded include statement (w32) mmsystem.h is not needed in qemu-timer.h, so remove it. Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- qemu-timer.h | 1 - 1 file changed, 1 deletion(-) diff --git a/qemu-timer.h b/qemu-timer.h index 2cacf65535..06cbe20914 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -7,7 +7,6 @@ #ifdef _WIN32 #include <windows.h> -#include <mmsystem.h> #endif /* timers */ From cd0544ee550cb125d752f765e9d9e7c3fdf464b2 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 10 Apr 2011 20:15:09 +0200 Subject: [PATCH 333/386] qemu-timer: Avoid type casts The type casts are no longer needed after some small changes in struct qemu_alarm_timer. This also improves readability of the code. Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- qemu-timer.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index f771697574..e8e5e15c8e 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -175,8 +175,12 @@ struct qemu_alarm_timer { int (*start)(struct qemu_alarm_timer *t); void (*stop)(struct qemu_alarm_timer *t); void (*rearm)(struct qemu_alarm_timer *t); - void *priv; - +#if defined(__linux__) + int fd; + timer_t timer; +#elif defined(_WIN32) + HANDLE timer; +#endif char expired; char pending; }; @@ -295,18 +299,16 @@ static struct qemu_alarm_timer alarm_timers[] = { #ifndef _WIN32 #ifdef __linux__ {"dynticks", dynticks_start_timer, - dynticks_stop_timer, dynticks_rearm_timer, NULL}, + dynticks_stop_timer, dynticks_rearm_timer}, /* HPET - if available - is preferred */ - {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL}, + {"hpet", hpet_start_timer, hpet_stop_timer, NULL}, /* ...otherwise try RTC */ - {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL}, + {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, #endif - {"unix", unix_start_timer, unix_stop_timer, NULL, NULL}, + {"unix", unix_start_timer, unix_stop_timer, NULL}, #else - {"dynticks", win32_start_timer, - win32_stop_timer, win32_rearm_timer, NULL}, - {"win32", win32_start_timer, - win32_stop_timer, NULL, NULL}, + {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, + {"win32", win32_start_timer, win32_stop_timer, NULL}, #endif {NULL, } }; @@ -864,7 +866,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t) goto fail; enable_sigio_timer(fd); - t->priv = (void *)(long)fd; + t->fd = fd; return 0; fail: @@ -874,7 +876,7 @@ fail: static void hpet_stop_timer(struct qemu_alarm_timer *t) { - int fd = (long)t->priv; + int fd = t->fd; close(fd); } @@ -903,14 +905,14 @@ static int rtc_start_timer(struct qemu_alarm_timer *t) enable_sigio_timer(rtc_fd); - t->priv = (void *)(long)rtc_fd; + t->fd = rtc_fd; return 0; } static void rtc_stop_timer(struct qemu_alarm_timer *t) { - int rtc_fd = (long)t->priv; + int rtc_fd = t->fd; close(rtc_fd); } @@ -945,21 +947,21 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t) return -1; } - t->priv = (void *)(long)host_timer; + t->timer = host_timer; return 0; } static void dynticks_stop_timer(struct qemu_alarm_timer *t) { - timer_t host_timer = (timer_t)(long)t->priv; + timer_t host_timer = t->timer; timer_delete(host_timer); } static void dynticks_rearm_timer(struct qemu_alarm_timer *t) { - timer_t host_timer = (timer_t)(long)t->priv; + timer_t host_timer = t->timer; struct itimerspec timeout; int64_t nearest_delta_ns = INT64_MAX; int64_t current_ns; @@ -1061,13 +1063,13 @@ static int win32_start_timer(struct qemu_alarm_timer *t) return -1; } - t->priv = (PVOID) hTimer; + t->timer = hTimer; return 0; } static void win32_stop_timer(struct qemu_alarm_timer *t) { - HANDLE hTimer = t->priv; + HANDLE hTimer = t->timer; if (hTimer) { DeleteTimerQueueTimer(NULL, hTimer, NULL); @@ -1076,7 +1078,7 @@ static void win32_stop_timer(struct qemu_alarm_timer *t) static void win32_rearm_timer(struct qemu_alarm_timer *t) { - HANDLE hTimer = t->priv; + HANDLE hTimer = t->timer; int nearest_delta_ms; BOOLEAN success; From 2f9cba0c148af32fad6813480f5c92efe17c2d49 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Tue, 5 Apr 2011 18:34:21 +0200 Subject: [PATCH 334/386] qemu-timer: Fix timers for w32 Commit 68c23e5520e8286d79d96ab47c0ea722ceb75041 removed the multimedia timer, but this timer is needed for certain Linux kernels. Otherwise Linux boot stops with this error: MP-BIOS bug: 8254 timer not connected to IO-APIC So the multimedia timer is added again here. Cc: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> --- qemu-timer.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/qemu-timer.c b/qemu-timer.c index e8e5e15c8e..4141b6edbe 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -215,6 +215,10 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) #ifdef _WIN32 +static int mm_start_timer(struct qemu_alarm_timer *t); +static void mm_stop_timer(struct qemu_alarm_timer *t); +static void mm_rearm_timer(struct qemu_alarm_timer *t); + static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); static void win32_rearm_timer(struct qemu_alarm_timer *t); @@ -307,6 +311,8 @@ static struct qemu_alarm_timer alarm_timers[] = { #endif {"unix", unix_start_timer, unix_stop_timer, NULL}, #else + {"mmtimer", mm_start_timer, mm_stop_timer, NULL}, + {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer}, {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, {"win32", win32_start_timer, win32_stop_timer, NULL}, #endif @@ -1040,6 +1046,96 @@ static void unix_stop_timer(struct qemu_alarm_timer *t) #ifdef _WIN32 +static MMRESULT mm_timer; +static unsigned mm_period; + +static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, + DWORD_PTR dwUser, DWORD_PTR dw1, + DWORD_PTR dw2) +{ + struct qemu_alarm_timer *t = alarm_timer; + if (!t) { + return; + } + if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) { + t->expired = alarm_has_dynticks(t); + t->pending = 1; + qemu_notify_event(); + } +} + +static int mm_start_timer(struct qemu_alarm_timer *t) +{ + TIMECAPS tc; + UINT flags; + + memset(&tc, 0, sizeof(tc)); + timeGetDevCaps(&tc, sizeof(tc)); + + mm_period = tc.wPeriodMin; + timeBeginPeriod(mm_period); + + flags = TIME_CALLBACK_FUNCTION; + if (alarm_has_dynticks(t)) { + flags |= TIME_ONESHOT; + } else { + flags |= TIME_PERIODIC; + } + + mm_timer = timeSetEvent(1, /* interval (ms) */ + mm_period, /* resolution */ + mm_alarm_handler, /* function */ + (DWORD_PTR)t, /* parameter */ + flags); + + if (!mm_timer) { + fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", + GetLastError()); + timeEndPeriod(mm_period); + return -1; + } + + return 0; +} + +static void mm_stop_timer(struct qemu_alarm_timer *t) +{ + timeKillEvent(mm_timer); + timeEndPeriod(mm_period); +} + +static void mm_rearm_timer(struct qemu_alarm_timer *t) +{ + int nearest_delta_ms; + + assert(alarm_has_dynticks(t)); + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) { + return; + } + + timeKillEvent(mm_timer); + + nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000; + if (nearest_delta_ms < 1) { + nearest_delta_ms = 1; + } + mm_timer = timeSetEvent(nearest_delta_ms, + mm_period, + mm_alarm_handler, + (DWORD_PTR)t, + TIME_ONESHOT | TIME_CALLBACK_FUNCTION); + + if (!mm_timer) { + fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", + GetLastError()); + + timeEndPeriod(mm_period); + exit(1); + } +} + static int win32_start_timer(struct qemu_alarm_timer *t) { HANDLE hTimer; From 4b9b7092b4cbef084138a446b8247ba89fd474f4 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Mon, 18 Apr 2011 17:15:46 +0530 Subject: [PATCH 335/386] atapi: Add 'medium ready' to 'medium not ready' transition on cd change MMC-5 Table F.1 lists errors that can be thrown for the TEST_UNIT_READY command. Going from medium not ready to medium ready states is communicated by throwing an error. This adds the missing 'tray opened' event that we fail to report to guests. After doing this, older Linux guests properly revalidate a disc on the change command. HSM violation errors, which caused Linux guests to do a soft-reset of the link, also go away: ata2.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 sr 1:0:0:0: CDB: Test Unit Ready: 00 00 00 00 00 00 ata2.00: cmd a0/00:00:00:00:00/00:00:00:00:00/a0 tag 0 res 01/60:00:00:00:00/00:00:00:00:00/a0 Emask 0x3 (HSM violation) ata2.00: status: { ERR } ata2: soft resetting link ata2.00: configured for MWDMA2 ata2: EH complete Signed-off-by: Amit Shah <amit.shah@redhat.com> Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Tested-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/core.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index f028ddb495..d8c613ae0d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1248,12 +1248,19 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_check_status(s); return; } + if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + + s->cdrom_changed = 0; + s->sense_key = SENSE_UNIT_ATTENTION; + s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; + return; + } switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: - if (bdrv_is_inserted(s->bs) && !s->cdrom_changed) { + if (bdrv_is_inserted(s->bs)) { ide_atapi_cmd_ok(s); } else { - s->cdrom_changed = 0; ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } @@ -1734,8 +1741,13 @@ static void cdrom_change_cb(void *opaque, int reason) bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; - s->sense_key = SENSE_UNIT_ATTENTION; - s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; + /* + * First indicate to the guest that a CD has been removed. That's + * done on the next command the guest sends us. + * + * Then we set SENSE_UNIT_ATTENTION, by which the guest will + * detect a new CD in the drive. See ide_atapi_cmd() for details. + */ s->cdrom_changed = 1; s->events.new_media = true; ide_set_irq(s->bus); From ff5c52a379b9fddaf512907e9ffdc275a722e65a Mon Sep 17 00:00:00 2001 From: Avishay Traeger <AVISHAY@il.ibm.com> Date: Sun, 3 Apr 2011 11:31:45 +0300 Subject: [PATCH 336/386] Improve accuracy of block migration bandwidth calculation block_mig_state.total_time is currently the sum of the read request latencies. This is not very accurate because block migration uses aio and so several requests can be submitted at once. Bandwidth should be computed with wall-clock time, not by adding the latencies. In this case, "total_time" has a higher value than it should, and so the computed bandwidth is lower than it is in reality. This means that migration can take longer than it needs to. However, we don't want to use pure wall-clock time here. We are computing bandwidth in the asynchronous phase, where the migration repeatedly wakes up and sends some aio requests. The computed bandwidth will be used for synchronous transfer. Signed-off-by: Avishay Traeger <avishay@il.ibm.com> Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block-migration.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/block-migration.c b/block-migration.c index 576e55a6a3..8d06a23649 100644 --- a/block-migration.c +++ b/block-migration.c @@ -62,7 +62,6 @@ typedef struct BlkMigBlock { QEMUIOVector qiov; BlockDriverAIOCB *aiocb; int ret; - int64_t time; QSIMPLEQ_ENTRY(BlkMigBlock) entry; } BlkMigBlock; @@ -78,6 +77,7 @@ typedef struct BlkMigState { int prev_progress; int bulk_completed; long double total_time; + long double prev_time_offset; int reads; } BlkMigState; @@ -131,12 +131,6 @@ uint64_t blk_mig_bytes_total(void) return sum << BDRV_SECTOR_BITS; } -static inline void add_avg_read_time(int64_t time) -{ - block_mig_state.reads++; - block_mig_state.total_time += time; -} - static inline long double compute_read_bwidth(void) { assert(block_mig_state.total_time != 0); @@ -191,13 +185,14 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds) static void blk_mig_read_cb(void *opaque, int ret) { + long double curr_time = qemu_get_clock_ns(rt_clock); BlkMigBlock *blk = opaque; blk->ret = ret; - blk->time = qemu_get_clock_ns(rt_clock) - blk->time; - - add_avg_read_time(blk->time); + block_mig_state.reads++; + block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset); + block_mig_state.prev_time_offset = curr_time; QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0); @@ -250,7 +245,9 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - blk->time = qemu_get_clock_ns(rt_clock); + if (block_mig_state.submitted == 0) { + block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock); + } blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); @@ -409,7 +406,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - blk->time = qemu_get_clock_ns(rt_clock); + if (block_mig_state.submitted == 0) { + block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock); + } blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); From 33231e0e221543759b11a4a79b54b9a88d4b455e Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Mon, 18 Apr 2011 16:45:49 +0200 Subject: [PATCH 337/386] ide: Split atapi.c out Besides moving code, this patch only fixes some whitespace issues in the moved code and makes all functions in atapi.c static which can be static. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- Makefile.objs | 2 +- hw/ide/atapi.c | 1083 +++++++++++++++++++++++++++++++++++++++++++++ hw/ide/core.c | 1065 +------------------------------------------- hw/ide/internal.h | 10 + 4 files changed, 1098 insertions(+), 1062 deletions(-) create mode 100644 hw/ide/atapi.c diff --git a/Makefile.objs b/Makefile.objs index 44ce368d05..1b446958c5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -242,7 +242,7 @@ hw-obj-$(CONFIG_LAN9118) += lan9118.o hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o # IDE -hw-obj-$(CONFIG_IDE_CORE) += ide/core.o +hw-obj-$(CONFIG_IDE_CORE) += ide/core.o ide/atapi.o hw-obj-$(CONFIG_IDE_QDEV) += ide/qdev.o hw-obj-$(CONFIG_IDE_PCI) += ide/pci.o hw-obj-$(CONFIG_IDE_ISA) += ide/isa.o diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c new file mode 100644 index 0000000000..0edfd580f2 --- /dev/null +++ b/hw/ide/atapi.c @@ -0,0 +1,1083 @@ +/* + * QEMU ATAPI Emulation + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 Openedhand Ltd. + * + * 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 "hw/ide/internal.h" +#include "hw/scsi.h" + +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); + +static void padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + for(i = 0; i < buf_size; i++) { + if (*src) + buf[i] = *src++; + else + buf[i] = ' '; + } +} + +static inline void cpu_to_ube16(uint8_t *buf, int val) +{ + buf[0] = val >> 8; + buf[1] = val & 0xff; +} + +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 & 0xff; +} + +static inline int ube16_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static inline int ube32_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +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; +} + +/* XXX: DVDs that could fit on a CD will be reported as a CD */ +static inline int media_present(IDEState *s) +{ + return (s->nb_sectors > 0); +} + +static inline int media_is_dvd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS); +} + +static inline int media_is_cd(IDEState *s) +{ + return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS); +} + +static void cd_data_to_raw(uint8_t *buf, int lba) +{ + /* sync bytes */ + buf[0] = 0x00; + memset(buf + 1, 0xff, 10); + buf[11] = 0x00; + buf += 12; + /* MSF */ + lba_to_msf(buf, lba); + buf[3] = 0x01; /* mode 1 data */ + buf += 4; + /* data */ + buf += 2048; + /* XXX: ECC not computed */ + memset(buf, 0, 288); +} + +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, + int sector_size) +{ + int ret; + + switch(sector_size) { + case 2048: + ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); + break; + case 2352: + ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + if (ret < 0) + return ret; + cd_data_to_raw(buf, lba); + break; + default: + ret = -EIO; + break; + } + return ret; +} + +void ide_atapi_cmd_ok(IDEState *s) +{ + s->error = 0; + s->status = READY_STAT | SEEK_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s->bus); +} + +void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) +{ +#ifdef DEBUG_IDE_ATAPI + printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); +#endif + s->error = sense_key << 4; + s->status = READY_STAT | ERR_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + s->sense_key = sense_key; + s->asc = asc; + ide_set_irq(s->bus); +} + +void ide_atapi_io_error(IDEState *s, int ret) +{ + /* XXX: handle more errors */ + if (ret == -ENOMEDIUM) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } else { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + } +} + +/* The whole ATAPI transfer logic is handled in this function */ +void ide_atapi_cmd_reply_end(IDEState *s) +{ + int byte_count_limit, size, ret; +#ifdef DEBUG_IDE_ATAPI + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", + s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); +#endif + if (s->packet_transfer_size <= 0) { + /* end of transfer */ + ide_transfer_stop(s); + s->status = READY_STAT | SEEK_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s->bus); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } else { + /* see if a new sector must be read */ + if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + if (ret < 0) { + ide_transfer_stop(s); + ide_atapi_io_error(s, ret); + return; + } + s->lba++; + s->io_buffer_index = 0; + } + if (s->elementary_transfer_size > 0) { + /* there are some data left to transmit in this elementary + transfer */ + size = s->cd_sector_size - s->io_buffer_index; + if (size > s->elementary_transfer_size) + size = s->elementary_transfer_size; + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, + size, ide_atapi_cmd_reply_end); + } else { + /* a new transfer is needed */ + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + byte_count_limit = s->lcyl | (s->hcyl << 8); +#ifdef DEBUG_IDE_ATAPI + printf("byte_count_limit=%d\n", byte_count_limit); +#endif + if (byte_count_limit == 0xffff) + byte_count_limit--; + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) + byte_count_limit--; + size = byte_count_limit; + } + s->lcyl = size; + s->hcyl = size >> 8; + s->elementary_transfer_size = size; + /* we cannot transmit more than one sector at a time */ + if (s->lba != -1) { + if (size > (s->cd_sector_size - s->io_buffer_index)) + size = (s->cd_sector_size - s->io_buffer_index); + } + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, + size, ide_atapi_cmd_reply_end); + ide_set_irq(s->bus); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } + } +} + +/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ +static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) +{ + if (size > max_size) + size = max_size; + s->lba = -1; /* no sector read */ + s->packet_transfer_size = size; + s->io_buffer_size = size; /* dma: send the reply data as one chunk */ + s->elementary_transfer_size = 0; + s->io_buffer_index = 0; + + if (s->atapi_dma) { + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; + s->bus->dma->ops->start_dma(s->bus->dma, s, + ide_atapi_cmd_read_dma_cb); + } else { + s->status = READY_STAT | SEEK_STAT; + ide_atapi_cmd_reply_end(s); + } +} + +/* start a CD-CDROM read command */ +static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ + s->lba = lba; + s->packet_transfer_size = nb_sectors * sector_size; + s->elementary_transfer_size = 0; + s->io_buffer_index = sector_size; + s->cd_sector_size = sector_size; + + s->status = READY_STAT | SEEK_STAT; + ide_atapi_cmd_reply_end(s); +} + +static void ide_atapi_cmd_check_status(IDEState *s) +{ +#ifdef DEBUG_IDE_ATAPI + printf("atapi_cmd_check_status\n"); +#endif + s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4); + s->status = ERR_STAT; + s->nsector = 0; + ide_set_irq(s->bus); +} +/* ATAPI DMA support */ + +/* XXX: handle read errors */ +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) +{ + IDEState *s = opaque; + int data_offset, n; + + if (ret < 0) { + ide_atapi_io_error(s, ret); + goto eot; + } + + if (s->io_buffer_size > 0) { + /* + * For a cdrom read sector command (s->lba != -1), + * adjust the lba for the next s->io_buffer_size chunk + * and dma the current chunk. + * For a command != read (s->lba == -1), just transfer + * the reply data. + */ + if (s->lba != -1) { + if (s->cd_sector_size == 2352) { + n = 1; + cd_data_to_raw(s->io_buffer, s->lba); + } else { + n = s->io_buffer_size >> 11; + } + s->lba += n; + } + s->packet_transfer_size -= s->io_buffer_size; + if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0) + goto eot; + } + + if (s->packet_transfer_size <= 0) { + s->status = READY_STAT | SEEK_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s->bus); + eot: + s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT); + ide_set_inactive(s); + return; + } + + s->io_buffer_index = 0; + if (s->cd_sector_size == 2352) { + n = 1; + s->io_buffer_size = s->cd_sector_size; + data_offset = 16; + } else { + n = s->packet_transfer_size >> 11; + if (n > (IDE_DMA_BUF_SECTORS / 4)) + n = (IDE_DMA_BUF_SECTORS / 4); + s->io_buffer_size = n * 2048; + data_offset = 0; + } +#ifdef DEBUG_AIO + printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); +#endif + s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); + s->bus->dma->iov.iov_len = n * 4 * 512; + qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); + s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2, + &s->bus->dma->qiov, n * 4, + ide_atapi_cmd_read_dma_cb, s); + if (!s->bus->dma->aiocb) { + /* Note: media not present is the most likely case */ + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + goto eot; + } +} + +/* start a CD-CDROM read command with DMA */ +/* XXX: test if DMA is available */ +static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ + s->lba = lba; + s->packet_transfer_size = nb_sectors * sector_size; + s->io_buffer_index = 0; + s->io_buffer_size = 0; + s->cd_sector_size = sector_size; + + /* XXX: check if BUSY_STAT should be set */ + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; + s->bus->dma->ops->start_dma(s->bus->dma, s, + ide_atapi_cmd_read_dma_cb); +} + +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ +#ifdef DEBUG_IDE_ATAPI + printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", + lba, nb_sectors); +#endif + if (s->atapi_dma) { + ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); + } else { + ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); + } +} + +static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, + uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + cpu_to_ube16 (buf_profile, profile); + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +static int ide_dvd_read_structure(IDEState *s, int format, + const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + cpu_to_ube32(buf + 8, 0); /* start sector */ + cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */ + cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 4 + 2); + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 2048 + 2); + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4); + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4); + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4); + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4); + + /* Size of buffer, not including 2 byte size field */ + cpu_to_be16wu((uint16_t *)buf, 16 + 2); + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + +static unsigned int event_status_media(IDEState *s, + uint8_t *buf) +{ + enum media_event_code { + MEC_NO_CHANGE = 0, /* Status unchanged */ + MEC_EJECT_REQUESTED, /* received a request from user to eject */ + MEC_NEW_MEDIA, /* new media inserted and ready for access */ + MEC_MEDIA_REMOVAL, /* only for media changers */ + MEC_MEDIA_CHANGED, /* only for media changers */ + MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */ + MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */ + }; + enum media_status { + MS_TRAY_OPEN = 1, + MS_MEDIA_PRESENT = 2, + }; + uint8_t event_code, media_status; + + media_status = 0; + if (s->bs->tray_open) { + media_status = MS_TRAY_OPEN; + } else if (bdrv_is_inserted(s->bs)) { + media_status = MS_MEDIA_PRESENT; + } + + /* Event notification descriptor */ + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN && s->events.new_media) { + event_code = MEC_NEW_MEDIA; + s->events.new_media = false; + } + + buf[4] = event_code; + buf[5] = media_status; + + /* These fields are reserved, just clear them. */ + buf[6] = 0; + buf[7] = 0; + + return 8; /* We wrote to 4 extra bytes from the header */ +} + +static void handle_get_event_status_notification(IDEState *s, + uint8_t *buf, + const uint8_t *packet) +{ + struct { + uint8_t opcode; + uint8_t polled; /* lsb bit is polled; others are reserved */ + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } __attribute__((packed)) *gesn_cdb; + + struct { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } __attribute((packed)) *gesn_event_header; + + enum notification_class_request_type { + NCR_RESERVED1 = 1 << 0, + NCR_OPERATIONAL_CHANGE = 1 << 1, + NCR_POWER_MANAGEMENT = 1 << 2, + NCR_EXTERNAL_REQUEST = 1 << 3, + NCR_MEDIA = 1 << 4, + NCR_MULTI_HOST = 1 << 5, + NCR_DEVICE_BUSY = 1 << 6, + NCR_RESERVED2 = 1 << 7, + }; + enum event_notification_class_field { + ENC_NO_EVENTS = 0, + ENC_OPERATIONAL_CHANGE, + ENC_POWER_MANAGEMENT, + ENC_EXTERNAL_REQUEST, + ENC_MEDIA, + ENC_MULTIPLE_HOSTS, + ENC_DEVICE_BUSY, + ENC_RESERVED, + }; + unsigned int max_len, used_len; + + gesn_cdb = (void *)packet; + gesn_event_header = (void *)buf; + + max_len = be16_to_cpu(gesn_cdb->len); + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + */ + gesn_event_header->supported_events = NCR_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & NCR_MEDIA) { + gesn_event_header->notification_class |= ENC_MEDIA; + used_len = event_status_media(s, buf); + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = cpu_to_be16(used_len + - sizeof(*gesn_event_header)); + ide_atapi_cmd_reply(s, used_len, max_len); +} + +void ide_atapi_cmd(IDEState *s) +{ + const uint8_t *packet; + uint8_t *buf; + int max_len; + + packet = s->io_buffer; + buf = s->io_buffer; +#ifdef DEBUG_IDE_ATAPI + { + int i; + printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); + for(i = 0; i < ATAPI_PACKET_SIZE; i++) { + printf(" %02x", packet[i]); + } + printf("\n"); + } +#endif + /* + * If there's a UNIT_ATTENTION condition pending, only + * REQUEST_SENSE, INQUIRY, GET_CONFIGURATION and + * GET_EVENT_STATUS_NOTIFICATION commands are allowed to complete. + * MMC-5, section 4.1.6.1 lists only these commands being allowed + * to complete, with other commands getting a CHECK condition + * response unless a higher priority status, defined by the drive + * here, is pending. + */ + if (s->sense_key == SENSE_UNIT_ATTENTION && + s->io_buffer[0] != GPCMD_REQUEST_SENSE && + s->io_buffer[0] != GPCMD_INQUIRY && + s->io_buffer[0] != GPCMD_GET_EVENT_STATUS_NOTIFICATION) { + ide_atapi_cmd_check_status(s); + return; + } + if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + + s->cdrom_changed = 0; + s->sense_key = SENSE_UNIT_ATTENTION; + s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; + return; + } + switch(s->io_buffer[0]) { + case GPCMD_TEST_UNIT_READY: + if (bdrv_is_inserted(s->bs)) { + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + { + int action, code; + if (packet[0] == GPCMD_MODE_SENSE_10) + max_len = ube16_to_cpu(packet + 7); + else + max_len = packet[4]; + action = packet[2] >> 6; + code = packet[2] & 0x3f; + switch(action) { + case 0: /* current values */ + switch(code) { + case GPMODE_R_W_ERROR_PAGE: /* error recovery */ + cpu_to_ube16(&buf[0], 16 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x01; + buf[9] = 0x06; + buf[10] = 0x00; + buf[11] = 0x05; + buf[12] = 0x00; + buf[13] = 0x00; + buf[14] = 0x00; + buf[15] = 0x00; + ide_atapi_cmd_reply(s, 16, max_len); + break; + case GPMODE_AUDIO_CTL_PAGE: + cpu_to_ube16(&buf[0], 24 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + /* Fill with CDROM audio volume */ + buf[17] = 0; + buf[19] = 0; + buf[21] = 0; + buf[23] = 0; + + ide_atapi_cmd_reply(s, 24, max_len); + break; + case GPMODE_CAPABILITIES_PAGE: + cpu_to_ube16(&buf[0], 28 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x2a; + buf[9] = 0x12; + buf[10] = 0x00; + buf[11] = 0x00; + + /* Claim PLAY_AUDIO capability (0x01) since some Linux + code checks for this to automount media. */ + buf[12] = 0x71; + buf[13] = 3 << 5; + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); + if (bdrv_is_locked(s->bs)) + buf[6] |= 1 << 1; + buf[15] = 0x00; + cpu_to_ube16(&buf[16], 706); + buf[18] = 0; + buf[19] = 2; + cpu_to_ube16(&buf[20], 512); + cpu_to_ube16(&buf[22], 706); + buf[24] = 0; + buf[25] = 0; + buf[26] = 0; + buf[27] = 0; + ide_atapi_cmd_reply(s, 28, max_len); + break; + default: + goto error_cmd; + } + break; + case 1: /* changeable values */ + goto error_cmd; + case 2: /* default values */ + goto error_cmd; + default: + case 3: /* saved values */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); + break; + } + } + break; + case GPCMD_REQUEST_SENSE: + max_len = packet[4]; + memset(buf, 0, 18); + buf[0] = 0x70 | (1 << 7); + buf[2] = s->sense_key; + buf[7] = 10; + buf[12] = s->asc; + if (s->sense_key == SENSE_UNIT_ATTENTION) + s->sense_key = SENSE_NONE; + ide_atapi_cmd_reply(s, 18, max_len); + break; + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + bdrv_set_locked(s->bs, packet[4] & 1); + ide_atapi_cmd_ok(s); + break; + case GPCMD_READ_10: + case GPCMD_READ_12: + { + int nb_sectors, lba; + + if (packet[0] == GPCMD_READ_10) + nb_sectors = ube16_to_cpu(packet + 7); + else + nb_sectors = ube32_to_cpu(packet + 6); + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + } + break; + case GPCMD_READ_CD: + { + int nb_sectors, lba, transfer_request; + + nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + transfer_request = packet[9]; + switch(transfer_request & 0xf8) { + case 0x00: + /* nothing */ + ide_atapi_cmd_ok(s); + break; + case 0x10: + /* normal read */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + break; + case 0xf8: + /* read all data */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2352); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_SEEK: + { + unsigned int lba; + uint64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + lba = ube32_to_cpu(packet + 2); + if (lba >= total_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_START_STOP_UNIT: + { + int start, eject, sense, err = 0; + start = packet[4] & 1; + eject = (packet[4] >> 1) & 1; + + if (eject) { + err = bdrv_eject(s->bs, !start); + } + + switch (err) { + case 0: + ide_atapi_cmd_ok(s); + break; + case -EBUSY: + sense = SENSE_NOT_READY; + if (bdrv_is_inserted(s->bs)) { + sense = SENSE_ILLEGAL_REQUEST; + } + ide_atapi_cmd_error(s, sense, + ASC_MEDIA_REMOVAL_PREVENTED); + break; + default: + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + } + break; + case GPCMD_MECHANISM_STATUS: + { + max_len = ube16_to_cpu(packet + 8); + cpu_to_ube16(buf, 0); + /* no current LBA */ + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; + cpu_to_ube16(buf + 6, 0); + ide_atapi_cmd_reply(s, 8, max_len); + } + break; + case GPCMD_READ_TOC_PMA_ATIP: + { + int format, msf, start_track, len; + uint64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + max_len = ube16_to_cpu(packet + 7); + format = packet[9] >> 6; + msf = (packet[1] >> 1) & 1; + start_track = packet[6]; + switch(format) { + case 0: + len = cdrom_read_toc(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + ide_atapi_cmd_reply(s, 12, max_len); + break; + case 2: + len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + default: + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_READ_CDVD_CAPACITY: + { + uint64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, total_sectors - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); + } + break; + case GPCMD_READ_DVD_STRUCTURE: + { + int media = packet[1]; + int format = packet[7]; + int ret; + + max_len = ube16_to_cpu(packet + 8); + + if (format < 0xff) { + if (media_is_cd(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INCOMPATIBLE_FORMAT); + break; + } else if (!media_present(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + + memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? + IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); + + switch (format) { + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = ide_dvd_read_structure(s, format, packet, buf); + + if (ret < 0) + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); + else + ide_atapi_cmd_reply(s, ret, max_len); + + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_SET_SPEED: + ide_atapi_cmd_ok(s); + break; + case GPCMD_INQUIRY: + max_len = packet[4]; + buf[0] = 0x05; /* CD-ROM */ + buf[1] = 0x80; /* removable */ + buf[2] = 0x00; /* ISO */ + buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ + buf[4] = 31; /* additional length */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* reserved */ + padstr8(buf + 8, 8, "QEMU"); + padstr8(buf + 16, 16, "QEMU DVD-ROM"); + padstr8(buf + 32, 4, s->version); + ide_atapi_cmd_reply(s, 36, max_len); + break; + case GPCMD_GET_CONFIGURATION: + { + uint32_t len; + uint8_t index = 0; + + /* only feature 0 is supported */ + if (packet[2] != 0 || packet[3] != 0) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + + /* XXX: could result in alignment problems in some architectures */ + max_len = ube16_to_cpu(packet + 7); + + /* + * XXX: avoid overflow for io_buffer if max_len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (max_len > 512) /* XXX: assume 1 sector */ + max_len = 512; + + memset(buf, 0, max_len); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (media_is_dvd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); + else if (media_is_cd(s)) + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); + + buf[10] = 0x02 | 0x01; /* persistent and current */ + len = 12; /* headers: 8 + 4 */ + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); + cpu_to_ube32(buf, len - 4); /* data length */ + + ide_atapi_cmd_reply(s, len, max_len); + break; + } + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + handle_get_event_status_notification(s, buf, packet); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_ILLEGAL_OPCODE); + break; + } +} diff --git a/hw/ide/core.c b/hw/ide/core.c index d8c613ae0d..90f553b69b 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -25,7 +25,6 @@ #include <hw/hw.h> #include <hw/pc.h> #include <hw/pci.h> -#include <hw/scsi.h> #include "qemu-error.h" #include "qemu-timer.h" #include "sysemu.h" @@ -56,23 +55,6 @@ static const int smart_attributes[][12] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; -/* XXX: DVDs that could fit on a CD will be reported as a CD */ -static inline int media_present(IDEState *s) -{ - return (s->nb_sectors > 0); -} - -static inline int media_is_dvd(IDEState *s) -{ - return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS); -} - -static inline int media_is_cd(IDEState *s) -{ - return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS); -} - -static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); static int ide_handle_rw_error(IDEState *s, int error, int op); static void padstr(char *str, const char *src, int len) @@ -87,17 +69,6 @@ static void padstr(char *str, const char *src, int len) } } -static void padstr8(uint8_t *buf, int buf_size, const char *src) -{ - int i; - for(i = 0; i < buf_size; i++) { - if (*src) - buf[i] = *src++; - else - buf[i] = ' '; - } -} - static void put_le16(uint16_t *p, unsigned int v) { *p = cpu_to_le16(v); @@ -335,8 +306,8 @@ static inline void ide_abort_command(IDEState *s) } /* prepare data transfer and tell what to do after */ -static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, - EndTransferFunc *end_transfer_func) +void ide_transfer_start(IDEState *s, uint8_t *buf, int size, + EndTransferFunc *end_transfer_func) { s->end_transfer_func = end_transfer_func; s->data_ptr = buf; @@ -347,7 +318,7 @@ static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, s->bus->dma->ops->start_transfer(s->bus->dma); } -static void ide_transfer_stop(IDEState *s) +void ide_transfer_stop(IDEState *s) { s->end_transfer_func = ide_transfer_stop; s->data_ptr = s->io_buffer; @@ -447,7 +418,7 @@ static void dma_buf_commit(IDEState *s, int is_write) qemu_sglist_destroy(&s->sg); } -static void ide_set_inactive(IDEState *s) +void ide_set_inactive(IDEState *s) { s->bus->dma->aiocb = NULL; s->bus->dma->ops->set_inactive(s->bus->dma); @@ -617,38 +588,6 @@ void ide_sector_write(IDEState *s) } } -void ide_atapi_cmd_ok(IDEState *s) -{ - s->error = 0; - s->status = READY_STAT | SEEK_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s->bus); -} - -void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) -{ -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); -#endif - s->error = sense_key << 4; - s->status = READY_STAT | ERR_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - s->sense_key = sense_key; - s->asc = asc; - ide_set_irq(s->bus); -} - -static void ide_atapi_cmd_check_status(IDEState *s) -{ -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_check_status\n"); -#endif - s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4); - s->status = ERR_STAT; - s->nsector = 0; - ide_set_irq(s->bus); -} - static void ide_flush_cb(void *opaque, int ret) { IDEState *s = opaque; @@ -679,1002 +618,6 @@ void ide_flush_cache(IDEState *s) } } -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val & 0xff; -} - -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 & 0xff; -} - -static inline int ube16_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 8) | buf[1]; -} - -static inline int ube32_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -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; -} - -static void cd_data_to_raw(uint8_t *buf, int lba) -{ - /* sync bytes */ - buf[0] = 0x00; - memset(buf + 1, 0xff, 10); - buf[11] = 0x00; - buf += 12; - /* MSF */ - lba_to_msf(buf, lba); - buf[3] = 0x01; /* mode 1 data */ - buf += 4; - /* data */ - buf += 2048; - /* XXX: ECC not computed */ - memset(buf, 0, 288); -} - -static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, - int sector_size) -{ - int ret; - - switch(sector_size) { - case 2048: - ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); - break; - case 2352: - ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); - if (ret < 0) - return ret; - cd_data_to_raw(buf, lba); - break; - default: - ret = -EIO; - break; - } - return ret; -} - -void ide_atapi_io_error(IDEState *s, int ret) -{ - /* XXX: handle more errors */ - if (ret == -ENOMEDIUM) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } else { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - } -} - -/* The whole ATAPI transfer logic is handled in this function */ -static void ide_atapi_cmd_reply_end(IDEState *s) -{ - int byte_count_limit, size, ret; -#ifdef DEBUG_IDE_ATAPI - printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", - s->packet_transfer_size, - s->elementary_transfer_size, - s->io_buffer_index); -#endif - if (s->packet_transfer_size <= 0) { - /* end of transfer */ - ide_transfer_stop(s); - s->status = READY_STAT | SEEK_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s->bus); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } else { - /* see if a new sector must be read */ - if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { - ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); - if (ret < 0) { - ide_transfer_stop(s); - ide_atapi_io_error(s, ret); - return; - } - s->lba++; - s->io_buffer_index = 0; - } - if (s->elementary_transfer_size > 0) { - /* there are some data left to transmit in this elementary - transfer */ - size = s->cd_sector_size - s->io_buffer_index; - if (size > s->elementary_transfer_size) - size = s->elementary_transfer_size; - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, - size, ide_atapi_cmd_reply_end); - } else { - /* a new transfer is needed */ - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; - byte_count_limit = s->lcyl | (s->hcyl << 8); -#ifdef DEBUG_IDE_ATAPI - printf("byte_count_limit=%d\n", byte_count_limit); -#endif - if (byte_count_limit == 0xffff) - byte_count_limit--; - size = s->packet_transfer_size; - if (size > byte_count_limit) { - /* byte count limit must be even if this case */ - if (byte_count_limit & 1) - byte_count_limit--; - size = byte_count_limit; - } - s->lcyl = size; - s->hcyl = size >> 8; - s->elementary_transfer_size = size; - /* we cannot transmit more than one sector at a time */ - if (s->lba != -1) { - if (size > (s->cd_sector_size - s->io_buffer_index)) - size = (s->cd_sector_size - s->io_buffer_index); - } - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, - size, ide_atapi_cmd_reply_end); - ide_set_irq(s->bus); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } - } -} - -/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ -static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) -{ - if (size > max_size) - size = max_size; - s->lba = -1; /* no sector read */ - s->packet_transfer_size = size; - s->io_buffer_size = size; /* dma: send the reply data as one chunk */ - s->elementary_transfer_size = 0; - s->io_buffer_index = 0; - - if (s->atapi_dma) { - s->status = READY_STAT | SEEK_STAT | DRQ_STAT; - s->bus->dma->ops->start_dma(s->bus->dma, s, - ide_atapi_cmd_read_dma_cb); - } else { - s->status = READY_STAT | SEEK_STAT; - ide_atapi_cmd_reply_end(s); - } -} - -/* start a CD-CDROM read command */ -static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ - s->lba = lba; - s->packet_transfer_size = nb_sectors * sector_size; - s->elementary_transfer_size = 0; - s->io_buffer_index = sector_size; - s->cd_sector_size = sector_size; - - s->status = READY_STAT | SEEK_STAT; - ide_atapi_cmd_reply_end(s); -} - -/* ATAPI DMA support */ - -/* XXX: handle read errors */ -static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) -{ - IDEState *s = opaque; - int data_offset, n; - - if (ret < 0) { - ide_atapi_io_error(s, ret); - goto eot; - } - - if (s->io_buffer_size > 0) { - /* - * For a cdrom read sector command (s->lba != -1), - * adjust the lba for the next s->io_buffer_size chunk - * and dma the current chunk. - * For a command != read (s->lba == -1), just transfer - * the reply data. - */ - if (s->lba != -1) { - if (s->cd_sector_size == 2352) { - n = 1; - cd_data_to_raw(s->io_buffer, s->lba); - } else { - n = s->io_buffer_size >> 11; - } - s->lba += n; - } - s->packet_transfer_size -= s->io_buffer_size; - if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0) - goto eot; - } - - if (s->packet_transfer_size <= 0) { - s->status = READY_STAT | SEEK_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s->bus); - eot: - s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT); - ide_set_inactive(s); - return; - } - - s->io_buffer_index = 0; - if (s->cd_sector_size == 2352) { - n = 1; - s->io_buffer_size = s->cd_sector_size; - data_offset = 16; - } else { - n = s->packet_transfer_size >> 11; - if (n > (IDE_DMA_BUF_SECTORS / 4)) - n = (IDE_DMA_BUF_SECTORS / 4); - s->io_buffer_size = n * 2048; - data_offset = 0; - } -#ifdef DEBUG_AIO - printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); -#endif - s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); - s->bus->dma->iov.iov_len = n * 4 * 512; - qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); - s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2, - &s->bus->dma->qiov, n * 4, - ide_atapi_cmd_read_dma_cb, s); - if (!s->bus->dma->aiocb) { - /* Note: media not present is the most likely case */ - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - goto eot; - } -} - -/* start a CD-CDROM read command with DMA */ -/* XXX: test if DMA is available */ -static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ - s->lba = lba; - s->packet_transfer_size = nb_sectors * sector_size; - s->io_buffer_index = 0; - s->io_buffer_size = 0; - s->cd_sector_size = sector_size; - - /* XXX: check if BUSY_STAT should be set */ - s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; - s->bus->dma->ops->start_dma(s->bus->dma, s, - ide_atapi_cmd_read_dma_cb); -} - -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ -#ifdef DEBUG_IDE_ATAPI - printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", - lba, nb_sectors); -#endif - if (s->atapi_dma) { - ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); - } else { - ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); - } -} - -static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, - uint16_t profile) -{ - uint8_t *buf_profile = buf + 12; /* start of profiles */ - - buf_profile += ((*index) * 4); /* start of indexed profile */ - cpu_to_ube16 (buf_profile, profile); - buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); - - /* each profile adds 4 bytes to the response */ - (*index)++; - buf[11] += 4; /* Additional Length */ - - return 4; -} - -static int ide_dvd_read_structure(IDEState *s, int format, - const uint8_t *packet, uint8_t *buf) -{ - switch (format) { - case 0x0: /* Physical format information */ - { - int layer = packet[6]; - uint64_t total_sectors; - - if (layer != 0) - return -ASC_INV_FIELD_IN_CMD_PACKET; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) - return -ASC_MEDIUM_NOT_PRESENT; - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - cpu_to_ube32(buf + 8, 0); /* start sector */ - cpu_to_ube32(buf + 12, total_sectors - 1); /* end sector */ - cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */ - - /* Size of buffer, not including 2 byte size field */ - cpu_to_be16wu((uint16_t *)buf, 2048 + 2); - - /* 2k data + 4 byte header */ - return (2048 + 4); - } - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - cpu_to_be16wu((uint16_t *)buf, 4 + 2); - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - cpu_to_be16wu((uint16_t *)buf, 2048 + 2); - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4); - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4); - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4); - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4); - - /* Size of buffer, not including 2 byte size field */ - cpu_to_be16wu((uint16_t *)buf, 16 + 2); - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - } -} - -static unsigned int event_status_media(IDEState *s, - uint8_t *buf) -{ - enum media_event_code { - MEC_NO_CHANGE = 0, /* Status unchanged */ - MEC_EJECT_REQUESTED, /* received a request from user to eject */ - MEC_NEW_MEDIA, /* new media inserted and ready for access */ - MEC_MEDIA_REMOVAL, /* only for media changers */ - MEC_MEDIA_CHANGED, /* only for media changers */ - MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */ - MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */ - }; - enum media_status { - MS_TRAY_OPEN = 1, - MS_MEDIA_PRESENT = 2, - }; - uint8_t event_code, media_status; - - media_status = 0; - if (s->bs->tray_open) { - media_status = MS_TRAY_OPEN; - } else if (bdrv_is_inserted(s->bs)) { - media_status = MS_MEDIA_PRESENT; - } - - /* Event notification descriptor */ - event_code = MEC_NO_CHANGE; - if (media_status != MS_TRAY_OPEN && s->events.new_media) { - event_code = MEC_NEW_MEDIA; - s->events.new_media = false; - } - - buf[4] = event_code; - buf[5] = media_status; - - /* These fields are reserved, just clear them. */ - buf[6] = 0; - buf[7] = 0; - - return 8; /* We wrote to 4 extra bytes from the header */ -} - -static void handle_get_event_status_notification(IDEState *s, - uint8_t *buf, - const uint8_t *packet) -{ - struct { - uint8_t opcode; - uint8_t polled; /* lsb bit is polled; others are reserved */ - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; - } __attribute__((packed)) *gesn_cdb; - - struct { - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; - } __attribute((packed)) *gesn_event_header; - - enum notification_class_request_type { - NCR_RESERVED1 = 1 << 0, - NCR_OPERATIONAL_CHANGE = 1 << 1, - NCR_POWER_MANAGEMENT = 1 << 2, - NCR_EXTERNAL_REQUEST = 1 << 3, - NCR_MEDIA = 1 << 4, - NCR_MULTI_HOST = 1 << 5, - NCR_DEVICE_BUSY = 1 << 6, - NCR_RESERVED2 = 1 << 7, - }; - enum event_notification_class_field { - ENC_NO_EVENTS = 0, - ENC_OPERATIONAL_CHANGE, - ENC_POWER_MANAGEMENT, - ENC_EXTERNAL_REQUEST, - ENC_MEDIA, - ENC_MULTIPLE_HOSTS, - ENC_DEVICE_BUSY, - ENC_RESERVED, - }; - unsigned int max_len, used_len; - - gesn_cdb = (void *)packet; - gesn_event_header = (void *)buf; - - max_len = be16_to_cpu(gesn_cdb->len); - - /* It is fine by the MMC spec to not support async mode operations */ - if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - return; - } - - /* polling mode operation */ - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - */ - gesn_event_header->supported_events = NCR_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & NCR_MEDIA) { - gesn_event_header->notification_class |= ENC_MEDIA; - used_len = event_status_media(s, buf); - } else { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = cpu_to_be16(used_len - - sizeof(*gesn_event_header)); - ide_atapi_cmd_reply(s, used_len, max_len); -} - -static void ide_atapi_cmd(IDEState *s) -{ - const uint8_t *packet; - uint8_t *buf; - int max_len; - - packet = s->io_buffer; - buf = s->io_buffer; -#ifdef DEBUG_IDE_ATAPI - { - int i; - printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); - for(i = 0; i < ATAPI_PACKET_SIZE; i++) { - printf(" %02x", packet[i]); - } - printf("\n"); - } -#endif - /* - * If there's a UNIT_ATTENTION condition pending, only - * REQUEST_SENSE, INQUIRY, GET_CONFIGURATION and - * GET_EVENT_STATUS_NOTIFICATION commands are allowed to complete. - * MMC-5, section 4.1.6.1 lists only these commands being allowed - * to complete, with other commands getting a CHECK condition - * response unless a higher priority status, defined by the drive - * here, is pending. - */ - if (s->sense_key == SENSE_UNIT_ATTENTION && - s->io_buffer[0] != GPCMD_REQUEST_SENSE && - s->io_buffer[0] != GPCMD_INQUIRY && - s->io_buffer[0] != GPCMD_GET_EVENT_STATUS_NOTIFICATION) { - ide_atapi_cmd_check_status(s); - return; - } - if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - - s->cdrom_changed = 0; - s->sense_key = SENSE_UNIT_ATTENTION; - s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; - return; - } - switch(s->io_buffer[0]) { - case GPCMD_TEST_UNIT_READY: - if (bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - { - int action, code; - if (packet[0] == GPCMD_MODE_SENSE_10) - max_len = ube16_to_cpu(packet + 7); - else - max_len = packet[4]; - action = packet[2] >> 6; - code = packet[2] & 0x3f; - switch(action) { - case 0: /* current values */ - switch(code) { - case GPMODE_R_W_ERROR_PAGE: /* error recovery */ - cpu_to_ube16(&buf[0], 16 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x01; - buf[9] = 0x06; - buf[10] = 0x00; - buf[11] = 0x05; - buf[12] = 0x00; - buf[13] = 0x00; - buf[14] = 0x00; - buf[15] = 0x00; - ide_atapi_cmd_reply(s, 16, max_len); - break; - case GPMODE_AUDIO_CTL_PAGE: - cpu_to_ube16(&buf[0], 24 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - /* Fill with CDROM audio volume */ - buf[17] = 0; - buf[19] = 0; - buf[21] = 0; - buf[23] = 0; - - ide_atapi_cmd_reply(s, 24, max_len); - break; - case GPMODE_CAPABILITIES_PAGE: - cpu_to_ube16(&buf[0], 28 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x2a; - buf[9] = 0x12; - buf[10] = 0x00; - buf[11] = 0x00; - - /* Claim PLAY_AUDIO capability (0x01) since some Linux - code checks for this to automount media. */ - buf[12] = 0x71; - buf[13] = 3 << 5; - buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (bdrv_is_locked(s->bs)) - buf[6] |= 1 << 1; - buf[15] = 0x00; - cpu_to_ube16(&buf[16], 706); - buf[18] = 0; - buf[19] = 2; - cpu_to_ube16(&buf[20], 512); - cpu_to_ube16(&buf[22], 706); - buf[24] = 0; - buf[25] = 0; - buf[26] = 0; - buf[27] = 0; - ide_atapi_cmd_reply(s, 28, max_len); - break; - default: - goto error_cmd; - } - break; - case 1: /* changeable values */ - goto error_cmd; - case 2: /* default values */ - goto error_cmd; - default: - case 3: /* saved values */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_SAVING_PARAMETERS_NOT_SUPPORTED); - break; - } - } - break; - case GPCMD_REQUEST_SENSE: - max_len = packet[4]; - memset(buf, 0, 18); - buf[0] = 0x70 | (1 << 7); - buf[2] = s->sense_key; - buf[7] = 10; - buf[12] = s->asc; - if (s->sense_key == SENSE_UNIT_ATTENTION) - s->sense_key = SENSE_NONE; - ide_atapi_cmd_reply(s, 18, max_len); - break; - case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - bdrv_set_locked(s->bs, packet[4] & 1); - ide_atapi_cmd_ok(s); - break; - case GPCMD_READ_10: - case GPCMD_READ_12: - { - int nb_sectors, lba; - - if (packet[0] == GPCMD_READ_10) - nb_sectors = ube16_to_cpu(packet + 7); - else - nb_sectors = ube32_to_cpu(packet + 6); - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - } - break; - case GPCMD_READ_CD: - { - int nb_sectors, lba, transfer_request; - - nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - transfer_request = packet[9]; - switch(transfer_request & 0xf8) { - case 0x00: - /* nothing */ - ide_atapi_cmd_ok(s); - break; - case 0x10: - /* normal read */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - break; - case 0xf8: - /* read all data */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2352); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - break; - case GPCMD_SEEK: - { - unsigned int lba; - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - lba = ube32_to_cpu(packet + 2); - if (lba >= total_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_ok(s); - } - break; - case GPCMD_START_STOP_UNIT: - { - int start, eject, sense, err = 0; - start = packet[4] & 1; - eject = (packet[4] >> 1) & 1; - - if (eject) { - err = bdrv_eject(s->bs, !start); - } - - switch (err) { - case 0: - ide_atapi_cmd_ok(s); - break; - case -EBUSY: - sense = SENSE_NOT_READY; - if (bdrv_is_inserted(s->bs)) { - sense = SENSE_ILLEGAL_REQUEST; - } - ide_atapi_cmd_error(s, sense, - ASC_MEDIA_REMOVAL_PREVENTED); - break; - default: - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - } - break; - case GPCMD_MECHANISM_STATUS: - { - max_len = ube16_to_cpu(packet + 8); - cpu_to_ube16(buf, 0); - /* no current LBA */ - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = 1; - cpu_to_ube16(buf + 6, 0); - ide_atapi_cmd_reply(s, 8, max_len); - } - break; - case GPCMD_READ_TOC_PMA_ATIP: - { - int format, msf, start_track, len; - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - max_len = ube16_to_cpu(packet + 7); - format = packet[9] >> 6; - msf = (packet[1] >> 1) & 1; - start_track = packet[6]; - switch(format) { - case 0: - len = cdrom_read_toc(total_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - ide_atapi_cmd_reply(s, 12, max_len); - break; - case 2: - len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - default: - error_cmd: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - break; - case GPCMD_READ_CDVD_CAPACITY: - { - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, total_sectors - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); - } - break; - case GPCMD_READ_DVD_STRUCTURE: - { - int media = packet[1]; - int format = packet[7]; - int ret; - - max_len = ube16_to_cpu(packet + 8); - - if (format < 0xff) { - if (media_is_cd(s)) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INCOMPATIBLE_FORMAT); - break; - } else if (!media_present(s)) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - - memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? - IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); - - switch (format) { - case 0x00 ... 0x7f: - case 0xff: - if (media == 0) { - ret = ide_dvd_read_structure(s, format, packet, buf); - - if (ret < 0) - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); - else - ide_atapi_cmd_reply(s, ret, max_len); - - break; - } - /* TODO: BD support, fall through for now */ - - /* Generic disk structures */ - case 0x80: /* TODO: AACS volume identifier */ - case 0x81: /* TODO: AACS media serial number */ - case 0x82: /* TODO: AACS media identifier */ - case 0x83: /* TODO: AACS media key block */ - case 0x90: /* TODO: List of recognized format layers */ - case 0xc0: /* TODO: Write protection status */ - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - break; - case GPCMD_SET_SPEED: - ide_atapi_cmd_ok(s); - break; - case GPCMD_INQUIRY: - max_len = packet[4]; - buf[0] = 0x05; /* CD-ROM */ - buf[1] = 0x80; /* removable */ - buf[2] = 0x00; /* ISO */ - buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ - buf[4] = 31; /* additional length */ - buf[5] = 0; /* reserved */ - buf[6] = 0; /* reserved */ - buf[7] = 0; /* reserved */ - padstr8(buf + 8, 8, "QEMU"); - padstr8(buf + 16, 16, "QEMU DVD-ROM"); - padstr8(buf + 32, 4, s->version); - ide_atapi_cmd_reply(s, 36, max_len); - break; - case GPCMD_GET_CONFIGURATION: - { - uint32_t len; - uint8_t index = 0; - - /* only feature 0 is supported */ - if (packet[2] != 0 || packet[3] != 0) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - - /* XXX: could result in alignment problems in some architectures */ - max_len = ube16_to_cpu(packet + 7); - - /* - * XXX: avoid overflow for io_buffer if max_len is bigger than - * the size of that buffer (dimensioned to max number of - * sectors to transfer at once) - * - * Only a problem if the feature/profiles grow. - */ - if (max_len > 512) /* XXX: assume 1 sector */ - max_len = 512; - - memset(buf, 0, max_len); - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (media_is_dvd(s)) - cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); - else if (media_is_cd(s)) - cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); - - buf[10] = 0x02 | 0x01; /* persistent and current */ - len = 12; /* headers: 8 + 4 */ - len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); - len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); - cpu_to_ube32(buf, len - 4); /* data length */ - - ide_atapi_cmd_reply(s, len, max_len); - break; - } - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - handle_get_event_status_notification(s, buf, packet); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_ILLEGAL_OPCODE); - break; - } -} - static void ide_cfata_metadata_inquiry(IDEState *s) { uint16_t *p; diff --git a/hw/ide/internal.h b/hw/ide/internal.h index ba7e9a8ee2..aa198b6b12 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -9,6 +9,7 @@ #include <hw/ide.h> #include "block_int.h" #include "iorange.h" +#include "dma.h" /* debug IDE devices */ //#define DEBUG_IDE @@ -570,6 +571,15 @@ void ide_sector_write(IDEState *s); void ide_sector_read(IDEState *s); void ide_flush_cache(IDEState *s); +void ide_transfer_start(IDEState *s, uint8_t *buf, int size, + EndTransferFunc *end_transfer_func); +void ide_transfer_stop(IDEState *s); +void ide_set_inactive(IDEState *s); + +/* hw/ide/atapi.c */ +void ide_atapi_cmd(IDEState *s); +void ide_atapi_cmd_reply_end(IDEState *s); + /* hw/ide/qdev.c */ void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id); IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive); From a60cf7e7eba06bed118ae1b161f7e481ab72693c Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Mon, 18 Apr 2011 17:55:08 +0200 Subject: [PATCH 338/386] ide/atapi: Factor commands out In preparation for a table of function pointers, factor each command out from ide_atapi_cmd() into its own function. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 837 +++++++++++++++++++++++++++---------------------- 1 file changed, 459 insertions(+), 378 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 0edfd580f2..25b796e7e5 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -621,11 +621,453 @@ static void handle_get_event_status_notification(IDEState *s, ide_atapi_cmd_reply(s, used_len, max_len); } +static void cmd_request_sense(IDEState *s, uint8_t *buf) +{ + int max_len = buf[4]; + + memset(buf, 0, 18); + buf[0] = 0x70 | (1 << 7); + buf[2] = s->sense_key; + buf[7] = 10; + buf[12] = s->asc; + + if (s->sense_key == SENSE_UNIT_ATTENTION) { + s->sense_key = SENSE_NONE; + } + + ide_atapi_cmd_reply(s, 18, max_len); +} + +static void cmd_inquiry(IDEState *s, uint8_t *buf) +{ + int max_len = buf[4]; + + buf[0] = 0x05; /* CD-ROM */ + buf[1] = 0x80; /* removable */ + buf[2] = 0x00; /* ISO */ + buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ + buf[4] = 31; /* additional length */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* reserved */ + padstr8(buf + 8, 8, "QEMU"); + padstr8(buf + 16, 16, "QEMU DVD-ROM"); + padstr8(buf + 32, 4, s->version); + ide_atapi_cmd_reply(s, 36, max_len); +} + +static void cmd_get_configuration(IDEState *s, uint8_t *buf) +{ + uint32_t len; + uint8_t index = 0; + int max_len; + + /* only feature 0 is supported */ + if (buf[2] != 0 || buf[3] != 0) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + return; + } + + /* XXX: could result in alignment problems in some architectures */ + max_len = ube16_to_cpu(buf + 7); + + /* + * XXX: avoid overflow for io_buffer if max_len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (max_len > 512) { + /* XXX: assume 1 sector */ + max_len = 512; + } + + memset(buf, 0, max_len); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (media_is_dvd(s)) { + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); + } else if (media_is_cd(s)) { + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); + } + + buf[10] = 0x02 | 0x01; /* persistent and current */ + len = 12; /* headers: 8 + 4 */ + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); + cpu_to_ube32(buf, len - 4); /* data length */ + + ide_atapi_cmd_reply(s, len, max_len); +} + +static void cmd_mode_sense(IDEState *s, uint8_t *buf) +{ + int action, code; + int max_len; + + if (buf[0] == GPCMD_MODE_SENSE_10) { + max_len = ube16_to_cpu(buf + 7); + } else { + max_len = buf[4]; + } + + action = buf[2] >> 6; + code = buf[2] & 0x3f; + + switch(action) { + case 0: /* current values */ + switch(code) { + case GPMODE_R_W_ERROR_PAGE: /* error recovery */ + cpu_to_ube16(&buf[0], 16 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x01; + buf[9] = 0x06; + buf[10] = 0x00; + buf[11] = 0x05; + buf[12] = 0x00; + buf[13] = 0x00; + buf[14] = 0x00; + buf[15] = 0x00; + ide_atapi_cmd_reply(s, 16, max_len); + break; + case GPMODE_AUDIO_CTL_PAGE: + cpu_to_ube16(&buf[0], 24 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + /* Fill with CDROM audio volume */ + buf[17] = 0; + buf[19] = 0; + buf[21] = 0; + buf[23] = 0; + + ide_atapi_cmd_reply(s, 24, max_len); + break; + case GPMODE_CAPABILITIES_PAGE: + cpu_to_ube16(&buf[0], 28 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x2a; + buf[9] = 0x12; + buf[10] = 0x00; + buf[11] = 0x00; + + /* Claim PLAY_AUDIO capability (0x01) since some Linux + code checks for this to automount media. */ + buf[12] = 0x71; + buf[13] = 3 << 5; + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); + if (bdrv_is_locked(s->bs)) + buf[6] |= 1 << 1; + buf[15] = 0x00; + cpu_to_ube16(&buf[16], 706); + buf[18] = 0; + buf[19] = 2; + cpu_to_ube16(&buf[20], 512); + cpu_to_ube16(&buf[22], 706); + buf[24] = 0; + buf[25] = 0; + buf[26] = 0; + buf[27] = 0; + ide_atapi_cmd_reply(s, 28, max_len); + break; + default: + goto error_cmd; + } + break; + case 1: /* changeable values */ + goto error_cmd; + case 2: /* default values */ + goto error_cmd; + default: + case 3: /* saved values */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); + break; + } + return; + +error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); +} + +static void cmd_test_unit_ready(IDEState *s, uint8_t *buf) +{ + if (bdrv_is_inserted(s->bs)) { + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + } +} + +static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf) +{ + bdrv_set_locked(s->bs, buf[4] & 1); + ide_atapi_cmd_ok(s); +} + +static void cmd_read(IDEState *s, uint8_t* buf) +{ + int nb_sectors, lba; + + if (buf[0] == GPCMD_READ_10) { + nb_sectors = ube16_to_cpu(buf + 7); + } else { + nb_sectors = ube32_to_cpu(buf + 6); + } + + lba = ube32_to_cpu(buf + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + return; + } + + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); +} + +static void cmd_read_cd(IDEState *s, uint8_t* buf) +{ + int nb_sectors, lba, transfer_request; + + nb_sectors = (buf[6] << 16) | (buf[7] << 8) | buf[8]; + lba = ube32_to_cpu(buf + 2); + + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + return; + } + + transfer_request = buf[9]; + switch(transfer_request & 0xf8) { + case 0x00: + /* nothing */ + ide_atapi_cmd_ok(s); + break; + case 0x10: + /* normal read */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + break; + case 0xf8: + /* read all data */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2352); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } +} + +static void cmd_seek(IDEState *s, uint8_t* buf) +{ + unsigned int lba; + uint64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + return; + } + + lba = ube32_to_cpu(buf + 2); + if (lba >= total_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); + return; + } + + ide_atapi_cmd_ok(s); +} + +static void cmd_start_stop_unit(IDEState *s, uint8_t* buf) +{ + int start, eject, sense, err = 0; + start = buf[4] & 1; + eject = (buf[4] >> 1) & 1; + + if (eject) { + err = bdrv_eject(s->bs, !start); + } + + switch (err) { + case 0: + ide_atapi_cmd_ok(s); + break; + case -EBUSY: + sense = SENSE_NOT_READY; + if (bdrv_is_inserted(s->bs)) { + sense = SENSE_ILLEGAL_REQUEST; + } + ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); + break; + default: + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + break; + } +} + +static void cmd_mechanism_status(IDEState *s, uint8_t* buf) +{ + int max_len = ube16_to_cpu(buf + 8); + + cpu_to_ube16(buf, 0); + /* no current LBA */ + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; + cpu_to_ube16(buf + 6, 0); + ide_atapi_cmd_reply(s, 8, max_len); +} + +static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf) +{ + int format, msf, start_track, len; + uint64_t total_sectors; + int max_len; + + bdrv_get_geometry(s->bs, &total_sectors); + + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + return; + } + + max_len = ube16_to_cpu(buf + 7); + format = buf[9] >> 6; + msf = (buf[1] >> 1) & 1; + start_track = buf[6]; + + switch(format) { + case 0: + len = cdrom_read_toc(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + ide_atapi_cmd_reply(s, 12, max_len); + break; + case 2: + len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + default: + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + } +} + +static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf) +{ + uint64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + + total_sectors >>= 2; + if (total_sectors == 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + return; + } + + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, total_sectors - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); +} + +static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf) +{ + int max_len; + int media = buf[1]; + int format = buf[7]; + int ret; + + max_len = ube16_to_cpu(buf + 8); + + if (format < 0xff) { + if (media_is_cd(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INCOMPATIBLE_FORMAT); + return; + } else if (!media_present(s)) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + return; + } + } + + memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? + IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); + + switch (format) { + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = ide_dvd_read_structure(s, format, buf, buf); + + if (ret < 0) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); + } else { + ide_atapi_cmd_reply(s, ret, max_len); + } + + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } +} + +static void cmd_set_speed(IDEState *s, uint8_t* buf) +{ + ide_atapi_cmd_ok(s); +} + void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; uint8_t *buf; - int max_len; packet = s->io_buffer; buf = s->io_buffer; @@ -665,413 +1107,52 @@ void ide_atapi_cmd(IDEState *s) } switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: - if (bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } + cmd_test_unit_ready(s, buf); break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: - { - int action, code; - if (packet[0] == GPCMD_MODE_SENSE_10) - max_len = ube16_to_cpu(packet + 7); - else - max_len = packet[4]; - action = packet[2] >> 6; - code = packet[2] & 0x3f; - switch(action) { - case 0: /* current values */ - switch(code) { - case GPMODE_R_W_ERROR_PAGE: /* error recovery */ - cpu_to_ube16(&buf[0], 16 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x01; - buf[9] = 0x06; - buf[10] = 0x00; - buf[11] = 0x05; - buf[12] = 0x00; - buf[13] = 0x00; - buf[14] = 0x00; - buf[15] = 0x00; - ide_atapi_cmd_reply(s, 16, max_len); - break; - case GPMODE_AUDIO_CTL_PAGE: - cpu_to_ube16(&buf[0], 24 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - /* Fill with CDROM audio volume */ - buf[17] = 0; - buf[19] = 0; - buf[21] = 0; - buf[23] = 0; - - ide_atapi_cmd_reply(s, 24, max_len); - break; - case GPMODE_CAPABILITIES_PAGE: - cpu_to_ube16(&buf[0], 28 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x2a; - buf[9] = 0x12; - buf[10] = 0x00; - buf[11] = 0x00; - - /* Claim PLAY_AUDIO capability (0x01) since some Linux - code checks for this to automount media. */ - buf[12] = 0x71; - buf[13] = 3 << 5; - buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (bdrv_is_locked(s->bs)) - buf[6] |= 1 << 1; - buf[15] = 0x00; - cpu_to_ube16(&buf[16], 706); - buf[18] = 0; - buf[19] = 2; - cpu_to_ube16(&buf[20], 512); - cpu_to_ube16(&buf[22], 706); - buf[24] = 0; - buf[25] = 0; - buf[26] = 0; - buf[27] = 0; - ide_atapi_cmd_reply(s, 28, max_len); - break; - default: - goto error_cmd; - } - break; - case 1: /* changeable values */ - goto error_cmd; - case 2: /* default values */ - goto error_cmd; - default: - case 3: /* saved values */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_SAVING_PARAMETERS_NOT_SUPPORTED); - break; - } - } + cmd_mode_sense(s, buf); break; case GPCMD_REQUEST_SENSE: - max_len = packet[4]; - memset(buf, 0, 18); - buf[0] = 0x70 | (1 << 7); - buf[2] = s->sense_key; - buf[7] = 10; - buf[12] = s->asc; - if (s->sense_key == SENSE_UNIT_ATTENTION) - s->sense_key = SENSE_NONE; - ide_atapi_cmd_reply(s, 18, max_len); + cmd_request_sense(s, buf); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - bdrv_set_locked(s->bs, packet[4] & 1); - ide_atapi_cmd_ok(s); + cmd_prevent_allow_medium_removal(s, buf); break; case GPCMD_READ_10: case GPCMD_READ_12: - { - int nb_sectors, lba; - - if (packet[0] == GPCMD_READ_10) - nb_sectors = ube16_to_cpu(packet + 7); - else - nb_sectors = ube32_to_cpu(packet + 6); - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - } + cmd_read(s, buf); break; case GPCMD_READ_CD: - { - int nb_sectors, lba, transfer_request; - - nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - transfer_request = packet[9]; - switch(transfer_request & 0xf8) { - case 0x00: - /* nothing */ - ide_atapi_cmd_ok(s); - break; - case 0x10: - /* normal read */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - break; - case 0xf8: - /* read all data */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2352); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } + cmd_read_cd(s, buf); break; case GPCMD_SEEK: - { - unsigned int lba; - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - lba = ube32_to_cpu(packet + 2); - if (lba >= total_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_ok(s); - } + cmd_seek(s, buf); break; case GPCMD_START_STOP_UNIT: - { - int start, eject, sense, err = 0; - start = packet[4] & 1; - eject = (packet[4] >> 1) & 1; - - if (eject) { - err = bdrv_eject(s->bs, !start); - } - - switch (err) { - case 0: - ide_atapi_cmd_ok(s); - break; - case -EBUSY: - sense = SENSE_NOT_READY; - if (bdrv_is_inserted(s->bs)) { - sense = SENSE_ILLEGAL_REQUEST; - } - ide_atapi_cmd_error(s, sense, - ASC_MEDIA_REMOVAL_PREVENTED); - break; - default: - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - } + cmd_start_stop_unit(s, buf); break; case GPCMD_MECHANISM_STATUS: - { - max_len = ube16_to_cpu(packet + 8); - cpu_to_ube16(buf, 0); - /* no current LBA */ - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = 1; - cpu_to_ube16(buf + 6, 0); - ide_atapi_cmd_reply(s, 8, max_len); - } + cmd_mechanism_status(s, buf); break; case GPCMD_READ_TOC_PMA_ATIP: - { - int format, msf, start_track, len; - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - max_len = ube16_to_cpu(packet + 7); - format = packet[9] >> 6; - msf = (packet[1] >> 1) & 1; - start_track = packet[6]; - switch(format) { - case 0: - len = cdrom_read_toc(total_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - ide_atapi_cmd_reply(s, 12, max_len); - break; - case 2: - len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - default: - error_cmd: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } + cmd_read_toc_pma_atip(s, buf); break; case GPCMD_READ_CDVD_CAPACITY: - { - uint64_t total_sectors; - - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, total_sectors - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); - } + cmd_read_cdvd_capacity(s, buf); break; case GPCMD_READ_DVD_STRUCTURE: - { - int media = packet[1]; - int format = packet[7]; - int ret; - - max_len = ube16_to_cpu(packet + 8); - - if (format < 0xff) { - if (media_is_cd(s)) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INCOMPATIBLE_FORMAT); - break; - } else if (!media_present(s)) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - - memset(buf, 0, max_len > IDE_DMA_BUF_SECTORS * 512 + 4 ? - IDE_DMA_BUF_SECTORS * 512 + 4 : max_len); - - switch (format) { - case 0x00 ... 0x7f: - case 0xff: - if (media == 0) { - ret = ide_dvd_read_structure(s, format, packet, buf); - - if (ret < 0) - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret); - else - ide_atapi_cmd_reply(s, ret, max_len); - - break; - } - /* TODO: BD support, fall through for now */ - - /* Generic disk structures */ - case 0x80: /* TODO: AACS volume identifier */ - case 0x81: /* TODO: AACS media serial number */ - case 0x82: /* TODO: AACS media identifier */ - case 0x83: /* TODO: AACS media key block */ - case 0x90: /* TODO: List of recognized format layers */ - case 0xc0: /* TODO: Write protection status */ - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } + cmd_read_dvd_structure(s, buf); break; case GPCMD_SET_SPEED: - ide_atapi_cmd_ok(s); + cmd_set_speed(s, buf); break; case GPCMD_INQUIRY: - max_len = packet[4]; - buf[0] = 0x05; /* CD-ROM */ - buf[1] = 0x80; /* removable */ - buf[2] = 0x00; /* ISO */ - buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ - buf[4] = 31; /* additional length */ - buf[5] = 0; /* reserved */ - buf[6] = 0; /* reserved */ - buf[7] = 0; /* reserved */ - padstr8(buf + 8, 8, "QEMU"); - padstr8(buf + 16, 16, "QEMU DVD-ROM"); - padstr8(buf + 32, 4, s->version); - ide_atapi_cmd_reply(s, 36, max_len); + cmd_inquiry(s, buf); break; case GPCMD_GET_CONFIGURATION: - { - uint32_t len; - uint8_t index = 0; - - /* only feature 0 is supported */ - if (packet[2] != 0 || packet[3] != 0) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - - /* XXX: could result in alignment problems in some architectures */ - max_len = ube16_to_cpu(packet + 7); - - /* - * XXX: avoid overflow for io_buffer if max_len is bigger than - * the size of that buffer (dimensioned to max number of - * sectors to transfer at once) - * - * Only a problem if the feature/profiles grow. - */ - if (max_len > 512) /* XXX: assume 1 sector */ - max_len = 512; - - memset(buf, 0, max_len); - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (media_is_dvd(s)) - cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); - else if (media_is_cd(s)) - cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); - - buf[10] = 0x02 | 0x01; /* persistent and current */ - len = 12; /* headers: 8 + 4 */ - len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); - len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); - cpu_to_ube32(buf, len - 4); /* data length */ - - ide_atapi_cmd_reply(s, len, max_len); - break; - } + cmd_get_configuration(s, buf); + break; case GPCMD_GET_EVENT_STATUS_NOTIFICATION: handle_get_event_status_notification(s, buf, packet); break; From e1a064f982802ebb4a865482b7c0fe5e68d047f9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Mon, 18 Apr 2011 17:55:08 +0200 Subject: [PATCH 339/386] ide/atapi: Use table instead of switch for commands Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 115 +++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 25b796e7e5..277404b615 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -533,10 +533,11 @@ static unsigned int event_status_media(IDEState *s, return 8; /* We wrote to 4 extra bytes from the header */ } -static void handle_get_event_status_notification(IDEState *s, - uint8_t *buf, - const uint8_t *packet) +static void cmd_get_event_status_notification(IDEState *s, + uint8_t *buf) { + const uint8_t *packet = buf; + struct { uint8_t opcode; uint8_t polled; /* lsb bit is polled; others are reserved */ @@ -1064,6 +1065,38 @@ static void cmd_set_speed(IDEState *s, uint8_t* buf) ide_atapi_cmd_ok(s); } +enum { + /* + * Only commands flagged as ALLOW_UA are allowed to run under a + * unit attention condition. (See MMC-5, section 4.1.6.1) + */ + ALLOW_UA = 0x01, +}; + +static const struct { + void (*handler)(IDEState *s, uint8_t *buf); + int flags; +} atapi_cmd_table[0x100] = { + [ 0x00 ] = { cmd_test_unit_ready, 0 }, + [ 0x03 ] = { cmd_request_sense, ALLOW_UA }, + [ 0x12 ] = { cmd_inquiry, ALLOW_UA }, + [ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 }, + [ 0x1b ] = { cmd_start_stop_unit, 0 }, + [ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 }, + [ 0x25 ] = { cmd_read_cdvd_capacity, 0 }, + [ 0x28 ] = { cmd_read, /* (10) */ 0 }, + [ 0x2b ] = { cmd_seek, 0 }, + [ 0x43 ] = { cmd_read_toc_pma_atip, 0 }, + [ 0x46 ] = { cmd_get_configuration, ALLOW_UA }, + [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA }, + [ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 }, + [ 0xa8 ] = { cmd_read, /* (12) */ 0 }, + [ 0xad ] = { cmd_read_dvd_structure, 0 }, + [ 0xbb ] = { cmd_set_speed, 0 }, + [ 0xbd ] = { cmd_mechanism_status, 0 }, + [ 0xbe ] = { cmd_read_cd, 0 }, +}; + void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1082,21 +1115,17 @@ void ide_atapi_cmd(IDEState *s) } #endif /* - * If there's a UNIT_ATTENTION condition pending, only - * REQUEST_SENSE, INQUIRY, GET_CONFIGURATION and - * GET_EVENT_STATUS_NOTIFICATION commands are allowed to complete. - * MMC-5, section 4.1.6.1 lists only these commands being allowed - * to complete, with other commands getting a CHECK condition - * response unless a higher priority status, defined by the drive + * If there's a UNIT_ATTENTION condition pending, only command flagged with + * ALLOW_UA are allowed to complete. with other commands getting a CHECK + * condition response unless a higher priority status, defined by the drive * here, is pending. */ if (s->sense_key == SENSE_UNIT_ATTENTION && - s->io_buffer[0] != GPCMD_REQUEST_SENSE && - s->io_buffer[0] != GPCMD_INQUIRY && - s->io_buffer[0] != GPCMD_GET_EVENT_STATUS_NOTIFICATION) { + !(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA)) { ide_atapi_cmd_check_status(s); return; } + if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); @@ -1105,60 +1134,12 @@ void ide_atapi_cmd(IDEState *s) s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; return; } - switch(s->io_buffer[0]) { - case GPCMD_TEST_UNIT_READY: - cmd_test_unit_ready(s, buf); - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - cmd_mode_sense(s, buf); - break; - case GPCMD_REQUEST_SENSE: - cmd_request_sense(s, buf); - break; - case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - cmd_prevent_allow_medium_removal(s, buf); - break; - case GPCMD_READ_10: - case GPCMD_READ_12: - cmd_read(s, buf); - break; - case GPCMD_READ_CD: - cmd_read_cd(s, buf); - break; - case GPCMD_SEEK: - cmd_seek(s, buf); - break; - case GPCMD_START_STOP_UNIT: - cmd_start_stop_unit(s, buf); - break; - case GPCMD_MECHANISM_STATUS: - cmd_mechanism_status(s, buf); - break; - case GPCMD_READ_TOC_PMA_ATIP: - cmd_read_toc_pma_atip(s, buf); - break; - case GPCMD_READ_CDVD_CAPACITY: - cmd_read_cdvd_capacity(s, buf); - break; - case GPCMD_READ_DVD_STRUCTURE: - cmd_read_dvd_structure(s, buf); - break; - case GPCMD_SET_SPEED: - cmd_set_speed(s, buf); - break; - case GPCMD_INQUIRY: - cmd_inquiry(s, buf); - break; - case GPCMD_GET_CONFIGURATION: - cmd_get_configuration(s, buf); - break; - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - handle_get_event_status_notification(s, buf, packet); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_ILLEGAL_OPCODE); - break; + + /* Execute the command */ + if (atapi_cmd_table[s->io_buffer[0]].handler) { + atapi_cmd_table[s->io_buffer[0]].handler(s, buf); + return; } + + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE); } From e119bcaceb8dc17fe4874d6b0d2b62752639e488 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Tue, 19 Apr 2011 13:13:44 +0200 Subject: [PATCH 340/386] ide/atapi: Replace bdrv_get_geometry calls by s->nb_sectors The disk size can only change when the medium is changed, and the change callback takes care of updating s->nb_sectors in this case. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 277404b615..0452337175 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -416,10 +416,10 @@ static int ide_dvd_read_structure(IDEState *s, int format, if (layer != 0) return -ASC_INV_FIELD_IN_CMD_PACKET; - bdrv_get_geometry(s->bs, &total_sectors); - total_sectors >>= 2; - if (total_sectors == 0) + total_sectors = s->nb_sectors >> 2; + if (total_sectors == 0) { return -ASC_MEDIUM_NOT_PRESENT; + } buf[4] = 1; /* DVD-ROM, part version 1 */ buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ @@ -881,11 +881,8 @@ static void cmd_read_cd(IDEState *s, uint8_t* buf) static void cmd_seek(IDEState *s, uint8_t* buf) { unsigned int lba; - uint64_t total_sectors; + uint64_t total_sectors = s->nb_sectors >> 2; - bdrv_get_geometry(s->bs, &total_sectors); - - total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); return; @@ -944,12 +941,9 @@ static void cmd_mechanism_status(IDEState *s, uint8_t* buf) static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf) { int format, msf, start_track, len; - uint64_t total_sectors; + uint64_t total_sectors = s->nb_sectors >> 2; int max_len; - bdrv_get_geometry(s->bs, &total_sectors); - - total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); return; @@ -990,11 +984,8 @@ static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf) static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf) { - uint64_t total_sectors; + uint64_t total_sectors = s->nb_sectors >> 2; - bdrv_get_geometry(s->bs, &total_sectors); - - total_sectors >>= 2; if (total_sectors == 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); return; From 7a2c4b82340d621bff462672b29c88d2020d68c1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Tue, 19 Apr 2011 13:15:52 +0200 Subject: [PATCH 341/386] ide/atapi: Introduce CHECK_READY flag for commands Some commands are supposed to report a Not Ready Condition (i.e. they require a medium to be present in order to execute successfully). Instead of duplicating the check in each command implementation, let's add a flag and check it before calling the command. This patch only converts existing checks, it does not introduce new checks for any of the other commands that can/should report a Not Ready Condition. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 0452337175..690a0abdda 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -813,11 +813,9 @@ error_cmd: static void cmd_test_unit_ready(IDEState *s, uint8_t *buf) { - if (bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - } + /* Not Ready Conditions are already handled in ide_atapi_cmd(), so if we + * come here, we know that it's ready. */ + ide_atapi_cmd_ok(s); } static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf) @@ -883,11 +881,6 @@ static void cmd_seek(IDEState *s, uint8_t* buf) unsigned int lba; uint64_t total_sectors = s->nb_sectors >> 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - return; - } - lba = ube32_to_cpu(buf + 2); if (lba >= total_sectors) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); @@ -941,13 +934,8 @@ static void cmd_mechanism_status(IDEState *s, uint8_t* buf) static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf) { int format, msf, start_track, len; - uint64_t total_sectors = s->nb_sectors >> 2; int max_len; - - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - return; - } + uint64_t total_sectors = s->nb_sectors >> 2; max_len = ube16_to_cpu(buf + 7); format = buf[9] >> 6; @@ -986,11 +974,6 @@ static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf) { uint64_t total_sectors = s->nb_sectors >> 2; - if (total_sectors == 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - return; - } - /* NOTE: it is really the number of sectors minus 1 */ cpu_to_ube32(buf, total_sectors - 1); cpu_to_ube32(buf + 4, 2048); @@ -1062,22 +1045,29 @@ enum { * unit attention condition. (See MMC-5, section 4.1.6.1) */ ALLOW_UA = 0x01, + + /* + * Commands flagged with CHECK_READY can only execute if a medium is present. + * Otherwise they report the Not Ready Condition. (See MMC-5, section + * 4.1.8) + */ + CHECK_READY = 0x02, }; static const struct { void (*handler)(IDEState *s, uint8_t *buf); int flags; } atapi_cmd_table[0x100] = { - [ 0x00 ] = { cmd_test_unit_ready, 0 }, + [ 0x00 ] = { cmd_test_unit_ready, CHECK_READY }, [ 0x03 ] = { cmd_request_sense, ALLOW_UA }, [ 0x12 ] = { cmd_inquiry, ALLOW_UA }, [ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 }, [ 0x1b ] = { cmd_start_stop_unit, 0 }, [ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 }, - [ 0x25 ] = { cmd_read_cdvd_capacity, 0 }, + [ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY }, [ 0x28 ] = { cmd_read, /* (10) */ 0 }, - [ 0x2b ] = { cmd_seek, 0 }, - [ 0x43 ] = { cmd_read_toc_pma_atip, 0 }, + [ 0x2b ] = { cmd_seek, CHECK_READY }, + [ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY }, [ 0x46 ] = { cmd_get_configuration, ALLOW_UA }, [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA }, [ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 }, @@ -1126,6 +1116,14 @@ void ide_atapi_cmd(IDEState *s) return; } + /* Report a Not Ready condition if appropriate for the command */ + if ((atapi_cmd_table[s->io_buffer[0]].flags & CHECK_READY) && + (!media_present(s) || !bdrv_is_inserted(s->bs))) + { + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + return; + } + /* Execute the command */ if (atapi_cmd_table[s->io_buffer[0]].handler) { atapi_cmd_table[s->io_buffer[0]].handler(s, buf); From 19dfc44a94f759848a0f7de7378b2f8b9af6b5d0 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Sun, 24 Apr 2011 18:38:58 +0100 Subject: [PATCH 342/386] qed: Fix consistency check on 32-bit hosts The qed_bytes_to_clusters() function is normally used with size_t lengths. Consistency check used it with file size length and therefore failed on 32-bit hosts when the image file is 4 GB or more. Make qed_bytes_to_clusters() explicitly 64-bit and update consistency check to keep 64-bit cluster counts. Reported-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/qed-check.c | 4 ++-- block/qed.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/block/qed-check.c b/block/qed-check.c index ea4ebc8e20..22cd07fa1f 100644 --- a/block/qed-check.c +++ b/block/qed-check.c @@ -18,7 +18,7 @@ typedef struct { BdrvCheckResult *result; bool fix; /* whether to fix invalid offsets */ - size_t nclusters; + uint64_t nclusters; uint32_t *used_clusters; /* referenced cluster bitmap */ QEDRequest request; @@ -177,7 +177,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table) static void qed_check_for_leaks(QEDCheck *check) { BDRVQEDState *s = check->s; - size_t i; + uint64_t i; for (i = s->header.header_size; i < check->nclusters; i++) { if (!qed_test_bit(check->used_clusters, i)) { diff --git a/block/qed.h b/block/qed.h index 3e1ab84781..1d1421fee1 100644 --- a/block/qed.h +++ b/block/qed.h @@ -252,7 +252,7 @@ static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset) return offset & (s->header.cluster_size - 1); } -static inline unsigned int qed_bytes_to_clusters(BDRVQEDState *s, size_t bytes) +static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes) { return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) / (s->header.cluster_size - 1); From a55c73ba3fb3f5700788933c519c193c5e85c878 Mon Sep 17 00:00:00 2001 From: Jes Sorensen <Jes.Sorensen@redhat.com> Date: Wed, 27 Apr 2011 14:31:50 +0200 Subject: [PATCH 343/386] Add dd-style SIGUSR1 progress reporting This introduces support for dd-style progress reporting on POSIX systems, if the user hasn't specified -p to report progress. If sent a SIGUSR1, qemu-img will report current progress for commands that support progress reporting. Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-progress.c | 53 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/qemu-progress.c b/qemu-progress.c index 656e065b1d..b4b751c9ec 100644 --- a/qemu-progress.c +++ b/qemu-progress.c @@ -26,12 +26,15 @@ #include "osdep.h" #include "sysemu.h" #include <stdio.h> +#include <signal.h> struct progress_state { int enabled; float current; float last_print; float min_skip; + void (*print)(void); + void (*end)(void); }; static struct progress_state state; @@ -51,20 +54,60 @@ static void progress_simple_print(void) static void progress_simple_end(void) { - if (state.enabled) { - printf("\n"); - } + printf("\n"); +} + +static void progress_simple_init(void) +{ + state.print = progress_simple_print; + state.end = progress_simple_end; +} + +#ifdef CONFIG_POSIX +static void sigusr_print(int signal) +{ + printf(" (%3.2f/100%%)\n", state.current); +} +#endif + +static void progress_dummy_print(void) +{ +} + +static void progress_dummy_end(void) +{ +} + +static void progress_dummy_init(void) +{ +#ifdef CONFIG_POSIX + struct sigaction action; + + memset(&action, 0, sizeof(action)); + sigfillset(&action.sa_mask); + action.sa_handler = sigusr_print; + action.sa_flags = 0; + sigaction(SIGUSR1, &action, NULL); +#endif + + state.print = progress_dummy_print; + state.end = progress_dummy_end; } void qemu_progress_init(int enabled, float min_skip) { state.enabled = enabled; state.min_skip = min_skip; + if (enabled) { + progress_simple_init(); + } else { + progress_dummy_init(); + } } void qemu_progress_end(void) { - progress_simple_end(); + state.end(); } void qemu_progress_print(float percent, int max) @@ -84,6 +127,6 @@ void qemu_progress_print(float percent, int max) if (current > (state.last_print + state.min_skip) || (current == 100) || (current == 0)) { state.last_print = state.current; - progress_simple_print(); + state.print(); } } From df6e008a8814af9db872f1319b58784d87987c93 Mon Sep 17 00:00:00 2001 From: Jes Sorensen <Jes.Sorensen@redhat.com> Date: Wed, 27 Apr 2011 14:31:51 +0200 Subject: [PATCH 344/386] Remove obsolete 'enabled' variable from progress state Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-progress.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/qemu-progress.c b/qemu-progress.c index b4b751c9ec..e1feb89614 100644 --- a/qemu-progress.c +++ b/qemu-progress.c @@ -29,7 +29,6 @@ #include <signal.h> struct progress_state { - int enabled; float current; float last_print; float min_skip; @@ -46,10 +45,8 @@ static struct progress_state state; */ static void progress_simple_print(void) { - if (state.enabled) { - printf(" (%3.2f/100%%)\r", state.current); - fflush(stdout); - } + printf(" (%3.2f/100%%)\r", state.current); + fflush(stdout); } static void progress_simple_end(void) @@ -96,7 +93,6 @@ static void progress_dummy_init(void) void qemu_progress_init(int enabled, float min_skip) { - state.enabled = enabled; state.min_skip = min_skip; if (enabled) { progress_simple_init(); From c6a0487b1fc29bc6047da0e484f79d4d627f9018 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Tue, 26 Apr 2011 10:17:48 +0200 Subject: [PATCH 345/386] rtl8139: Fix compilation for w32/w64 Compilation for Windows needs a different declaration for the printf format attribute, so use the macro which was defined for this purpose. Cc: Benjamin Poirier <benjamin.poirier@gmail.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/rtl8139.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index cbf667a301..515652f270 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -88,8 +88,7 @@ # define DPRINTF(fmt, ...) \ do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0) #else -static inline __attribute__ ((format (printf, 1, 2))) - int DPRINTF(const char *fmt, ...) +static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...) { return 0; } From 70afb8ff90e9d922ed729e6dbabaff6d67c461aa Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Sun, 3 Apr 2011 18:22:45 +0200 Subject: [PATCH 346/386] darwin-user: Remove unneeded null pointer check cppcheck reports this error: commpage.c:223: error: Possible null pointer dereference: value - otherwise it is redundant to check if value is null at line 214 The null pointer check in line 214 is indeed not needed. If value were null, the code would crash in line 223. See do_compare_and_swap64 were for a reference. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- darwin-user/commpage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c index f6aa71e058..cc29bddd95 100644 --- a/darwin-user/commpage.c +++ b/darwin-user/commpage.c @@ -211,7 +211,7 @@ void do_compare_and_swap32(void *cpu_env, int num) 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)) + if(old == tswap32(*value)) { uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX]; *value = tswap32(new); From 661bfc80e876d32da8befe53ba0234d87fc0bcc2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@web.de> Date: Sun, 10 Apr 2011 12:53:39 +0200 Subject: [PATCH 347/386] pflash: Restore & fix lazy ROMD switching Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences. Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/pflash_cfi02.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 370c5eef7b..14bbc34e16 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -50,6 +50,8 @@ do { \ #define DPRINTF(fmt, ...) do { } while (0) #endif +#define PFLASH_LAZY_ROMD_THRESHOLD 42 + struct pflash_t { BlockDriverState *bs; target_phys_addr_t base; @@ -70,6 +72,7 @@ struct pflash_t { ram_addr_t off; int fl_mem; int rom_mode; + int read_counter; /* used for lazy switch-back to rom mode */ void *storage; }; @@ -112,10 +115,10 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset); ret = -1; - if (!pfl->rom_mode) { - /* Lazy reset of to ROMD mode */ - if (pfl->wcycle == 0) - pflash_register_memory(pfl, 1); + /* Lazy reset to ROMD mode after a certain amount of read accesses */ + if (!pfl->rom_mode && pfl->wcycle == 0 && + ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) { + pflash_register_memory(pfl, 1); } offset &= pfl->chip_len - 1; boff = offset & 0xFF; @@ -254,6 +257,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, /* Set the device in I/O access mode if required */ if (pfl->rom_mode) pflash_register_memory(pfl, 0); + pfl->read_counter = 0; /* We're in read mode */ check_unlock0: if (boff == 0x55 && cmd == 0x98) { From 353ac78d495ef976242abd868f68d78420861c2c Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Date: Fri, 28 Jan 2011 18:09:08 +0530 Subject: [PATCH 348/386] virtio-9p: move 9p files around Now that we start adding more files related to 9pfs it make sense to move them to a separate directory Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- Makefile.objs | 10 +++++++--- Makefile.target | 6 ++++-- configure | 2 ++ {hw => fsdev}/file-op-9p.h | 0 fsdev/qemu-fsdev.h | 2 +- hw/{ => 9pfs}/virtio-9p-debug.c | 0 hw/{ => 9pfs}/virtio-9p-debug.h | 0 hw/{ => 9pfs}/virtio-9p-local.c | 0 hw/{ => 9pfs}/virtio-9p-posix-acl.c | 2 +- hw/{ => 9pfs}/virtio-9p-xattr-user.c | 2 +- hw/{ => 9pfs}/virtio-9p-xattr.c | 2 +- hw/{ => 9pfs}/virtio-9p-xattr.h | 0 hw/{ => 9pfs}/virtio-9p.c | 0 hw/{ => 9pfs}/virtio-9p.h | 2 +- 14 files changed, 18 insertions(+), 10 deletions(-) rename {hw => fsdev}/file-op-9p.h (100%) rename hw/{ => 9pfs}/virtio-9p-debug.c (100%) rename hw/{ => 9pfs}/virtio-9p-debug.h (100%) rename hw/{ => 9pfs}/virtio-9p-local.c (100%) rename hw/{ => 9pfs}/virtio-9p-posix-acl.c (99%) rename hw/{ => 9pfs}/virtio-9p-xattr-user.c (98%) rename hw/{ => 9pfs}/virtio-9p-xattr.c (99%) rename hw/{ => 9pfs}/virtio-9p-xattr.h (100%) rename hw/{ => 9pfs}/virtio-9p.c (100%) rename hw/{ => 9pfs}/virtio-9p.h (99%) diff --git a/Makefile.objs b/Makefile.objs index 1b446958c5..0cbff4d293 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -285,9 +285,13 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) -hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o -hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o -hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o +9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p-debug.o +9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o +9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o + +hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y)) +$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/ + ###################################################################### # libdis diff --git a/Makefile.target b/Makefile.target index 0e0ef36b97..2501c63bb2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -194,7 +194,7 @@ obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o obj-y += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o -obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o +obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o obj-y += rwhandler.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o @@ -401,9 +401,11 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx qmp-commands.h: $(SRC_PATH)/qmp-commands.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") +9pfs/virtio-9p.o: CFLAGS += -I$(SRC_PATH)/hw/ + clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o - rm -f *.d */*.d tcg/*.o ide/*.o + rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c ifdef CONFIG_SYSTEMTAP_TRACE rm -f *.stp diff --git a/configure b/configure index 35f7e8b7b2..6f75e2eb9f 100755 --- a/configure +++ b/configure @@ -3062,6 +3062,7 @@ mkdir -p $target_dir mkdir -p $target_dir/fpu mkdir -p $target_dir/tcg mkdir -p $target_dir/ide +mkdir -p $target_dir/9pfs if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then mkdir -p $target_dir/nwfpe fi @@ -3488,6 +3489,7 @@ for hwlib in 32 64; do mkdir -p $d mkdir -p $d/ide symlink $source_path/Makefile.hw $d/Makefile + mkdir -p $d/9pfs echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak done diff --git a/hw/file-op-9p.h b/fsdev/file-op-9p.h similarity index 100% rename from hw/file-op-9p.h rename to fsdev/file-op-9p.h diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h index a704043beb..f9f08d3e1b 100644 --- a/fsdev/qemu-fsdev.h +++ b/fsdev/qemu-fsdev.h @@ -13,7 +13,7 @@ #ifndef QEMU_FSDEV_H #define QEMU_FSDEV_H #include "qemu-option.h" -#include "hw/file-op-9p.h" +#include "file-op-9p.h" /* diff --git a/hw/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c similarity index 100% rename from hw/virtio-9p-debug.c rename to hw/9pfs/virtio-9p-debug.c diff --git a/hw/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h similarity index 100% rename from hw/virtio-9p-debug.h rename to hw/9pfs/virtio-9p-debug.h diff --git a/hw/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c similarity index 100% rename from hw/virtio-9p-local.c rename to hw/9pfs/virtio-9p-local.c diff --git a/hw/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c similarity index 99% rename from hw/virtio-9p-posix-acl.c rename to hw/9pfs/virtio-9p-posix-acl.c index 3978d0cf71..e4e0777107 100644 --- a/hw/virtio-9p-posix-acl.c +++ b/hw/9pfs/virtio-9p-posix-acl.c @@ -15,7 +15,7 @@ #include <attr/xattr.h> #include "virtio.h" #include "virtio-9p.h" -#include "file-op-9p.h" +#include "fsdev/file-op-9p.h" #include "virtio-9p-xattr.h" #define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access" diff --git a/hw/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c similarity index 98% rename from hw/virtio-9p-xattr-user.c rename to hw/9pfs/virtio-9p-xattr-user.c index faa02a1911..bba13ce643 100644 --- a/hw/virtio-9p-xattr-user.c +++ b/hw/9pfs/virtio-9p-xattr-user.c @@ -14,7 +14,7 @@ #include <sys/types.h> #include "virtio.h" #include "virtio-9p.h" -#include "file-op-9p.h" +#include "fsdev/file-op-9p.h" #include "virtio-9p-xattr.h" diff --git a/hw/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c similarity index 99% rename from hw/virtio-9p-xattr.c rename to hw/9pfs/virtio-9p-xattr.c index 1aab081de2..03c3d3f6bb 100644 --- a/hw/virtio-9p-xattr.c +++ b/hw/9pfs/virtio-9p-xattr.c @@ -13,7 +13,7 @@ #include "virtio.h" #include "virtio-9p.h" -#include "file-op-9p.h" +#include "fsdev/file-op-9p.h" #include "virtio-9p-xattr.h" diff --git a/hw/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h similarity index 100% rename from hw/virtio-9p-xattr.h rename to hw/9pfs/virtio-9p-xattr.h diff --git a/hw/virtio-9p.c b/hw/9pfs/virtio-9p.c similarity index 100% rename from hw/virtio-9p.c rename to hw/9pfs/virtio-9p.c diff --git a/hw/virtio-9p.h b/hw/9pfs/virtio-9p.h similarity index 99% rename from hw/virtio-9p.h rename to hw/9pfs/virtio-9p.h index 2ae4ce7189..95e4977363 100644 --- a/hw/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -6,7 +6,7 @@ #include <sys/time.h> #include <utime.h> -#include "file-op-9p.h" +#include "fsdev/file-op-9p.h" /* The feature bitmap for virtio 9P */ /* The mount point is specified in a config variable */ From 39792515185350a21ec84b9eb65aafd0bb65525c Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Date: Wed, 27 Apr 2011 12:25:46 +0530 Subject: [PATCH 349/386] virtio-9p: Print the pdu details on return Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 7e29535672..18968c25c3 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -596,7 +596,10 @@ static V9fsPDU *alloc_pdu(V9fsState *s) static void free_pdu(V9fsState *s, V9fsPDU *pdu) { if (pdu) { - QLIST_INSERT_HEAD(&s->free_list, pdu, next); + if (debug_9p_pdu) { + pprint_pdu(pdu); + } + QLIST_INSERT_HEAD(&s->free_list, pdu, next); } } From a09947617cc3d0035f485d9804cd26c5a895b683 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> Date: Wed, 27 Apr 2011 12:26:43 +0530 Subject: [PATCH 350/386] virtio-9p: removexattr on default acl should return 0 If we don't have default acl, removexattr on default acl should return 0 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p-posix-acl.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c index e4e0777107..575abe86b0 100644 --- a/hw/9pfs/virtio-9p-posix-acl.c +++ b/hw/9pfs/virtio-9p-posix-acl.c @@ -60,7 +60,7 @@ static int mp_pacl_removexattr(FsContext *ctx, ret = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS); if (ret == -1 && errno == ENODATA) { /* - * We don't get ENODATA error when trying to remote a + * We don't get ENODATA error when trying to remove a * posix acl that is not present. So don't throw the error * even in case of mapped security model */ @@ -103,7 +103,18 @@ static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name, static int mp_dacl_removexattr(FsContext *ctx, const char *path, const char *name) { - return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT); + int ret; + ret = lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT); + if (ret == -1 && errno == ENODATA) { + /* + * We don't get ENODATA error when trying to remove a + * posix acl that is not present. So don't throw the error + * even in case of mapped security model + */ + errno = 0; + ret = 0; + } + return ret; } From 1d810aeb4eda548e8a875db9e364732b8765d894 Mon Sep 17 00:00:00 2001 From: "M. Mohan Kumar" <mohan@in.ibm.com> Date: Tue, 1 Feb 2011 14:21:41 +0530 Subject: [PATCH 351/386] virtio-9p: Bugfix to send correct iounit LCREATE function packs address of iounit in the pdu, fix that to send actual iounit itself. Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com> Acked-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 18968c25c3..ca394570ca 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -1771,7 +1771,7 @@ static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err) v9fs_string_copy(&vs->fidp->path, &vs->fullname); stat_to_qid(&vs->stbuf, &vs->qid); vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, - &vs->iounit); + vs->iounit); err = vs->offset; } else { vs->fidp->fid_type = P9_FID_NONE; From f35bde2f8fb55541d4d7ddca50d64ce5a6ef384c Mon Sep 17 00:00:00 2001 From: Harsh Prateek Bora <harsh@linux.vnet.ibm.com> Date: Wed, 2 Feb 2011 10:20:33 +0530 Subject: [PATCH 352/386] hw/virtio-9p-local.c: Remove unnecessary null char in symlink file This patch removes the addition of null char in symlink file which is being appended to file in case of mapped security model. Without this patch, the extra null char causes LTP testcase lstat03 to fail and hence this fix is required. Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p-local.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index a8e7525bf6..0a015de9a5 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -370,7 +370,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, return fd; } /* Write the oldpath (target) to the file. */ - oldpath_size = strlen(oldpath) + 1; + oldpath_size = strlen(oldpath); do { write_size = write(fd, (void *)oldpath, oldpath_size); } while (write_size == -1 && errno == EINTR); From 4f8dee2dec9c6d590c8a7844b2824935542ca122 Mon Sep 17 00:00:00 2001 From: Harsh Prateek Bora <harsh@linux.vnet.ibm.com> Date: Thu, 14 Apr 2011 14:54:40 +0530 Subject: [PATCH 353/386] v9fs_walk: As per 9p2000 RFC, MAXWELEM >= nwnames >= 0. The nwnames field in TWALK message is assumed to be >=0 and <= MAXWELEM which is defined as macro P9_MAXWELEM (16) in virtio-9p.h as per 9p2000 RFC. Appropriate changes are required in V9fsWalkState and v9fs_walk. Signed-off-by: Harsh Prateek Bora <harsh@linux.vnet.ibm.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p.c | 7 +++++-- hw/9pfs/virtio-9p.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index ca394570ca..b5fc52b3eb 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -1482,7 +1482,7 @@ static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err) { complete_pdu(s, vs->pdu, err); - if (vs->nwnames) { + if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) { for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) { v9fs_string_free(&vs->wnames[vs->name_idx]); } @@ -1578,7 +1578,7 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu) vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid, &newfid, &vs->nwnames); - if (vs->nwnames) { + if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) { vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames); vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames); @@ -1587,6 +1587,9 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu) vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s", &vs->wnames[i]); } + } else if (vs->nwnames > P9_MAXWELEM) { + err = -EINVAL; + goto out; } vs->fidp = lookup_fid(s, fid); diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 95e4977363..622928fce5 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -282,7 +282,7 @@ typedef struct V9fsStatStateDotl { typedef struct V9fsWalkState { V9fsPDU *pdu; size_t offset; - int16_t nwnames; + uint16_t nwnames; int name_idx; V9fsQID *qids; V9fsFidState *fidp; From e14ea479b37d6c6665fae55ea0eb713c4b2d3376 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Date: Wed, 16 Mar 2011 08:31:43 +0000 Subject: [PATCH 354/386] vl.c: Replace -virtfs string manipulation with QemuOpts The -virtfs option creates an fsdev representing the pass-through file system and a guest-visible virtio-9p-pci device that can access this file system. This patch replaces the string manipulation used to build and reparse option lists with direct QemuOpts calls. Removing the string manipulation code makes it easier to maintain and less error prone. An error message is also updated to use "mount_tag" instead of "mnt_tag". Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com> --- vl.c | 54 ++++++++++++++++++------------------------------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/vl.c b/vl.c index b46ee663bf..6b9a2f61e3 100644 --- a/vl.c +++ b/vl.c @@ -2447,9 +2447,8 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_virtfs: { - char *arg_fsdev = NULL; - char *arg_9p = NULL; - int len = 0; + QemuOpts *fsdev; + QemuOpts *device; olist = qemu_find_opts("virtfs"); if (!olist) { @@ -2468,45 +2467,28 @@ int main(int argc, char **argv, char **envp) qemu_opt_get(opts, "security_model") == NULL) { fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/," "security_model=[mapped|passthrough|none]," - "mnt_tag=tag.\n"); + "mount_tag=tag.\n"); exit(1); } - len = strlen(",id=,path=,security_model="); - len += strlen(qemu_opt_get(opts, "fstype")); - len += strlen(qemu_opt_get(opts, "mount_tag")); - len += strlen(qemu_opt_get(opts, "path")); - len += strlen(qemu_opt_get(opts, "security_model")); - arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev)); - - snprintf(arg_fsdev, (len + 1) * sizeof(*arg_fsdev), - "%s,id=%s,path=%s,security_model=%s", - qemu_opt_get(opts, "fstype"), - qemu_opt_get(opts, "mount_tag"), - qemu_opt_get(opts, "path"), - qemu_opt_get(opts, "security_model")); - - len = strlen("virtio-9p,fsdev=,mount_tag="); - len += 2*strlen(qemu_opt_get(opts, "mount_tag")); - arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p)); - - snprintf(arg_9p, (len + 1) * sizeof(*arg_9p), - "virtio-9p,fsdev=%s,mount_tag=%s", - qemu_opt_get(opts, "mount_tag"), - qemu_opt_get(opts, "mount_tag")); - - if (!qemu_opts_parse(qemu_find_opts("fsdev"), arg_fsdev, 1)) { - fprintf(stderr, "parse error [fsdev]: %s\n", optarg); + fsdev = qemu_opts_create(qemu_find_opts("fsdev"), + qemu_opt_get(opts, "mount_tag"), 1); + if (!fsdev) { + fprintf(stderr, "duplicate fsdev id: %s\n", + qemu_opt_get(opts, "mount_tag")); exit(1); } + qemu_opt_set(fsdev, "fstype", qemu_opt_get(opts, "fstype")); + qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path")); + qemu_opt_set(fsdev, "security_model", + qemu_opt_get(opts, "security_model")); - if (!qemu_opts_parse(qemu_find_opts("device"), arg_9p, 1)) { - fprintf(stderr, "parse error [device]: %s\n", optarg); - exit(1); - } - - qemu_free(arg_fsdev); - qemu_free(arg_9p); + device = qemu_opts_create(qemu_find_opts("device"), NULL, 0); + qemu_opt_set(device, "driver", "virtio-9p-pci"); + qemu_opt_set(device, "fsdev", + qemu_opt_get(opts, "mount_tag")); + qemu_opt_set(device, "mount_tag", + qemu_opt_get(opts, "mount_tag")); break; } case QEMU_OPTION_serial: From 47f7be394aa7baf7855fe78f56b8ba4c69bf75d9 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@web.de> Date: Sat, 9 Apr 2011 13:18:59 +0200 Subject: [PATCH 355/386] ioapic: Do not set irr for masked edge IRQs So far we set IRR for edge IRQs even if the pin is masked. If the guest later on unmasks and switches the pin to level-triggered mode, irr will remain set, causing an IRQ storm. The point is that setting IRR is not correct in this case according to the spec, and avoiding this resolves the issue. Reported-and-tested-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- hw/ioapic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/ioapic.c b/hw/ioapic.c index 569327d1e9..6c26e820e0 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -160,8 +160,9 @@ static void ioapic_set_irq(void *opaque, int vector, int level) s->irr &= ~mask; } } else { - /* edge triggered */ - if (level) { + /* According to the 82093AA manual, we must ignore edge requests + * if the input pin is masked. */ + if (level && !(entry & IOAPIC_LVT_MASKED)) { s->irr |= mask; ioapic_service(s); } From 5856d44eb592e05bb266fb2c7db42926faa22144 Mon Sep 17 00:00:00 2001 From: YuYeon Oh <yuyeon.oh@samsung.com> Date: Mon, 25 Apr 2011 01:23:58 +0000 Subject: [PATCH 356/386] target-arm: fix LDMIA bug on page boundary target-arm: fix LDMIA bug on page boundary When consecutive memory locations are on page boundary, a base register may be loaded before page fault occurs. After page fault handling, it losts the memory location information. To solve this problem, loading a base register has to put back. Signed-off-by: Yuyeon Oh <yuyeon.oh@samsung.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 8b309d48b8..d8da514599 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8016,7 +8016,8 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } } } else { - int i; + int i, loaded_base = 0; + TCGv loaded_var; /* Load/store multiple. */ addr = load_reg(s, rn); offset = 0; @@ -8028,6 +8029,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) tcg_gen_addi_i32(addr, addr, -offset); } + TCGV_UNUSED(loaded_var); for (i = 0; i < 16; i++) { if ((insn & (1 << i)) == 0) continue; @@ -8036,6 +8038,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) tmp = gen_ld32(addr, IS_USER(s)); if (i == 15) { gen_bx(s, tmp); + } else if (i == rn) { + loaded_var = tmp; + loaded_base = 1; } else { store_reg(s, i, tmp); } @@ -8046,6 +8051,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } tcg_gen_addi_i32(addr, addr, 4); } + if (loaded_base) { + store_reg(s, rn, loaded_var); + } if (insn & (1 << 21)) { /* Base register writeback. */ if (insn & (1 << 24)) { From a7d3970d0635ebce1412736e7aaf11d387919dc8 Mon Sep 17 00:00:00 2001 From: Peter Maydell <peter.maydell@linaro.org> Date: Tue, 26 Apr 2011 18:17:20 +0100 Subject: [PATCH 357/386] target-arm: Don't update base register on abort in Thumb T1 LDM Make sure the base register isn't updated if it is in the load list for a Thumb LDM (T1 encoding) which aborts partway through the load. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-arm/translate.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index d8da514599..a1af436e34 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9454,7 +9454,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) break; case 12: + { /* load/store multiple */ + TCGv loaded_var; + TCGV_UNUSED(loaded_var); rn = (insn >> 8) & 0x7; addr = load_reg(s, rn); for (i = 0; i < 8; i++) { @@ -9462,7 +9465,11 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) if (insn & (1 << 11)) { /* load */ tmp = gen_ld32(addr, IS_USER(s)); - store_reg(s, i, tmp); + if (i == rn) { + loaded_var = tmp; + } else { + store_reg(s, i, tmp); + } } else { /* store */ tmp = load_reg(s, i); @@ -9472,14 +9479,18 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) tcg_gen_addi_i32(addr, addr, 4); } } - /* Base register writeback. */ if ((insn & (1 << rn)) == 0) { + /* base reg not in list: base register writeback */ store_reg(s, rn, addr); } else { + /* base reg in list: if load, complete it now */ + if (insn & (1 << 11)) { + store_reg(s, rn, loaded_var); + } tcg_temp_free_i32(addr); } break; - + } case 13: /* conditional branch or swi */ cond = (insn >> 8) & 0xf; From 7c32c4feebd962960fb160291a426b983e0ae668 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 24 Mar 2011 11:12:02 +0100 Subject: [PATCH 358/386] chardev: Allow frontends to notify backends of guest open / close Some frontends know when the guest has opened the "channel" and is actively listening to it, for example virtio-serial. This patch adds 2 new qemu-chardev functions which can be used by frontends to signal guest open / close, and allows interested backends to listen to this. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Alon Levy <alevy@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- qemu-char.c | 17 +++++++++++++++++ qemu-char.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 03858d4ef7..710d98ffc4 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -480,6 +480,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; + /* Frontend guest-open / -close notification is not support with muxes */ + chr->chr_guest_open = NULL; + chr->chr_guest_close = NULL; /* Muxes are always open on creation */ qemu_chr_generic_open(chr); @@ -2579,6 +2582,20 @@ void qemu_chr_set_echo(struct CharDriverState *chr, bool echo) } } +void qemu_chr_guest_open(struct CharDriverState *chr) +{ + if (chr->chr_guest_open) { + chr->chr_guest_open(chr); + } +} + +void qemu_chr_guest_close(struct CharDriverState *chr) +{ + if (chr->chr_guest_close) { + chr->chr_guest_close(chr); + } +} + void qemu_chr_close(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); diff --git a/qemu-char.h b/qemu-char.h index fb96eef3de..2f8512e528 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -65,6 +65,8 @@ struct CharDriverState { void (*chr_close)(struct CharDriverState *chr); void (*chr_accept_input)(struct CharDriverState *chr); void (*chr_set_echo)(struct CharDriverState *chr, bool echo); + void (*chr_guest_open)(struct CharDriverState *chr); + void (*chr_guest_close)(struct CharDriverState *chr); void *opaque; QEMUBH *bh; char *label; @@ -79,6 +81,8 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); void qemu_chr_set_echo(struct CharDriverState *chr, bool echo); +void qemu_chr_guest_open(struct CharDriverState *chr); +void qemu_chr_guest_close(struct CharDriverState *chr); void qemu_chr_close(CharDriverState *chr); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3); From 0b6d2266e3ee079c0eab4a5d2facacdcd36a329c Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 24 Mar 2011 11:12:03 +0100 Subject: [PATCH 359/386] virtio-console: notify backend of guest open / close Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Alon Levy <alevy@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- hw/virtio-console.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 6b5237b3ce..de539c4eac 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -28,6 +28,22 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) return qemu_chr_write(vcon->chr, buf, len); } +/* Callback function that's called when the guest opens the port */ +static void guest_open(VirtIOSerialPort *port) +{ + VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + + qemu_chr_guest_open(vcon->chr); +} + +/* Callback function that's called when the guest closes the port */ +static void guest_close(VirtIOSerialPort *port) +{ + VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + + qemu_chr_guest_close(vcon->chr); +} + /* Readiness of the guest to accept data on a port */ static int chr_can_read(void *opaque) { @@ -64,6 +80,8 @@ static int generic_port_init(VirtConsole *vcon, VirtIOSerialPort *port) qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, vcon); vcon->port.info->have_data = flush_buf; + vcon->port.info->guest_open = guest_open; + vcon->port.info->guest_close = guest_close; } return 0; } From cd8f7df2891891c3a6c346892545c4407be6699f Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 24 Mar 2011 11:12:04 +0100 Subject: [PATCH 360/386] spice-chardev: listen to frontend guest open / close Note the vmc_register_interface() in spice_chr_write is left in place in case someone uses spice-chardev with a frontend which does not have guest open / close notification. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Alon Levy <alevy@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- spice-qemu-char.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 517f337c43..fa15a71e14 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -131,6 +131,18 @@ static void spice_chr_close(struct CharDriverState *chr) qemu_free(s); } +static void spice_chr_guest_open(struct CharDriverState *chr) +{ + SpiceCharDriver *s = chr->opaque; + vmc_register_interface(s); +} + +static void spice_chr_guest_close(struct CharDriverState *chr) +{ + SpiceCharDriver *s = chr->opaque; + vmc_unregister_interface(s); +} + static void print_allowed_subtypes(void) { const char** psubtype; @@ -183,6 +195,8 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) chr->opaque = s; chr->chr_write = spice_chr_write; chr->chr_close = spice_chr_close; + chr->chr_guest_open = spice_chr_guest_open; + chr->chr_guest_close = spice_chr_guest_close; qemu_chr_generic_open(chr); From d5b27167e17e0d9393d6364703cc68e7f018023c Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi <slash@ac.auone-net.jp> Date: Tue, 26 Apr 2011 19:19:26 +0900 Subject: [PATCH 361/386] char: Allow devices to use a single multiplexed chardev. This fixes regression caused by commit 2d6c1ef40f3678ab47a4d14fb5dadaa486bfcda6 ("char: Prevent multiple devices opening same chardev"): -nodefaults -nographic -chardev stdio,id=stdio,mux=on,signal=off \ -mon stdio -device virtio-serial-pci \ -device virtconsole,chardev=stdio -device isa-serial,chardev=stdio fails with: qemu-system-x86_64: -device isa-serial,chardev=stdio: Property 'isa-serial.chardev' can't take value 'stdio', it's in use Signed-off-by: Kusanagi Kouichi <slash@ac.auone-net.jp> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- hw/qdev-properties.c | 4 ++-- qemu-char.c | 5 ++++- qemu-char.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 1088a26f8e..eff2d24945 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -354,10 +354,10 @@ static int parse_chr(DeviceState *dev, Property *prop, const char *str) if (*ptr == NULL) { return -ENOENT; } - if ((*ptr)->assigned) { + if ((*ptr)->avail_connections < 1) { return -EEXIST; } - (*ptr)->assigned = 1; + --(*ptr)->avail_connections; return 0; } diff --git a/qemu-char.c b/qemu-char.c index 710d98ffc4..eaf6571ac8 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -199,7 +199,7 @@ void qemu_chr_add_handlers(CharDriverState *s, { if (!opaque) { /* chr driver being released. */ - s->assigned = 0; + ++s->avail_connections; } s->chr_can_read = fd_can_read; s->chr_read = fd_read; @@ -2547,7 +2547,10 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, snprintf(base->label, len, "%s-base", qemu_opts_id(opts)); chr = qemu_chr_open_mux(base); chr->filename = base->filename; + chr->avail_connections = MAX_MUX; QTAILQ_INSERT_TAIL(&chardevs, chr, next); + } else { + chr->avail_connections = 1; } chr->label = qemu_strdup(qemu_opts_id(opts)); return chr; diff --git a/qemu-char.h b/qemu-char.h index 2f8512e528..892c6da9aa 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -72,7 +72,7 @@ struct CharDriverState { char *label; char *filename; int opened; - int assigned; /* chardev assigned to a device */ + int avail_connections; QTAILQ_ENTRY(CharDriverState) next; }; From da7d998bbb80f141ed5743418a4dfa5c1409e75f Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Mon, 25 Apr 2011 15:18:22 +0530 Subject: [PATCH 362/386] char: Detect chardev release by NULL handlers as well as NULL opaque Juan says he prefers these extra checks to ensure a user of a chardev is releasing it. Requested-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- qemu-char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index eaf6571ac8..5e04a20b8c 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -197,7 +197,7 @@ void qemu_chr_add_handlers(CharDriverState *s, IOEventHandler *fd_event, void *opaque) { - if (!opaque) { + if (!opaque && !fd_can_read && !fd_read && !fd_event) { /* chr driver being released. */ ++s->avail_connections; } From 5c1c9bb24b20fb5844d01ac67d51c26941db5af1 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy <aik@ozlabs.ru> Date: Tue, 19 Apr 2011 12:03:46 +1000 Subject: [PATCH 363/386] virtio-serial: Fix endianness bug in the config space The virtio serial specification requres that the values in the config space are encoded in native endian of the guest. The qemu virtio-serial code did not do conversion to the guest endian format what caused problems when host and guest use different format. This patch corrects the qemu side, correctly doing host-native <-> guest-native conversions when accessing the config space. This won't break any setups that aren't already broken, and fixes the case of different host and guest endianness. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> --- hw/virtio-serial-bus.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 62273799b6..f10d48fdb0 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -494,7 +494,7 @@ static void virtio_serial_save(QEMUFile *f, void *opaque) VirtIOSerial *s = opaque; VirtIOSerialPort *port; uint32_t nr_active_ports; - unsigned int i; + unsigned int i, max_nr_ports; /* The virtio device */ virtio_save(&s->vdev, f); @@ -506,8 +506,8 @@ static void virtio_serial_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->config.max_nr_ports); /* The ports map */ - - for (i = 0; i < (s->config.max_nr_ports + 31) / 32; i++) { + max_nr_ports = tswap32(s->config.max_nr_ports); + for (i = 0; i < (max_nr_ports + 31) / 32; i++) { qemu_put_be32s(f, &s->ports_map[i]); } @@ -568,7 +568,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &s->config.rows); qemu_get_be32s(f, &max_nr_ports); - if (max_nr_ports > s->config.max_nr_ports) { + tswap32s(&max_nr_ports); + if (max_nr_ports > tswap32(s->config.max_nr_ports)) { /* Source could have had more ports than us. Fail migration. */ return -EINVAL; } @@ -670,9 +671,10 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) /* This function is only used if a port id is not provided by the user */ static uint32_t find_free_port_id(VirtIOSerial *vser) { - unsigned int i; + unsigned int i, max_nr_ports; - for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) { + max_nr_ports = tswap32(vser->config.max_nr_ports); + for (i = 0; i < (max_nr_ports + 31) / 32; i++) { uint32_t map, bit; map = vser->ports_map[i]; @@ -720,7 +722,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base); VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus); - int ret; + int ret, max_nr_ports; bool plugging_port0; port->vser = bus->vser; @@ -750,9 +752,10 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) } } - if (port->id >= port->vser->config.max_nr_ports) { + max_nr_ports = tswap32(port->vser->config.max_nr_ports); + if (port->id >= max_nr_ports) { error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n", - port->vser->config.max_nr_ports - 1); + max_nr_ports - 1); return -1; } @@ -863,7 +866,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output); } - vser->config.max_nr_ports = conf->max_virtserial_ports; + vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports); vser->ports_map = qemu_mallocz(((conf->max_virtserial_ports + 31) / 32) * sizeof(vser->ports_map[0])); /* From 642cfd4d31241c0fc65c520cb1e703659af66236 Mon Sep 17 00:00:00 2001 From: Anthony Liguori <aliguori@us.ibm.com> Date: Thu, 28 Apr 2011 12:40:54 -0500 Subject: [PATCH 364/386] virtfs: fix build due from rename The latest virtfs pull broke the cris-softmmu target. Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> --- Makefile.objs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 0cbff4d293..9d8851e5d4 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -285,11 +285,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) -9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p-debug.o +9pfs-nested-$(CONFIG_REALLY_VIRTFS) = virtio-9p-debug.o 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o -hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y)) +hw-obj-$(CONFIG_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y)) $(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/ From 6f11f013a5ef88c42ce2e9060bbaafb39676ca39 Mon Sep 17 00:00:00 2001 From: Stefan Weil <weil@mail.berlios.de> Date: Wed, 27 Apr 2011 10:44:38 +0200 Subject: [PATCH 365/386] linux-user: Fix compilation for "old" linux versions Debian Lenny and other installations with older linux versions failed to compile linux-user because some CLONE_xxx macros are undefined. Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/strace.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index 5d9bb085c7..fe9326aa73 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -477,12 +477,24 @@ UNUSED static struct flags clone_flags[] = { FLAG_GENERIC(CLONE_DETACHED), FLAG_GENERIC(CLONE_UNTRACED), FLAG_GENERIC(CLONE_CHILD_SETTID), +#if defined(CLONE_NEWUTS) FLAG_GENERIC(CLONE_NEWUTS), +#endif +#if defined(CLONE_NEWIPC) FLAG_GENERIC(CLONE_NEWIPC), +#endif +#if defined(CLONE_NEWUSER) FLAG_GENERIC(CLONE_NEWUSER), +#endif +#if defined(CLONE_NEWPID) FLAG_GENERIC(CLONE_NEWPID), +#endif +#if defined(CLONE_NEWNET) FLAG_GENERIC(CLONE_NEWNET), +#endif +#if defined(CLONE_IO) FLAG_GENERIC(CLONE_IO), +#endif FLAG_END, }; From e95d3bf04d8a54af43bb8db3b8eb64d68c9f6927 Mon Sep 17 00:00:00 2001 From: Mike McCormack <mj.mccormack@samsung.com> Date: Tue, 12 Apr 2011 11:41:00 +0900 Subject: [PATCH 366/386] Fix buffer overrun in sched_getaffinity Zeroing of the cpu array should start from &cpus[kernel_ret] not &cpus[num_zeros_to_fill]. This fixes a crash in EFL's edje_cc running under qemu-arm. Signed-off-by: Mike McCormack <mj.mccormack@samsung.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Acked-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e969d1b61d..5b7b8e2394 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6505,7 +6505,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unsigned long zero = arg2 - ret; p = alloca(zero); memset(p, 0, zero); - if (copy_to_user(arg3 + zero, p, zero)) { + if (copy_to_user(arg3 + ret, p, zero)) { goto efault; } arg2 = ret; From cd18f05e248bb916028021634058da06a4657e26 Mon Sep 17 00:00:00 2001 From: Mike McCormack <mj.mccormack@samsung.com> Date: Mon, 18 Apr 2011 14:43:36 +0900 Subject: [PATCH 367/386] Don't zero out buffer in sched_getaffinity The kernel doesn't fill the buffer provided to sched_getaffinity with zero bytes, so neither should QEMU. Signed-off-by: Mike McCormack <mj.mccormack@samsung.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Riku Voipio <riku.voipio@iki.fi> --- linux-user/syscall.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5b7b8e2394..279cef3cd4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6500,20 +6500,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask)); if (!is_error(ret)) { - if (arg2 > ret) { - /* Zero out any extra space kernel didn't fill */ - unsigned long zero = arg2 - ret; - p = alloca(zero); - memset(p, 0, zero); - if (copy_to_user(arg3 + ret, p, zero)) { - goto efault; - } - arg2 = ret; - } - if (copy_to_user(arg3, mask, arg2)) { + if (copy_to_user(arg3, mask, ret)) { goto efault; } - ret = arg2; } } break; From 0c31b744f606d1c19b698041480eb195b8801747 Mon Sep 17 00:00:00 2001 From: Glauber Costa <glommer@redhat.com> Date: Thu, 17 Mar 2011 19:42:05 -0300 Subject: [PATCH 368/386] kvm: use kernel-provided para_features instead of statically coming up with new capabilities Use the features provided by KVM_GET_SUPPORTED_CPUID directly to mask out features from guest-visible cpuid. The old get_para_features() mechanism is kept for older kernels that do not implement it. Signed-off-by: Glauber Costa <glommer@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- target-i386/kvm.c | 82 +++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index a13599db81..485572f82b 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -92,6 +92,35 @@ static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max) return cpuid; } +#ifdef CONFIG_KVM_PARA +struct kvm_para_features { + int cap; + int feature; +} para_features[] = { + { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE }, + { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, + { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, +#ifdef KVM_CAP_ASYNC_PF + { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, +#endif + { -1, -1 } +}; + +static int get_para_features(CPUState *env) +{ + int i, features = 0; + + for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) { + if (kvm_check_extension(env->kvm_state, para_features[i].cap)) { + features |= (1 << para_features[i].feature); + } + } + + return features; +} +#endif + + uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, uint32_t index, int reg) { @@ -99,6 +128,9 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int i, max; uint32_t ret = 0; uint32_t cpuid_1_edx; +#ifdef CONFIG_KVM_PARA + int has_kvm_features = 0; +#endif max = 1; while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) { @@ -108,6 +140,11 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, for (i = 0; i < cpuid->nent; ++i) { if (cpuid->entries[i].function == function && cpuid->entries[i].index == index) { +#ifdef CONFIG_KVM_PARA + if (cpuid->entries[i].function == KVM_CPUID_FEATURES) { + has_kvm_features = 1; + } +#endif switch (reg) { case R_EAX: ret = cpuid->entries[i].eax; @@ -140,39 +177,16 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, qemu_free(cpuid); +#ifdef CONFIG_KVM_PARA + /* fallback for older kernels */ + if (!has_kvm_features && (function == KVM_CPUID_FEATURES)) { + ret = get_para_features(env); + } +#endif + return ret; } -#ifdef CONFIG_KVM_PARA -struct kvm_para_features { - int cap; - int feature; -} para_features[] = { - { KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE }, - { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, - { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, -#ifdef KVM_CAP_ASYNC_PF - { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, -#endif - { -1, -1 } -}; - -static int get_para_features(CPUState *env) -{ - int i, features = 0; - - for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) { - if (kvm_check_extension(env->kvm_state, para_features[i].cap)) { - features |= (1 << para_features[i].feature); - } - } -#ifdef KVM_CAP_ASYNC_PF - has_msr_async_pf_en = features & (1 << KVM_FEATURE_ASYNC_PF); -#endif - return features; -} -#endif /* CONFIG_KVM_PARA */ - typedef struct HWPoisonPage { ram_addr_t ram_addr; QLIST_ENTRY(HWPoisonPage) list; @@ -397,7 +411,13 @@ int kvm_arch_init_vcpu(CPUState *env) c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_FEATURES; - c->eax = env->cpuid_kvm_features & get_para_features(env); + c->eax = env->cpuid_kvm_features & kvm_arch_get_supported_cpuid(env, + KVM_CPUID_FEATURES, 0, R_EAX); + +#ifdef KVM_CAP_ASYNC_PF + has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); +#endif + #endif cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); From e41e0fc61ae776b9235380fe9570af31ea7bbc86 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Tue, 19 Apr 2011 13:06:06 +0200 Subject: [PATCH 369/386] x86: Allow multiple cpu feature matches of lookup_feature kvmclock is represented by two feature bits. Therefore, lookup_feature needs to continue its search even after the first match. Enhance it accordingly and switch to a bool return type at this chance. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- target-i386/cpuid.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 814d13e767..0ac592f0c1 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -182,20 +182,22 @@ static int altcmp(const char *s, const char *e, const char *altstr) } /* search featureset for flag *[s..e), if found set corresponding bit in - * *pval and return success, otherwise return zero + * *pval and return true, otherwise return false */ -static int lookup_feature(uint32_t *pval, const char *s, const char *e, - const char **featureset) +static bool lookup_feature(uint32_t *pval, const char *s, const char *e, + const char **featureset) { uint32_t mask; const char **ppc; + bool found = false; - for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) + for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) { if (*ppc && !altcmp(s, e, *ppc)) { *pval |= mask; - break; + found = true; } - return (mask ? 1 : 0); + } + return found; } static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features, From 642258c6c7f386165bc7e79dcd42040fd77df01e Mon Sep 17 00:00:00 2001 From: Glauber Costa <glommer@redhat.com> Date: Thu, 17 Mar 2011 19:42:06 -0300 Subject: [PATCH 370/386] kvm: add kvmclock to its second bit We have two bits that can represent kvmclock in cpuid. They signal the guest which msr set to use. When we tweak flags involving this value - specially when we use "-", we have to act on both. Signed-off-by: Glauber Costa <glommer@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- target-i386/cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 0ac592f0c1..e479a4dbd7 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = { }; static const char *kvm_feature_name[] = { - "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL, + "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, From 450fb75c478aa4134bc1e6b1655791c0a39ad141 Mon Sep 17 00:00:00 2001 From: Glauber Costa <glommer@redhat.com> Date: Thu, 17 Mar 2011 19:42:07 -0300 Subject: [PATCH 371/386] kvm: create kvmclock when one of the flags are present kvmclock presence can be signalled by two different flags. So for device creation, we have to test for both. Signed-off-by: Glauber Costa <glommer@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- hw/kvmclock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/kvmclock.c b/hw/kvmclock.c index b6ceddfba6..004c4add8c 100644 --- a/hw/kvmclock.c +++ b/hw/kvmclock.c @@ -103,7 +103,11 @@ static SysBusDeviceInfo kvmclock_info = { void kvmclock_create(void) { if (kvm_enabled() && - first_cpu->cpuid_kvm_features & (1ULL << KVM_FEATURE_CLOCKSOURCE)) { + first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) +#ifdef KVM_FEATURE_CLOCKSOURCE2 + || (1ULL << KVM_FEATURE_CLOCKSOURCE2) +#endif + )) { sysbus_create_simple("kvmclock", -1, NULL); } } From 97ffbd8d9d54736dd73227e5330c7f5cdc2d7a96 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Wed, 13 Apr 2011 01:32:56 +0200 Subject: [PATCH 372/386] Break up user and system cpu_interrupt implementations Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> CC: Riku Voipio <riku.voipio@iki.fi> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- exec.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index c3dc68ae09..d6d8a89110 100644 --- a/exec.c +++ b/exec.c @@ -1629,6 +1629,7 @@ static void cpu_unlink_tb(CPUState *env) spin_unlock(&interrupt_lock); } +#ifndef CONFIG_USER_ONLY /* mask must never be zero, except for A20 change call */ void cpu_interrupt(CPUState *env, int mask) { @@ -1637,7 +1638,6 @@ void cpu_interrupt(CPUState *env, int mask) old_mask = env->interrupt_request; env->interrupt_request |= mask; -#ifndef CONFIG_USER_ONLY /* * If called from iothread context, wake the target cpu in * case its halted. @@ -1646,21 +1646,27 @@ void cpu_interrupt(CPUState *env, int mask) qemu_cpu_kick(env); return; } -#endif if (use_icount) { env->icount_decr.u16.high = 0xffff; -#ifndef CONFIG_USER_ONLY if (!can_do_io(env) && (mask & ~old_mask) != 0) { cpu_abort(env, "Raised interrupt while not in I/O function"); } -#endif } else { cpu_unlink_tb(env); } } +#else /* CONFIG_USER_ONLY */ + +void cpu_interrupt(CPUState *env, int mask) +{ + env->interrupt_request |= mask; + cpu_unlink_tb(env); +} +#endif /* CONFIG_USER_ONLY */ + void cpu_reset_interrupt(CPUState *env, int mask) { env->interrupt_request &= ~mask; From ec6959d0466fb240fe4d94d5f525eebf9ba18b84 Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Wed, 13 Apr 2011 01:32:56 +0200 Subject: [PATCH 373/386] Redirect cpu_interrupt to callback handler This allows to override the interrupt handling of QEMU in system mode. KVM will make use of it to set a specialized handler. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- cpu-all.h | 14 +++++++++++++- exec.c | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 0bae6df8ec..88126ea651 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -799,7 +799,19 @@ extern CPUState *cpu_single_env; #define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ #define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */ -void cpu_interrupt(CPUState *s, int mask); +#ifndef CONFIG_USER_ONLY +typedef void (*CPUInterruptHandler)(CPUState *, int); + +extern CPUInterruptHandler cpu_interrupt_handler; + +static inline void cpu_interrupt(CPUState *s, int mask) +{ + cpu_interrupt_handler(s, mask); +} +#else /* USER_ONLY */ +void cpu_interrupt(CPUState *env, int mask); +#endif /* USER_ONLY */ + void cpu_reset_interrupt(CPUState *env, int mask); void cpu_exit(CPUState *s); diff --git a/exec.c b/exec.c index d6d8a89110..a718d747e7 100644 --- a/exec.c +++ b/exec.c @@ -1631,7 +1631,7 @@ static void cpu_unlink_tb(CPUState *env) #ifndef CONFIG_USER_ONLY /* mask must never be zero, except for A20 change call */ -void cpu_interrupt(CPUState *env, int mask) +static void tcg_handle_interrupt(CPUState *env, int mask) { int old_mask; @@ -1658,6 +1658,8 @@ void cpu_interrupt(CPUState *env, int mask) } } +CPUInterruptHandler cpu_interrupt_handler = tcg_handle_interrupt; + #else /* CONFIG_USER_ONLY */ void cpu_interrupt(CPUState *env, int mask) From aa7f74d1199020a29c677bc80518df5267bfe73f Mon Sep 17 00:00:00 2001 From: Jan Kiszka <jan.kiszka@siemens.com> Date: Wed, 13 Apr 2011 01:32:56 +0200 Subject: [PATCH 374/386] kvm: Install specialized interrupt handler KVM only requires to set the raised IRQ in CPUState and to kick the receiving vcpu if it is remote. Installing a specialized handler allows potential future changes to the TCG code path without risking KVM side effects. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- kvm-all.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index 1d7e8eabf4..fd1fbfec7a 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -651,6 +651,15 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = { .log_stop = kvm_log_stop, }; +static void kvm_handle_interrupt(CPUState *env, int mask) +{ + env->interrupt_request |= mask; + + if (!qemu_cpu_is_self(env)) { + qemu_cpu_kick(env); + } +} + int kvm_init(void) { static const char upgrade_note[] = @@ -759,6 +768,8 @@ int kvm_init(void) s->many_ioeventfds = kvm_check_many_ioeventfds(); + cpu_interrupt_handler = kvm_handle_interrupt; + return 0; err: From 51b0c6065aa6e47a47094d73e24be298a4a7f3a1 Mon Sep 17 00:00:00 2001 From: Michael Tokarev <mjt@tls.msk.ru> Date: Tue, 26 Apr 2011 20:13:49 +0400 Subject: [PATCH 375/386] fix crash in migration, 32-bit userspace on 64-bit host This change fixes a long-standing immediate crash (memory corruption and abort in glibc malloc code) in migration on 32bits. The bug is present since this commit: commit 692d9aca97b865b0f7903565274a52606910f129 Author: Bruce Rogers <brogers@novell.com> Date: Wed Sep 23 16:13:18 2009 -0600 qemu-kvm: allocate correct size for dirty bitmap The dirty bitmap copied out to userspace is stored in a long array, and gets copied out to userspace accordingly. This patch accounts for that correctly. Currently I'm seeing kvm crashing due to writing beyond the end of the alloc'd dirty bitmap memory, because the buffer has the wrong size. Signed-off-by: Bruce Rogers Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr, - buf = qemu_malloc((slots[i].len / 4096 + 7) / 8 + 2); + buf = qemu_malloc(BITMAP_SIZE(slots[i].len)); r = kvm_get_map(kvm, KVM_GET_DIRTY_LOG, i, buf); BITMAP_SIZE is now open-coded in that function, like this: size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), HOST_LONG_BITS) / 8; The problem is that HOST_LONG_BITS in 32bit userspace is 32 but it's 64 in 64bit kernel. So userspace aligns this to 32, and kernel to 64, but since no length is passed from userspace to kernel on ioctl, kernel uses its size calculation and copies 4 extra bytes to userspace, corrupting memory. Here's how it looks like during migrate execution: our=20, kern=24 our=4, kern=8 ... our=4, kern=8 our=4064, kern=4064 our=512, kern=512 our=4, kern=8 our=20, kern=24 our=4, kern=8 ... our=4, kern=8 our=4064, kern=4064 *** glibc detected *** ./x86_64-softmmu/qemu-system-x86_64: realloc(): invalid next size: 0x08f20528 *** (our is userspace size above, kern is the size as calculated by the kernel). Fix this by always aligning to 64 in a hope that no platform will have sizeof(long)>8 any time soon, and add a comment describing it all. It's a small price to pay for bad kernel design. Alternatively it's possible to fix that in the kernel by using different size calculation depending on the current process. But this becomes quite ugly. Special thanks goes to Stefan Hajnoczi for spotting the fundamental cause of the issue, and to Alexander Graf for his support in #qemu. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> CC: Bruce Rogers <brogers@novell.com> Signed-off-by: Avi Kivity <avi@redhat.com> --- kvm-all.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/kvm-all.c b/kvm-all.c index fd1fbfec7a..8b85029de3 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -373,7 +373,20 @@ static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, break; } - size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), HOST_LONG_BITS) / 8; + /* XXX bad kernel interface alert + * For dirty bitmap, kernel allocates array of size aligned to + * bits-per-long. But for case when the kernel is 64bits and + * the userspace is 32bits, userspace can't align to the same + * bits-per-long, since sizeof(long) is different between kernel + * and user space. This way, userspace will provide buffer which + * may be 4 bytes less than the kernel will use, resulting in + * userspace memory corruption (which is not detectable by valgrind + * too, in most cases). + * So for now, let's align to 64 instead of HOST_LONG_BITS here, in + * a hope that sizeof(long) wont become >8 any time soon. + */ + size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), + /*HOST_LONG_BITS*/ 64) / 8; if (!d.dirty_bitmap) { d.dirty_bitmap = qemu_malloc(size); } else if (size > allocated_size) { From 4a043713b34af8947a4e8f40a9f4f43d7a6d2ae9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini <pbonzini@redhat.com> Date: Mon, 2 May 2011 09:54:04 +0200 Subject: [PATCH 376/386] kvm: use qemu_free consistently Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> --- kvm-all.c | 4 ++-- target-i386/kvm.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 8b85029de3..d92c20e340 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1191,7 +1191,7 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, bp->use_count = 1; err = kvm_arch_insert_sw_breakpoint(current_env, bp); if (err) { - free(bp); + qemu_free(bp); return err; } @@ -1315,7 +1315,7 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset) sigmask->len = 8; memcpy(sigmask->sigset, sigset, sizeof(*sigset)); r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask); - free(sigmask); + qemu_free(sigmask); return r; } diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 485572f82b..faedc6c254 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -572,7 +572,7 @@ static int kvm_get_supported_msrs(KVMState *s) } } - free(kvm_msr_list); + qemu_free(kvm_msr_list); } return ret; From ecbe1de82362e73c2b1111770c4a91b675a6fca2 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Wed, 13 Apr 2011 00:29:33 +0200 Subject: [PATCH 377/386] lm32: fix exception handling Global interrupt enable bit is already saved within the exception handler helper routine. Thus remove extra code in translation routines. Additionally, debug exceptions has always DEBA as base address. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-lm32/helper.c | 6 +----- target-lm32/translate.c | 26 -------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/target-lm32/helper.c b/target-lm32/helper.c index 318e2cf6e0..4f3e7e0fcb 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -76,11 +76,7 @@ void do_interrupt(CPUState *env) env->regs[R_BA] = env->pc; env->ie |= (env->ie & IE_IE) ? IE_BIE : 0; env->ie &= ~IE_IE; - if (env->dc & DC_RE) { - env->pc = env->deba + (env->exception_index * 32); - } else { - env->pc = env->eba + (env->exception_index * 32); - } + env->pc = env->deba + (env->exception_index * 32); log_cpu_state_mask(CPU_LOG_INT, env, 0); break; default: diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 51b4f5a814..bcd52fe73d 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -598,36 +598,10 @@ static void dec_scall(DisasContext *dc) t0 = tcg_temp_new(); l1 = gen_new_label(); - /* save IE.IE */ - tcg_gen_andi_tl(t0, cpu_ie, IE_IE); - - /* IE.IE = 0 */ - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE); - if (dc->imm5 == 7) { - /* IE.EIE = IE.IE */ - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_EIE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_EIE); - gen_set_label(l1); - - /* gpr[ea] = PC */ - tcg_gen_movi_tl(cpu_R[R_EA], dc->pc); - tcg_temp_free(t0); - tcg_gen_movi_tl(cpu_pc, dc->pc); t_gen_raise_exception(dc, EXCP_SYSTEMCALL); } else { - /* IE.BIE = IE.IE */ - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_BIE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_BIE); - gen_set_label(l1); - - /* gpr[ba] = PC */ - tcg_gen_movi_tl(cpu_R[R_BA], dc->pc); - tcg_temp_free(t0); - tcg_gen_movi_tl(cpu_pc, dc->pc); t_gen_raise_exception(dc, EXCP_BREAKPOINT); } From c07050ddb9659805068b2f1a3686c6f096dd11f9 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Wed, 13 Apr 2011 00:29:34 +0200 Subject: [PATCH 378/386] milkymist-vgafb: fix console resizing After enabling the framebuffer, ensure that the console is resized. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/milkymist-vgafb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 8922731511..2e55e42e34 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -199,6 +199,9 @@ vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value) addr >>= 2; switch (addr) { case R_CTRL: + s->regs[addr] = value; + vgafb_resize(s); + break; case R_HSYNC_START: case R_HSYNC_END: case R_HSCAN: From f3172a0e2e7bd983cada19f11d9bb59400e0dd3d Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Wed, 13 Apr 2011 00:29:35 +0200 Subject: [PATCH 379/386] milkymist-sysctl: fix timers Prevent timers from firing right after starting. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/milkymist-sysctl.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index eaea543bf3..6bd0cb9740 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -140,24 +140,8 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value) case R_GPIO_OUT: case R_GPIO_INTEN: case R_TIMER0_COUNTER: - if (value > s->regs[R_TIMER0_COUNTER]) { - value = s->regs[R_TIMER0_COUNTER]; - error_report("milkymist_sysctl: timer0: trying to write a " - "value greater than the limit. Clipping."); - } - /* milkymist timer counts up */ - value = s->regs[R_TIMER0_COUNTER] - value; - ptimer_set_count(s->ptimer0, value); - break; case R_TIMER1_COUNTER: - if (value > s->regs[R_TIMER1_COUNTER]) { - value = s->regs[R_TIMER1_COUNTER]; - error_report("milkymist_sysctl: timer1: trying to write a " - "value greater than the limit. Clipping."); - } - /* milkymist timer counts up */ - value = s->regs[R_TIMER1_COUNTER] - value; - ptimer_set_count(s->ptimer1, value); + s->regs[addr] = value; break; case R_TIMER0_COMPARE: ptimer_set_limit(s->ptimer0, value, 0); @@ -170,10 +154,12 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value) case R_TIMER0_CONTROL: s->regs[addr] = value; if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) { - trace_milkymist_sysctl_start_timer1(); + trace_milkymist_sysctl_start_timer0(); + ptimer_set_count(s->ptimer0, + s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]); ptimer_run(s->ptimer0, 0); } else { - trace_milkymist_sysctl_stop_timer1(); + trace_milkymist_sysctl_stop_timer0(); ptimer_stop(s->ptimer0); } break; @@ -181,6 +167,8 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value) s->regs[addr] = value; if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) { trace_milkymist_sysctl_start_timer1(); + ptimer_set_count(s->ptimer1, + s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]); ptimer_run(s->ptimer1, 0); } else { trace_milkymist_sysctl_stop_timer1(); From 57aa265d462a64a06268be26d49020729cff56c1 Mon Sep 17 00:00:00 2001 From: Michael Walle <michael@walle.cc> Date: Wed, 13 Apr 2011 00:29:36 +0200 Subject: [PATCH 380/386] lm32: add Milkymist Minimac2 support This patch adds support for Milkymist's minimal Ethernet MAC v2. It superseds minimac1. Signed-off-by: Michael Walle <michael@walle.cc> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 2 +- hw/milkymist-hw.h | 20 ++ ...lkymist-minimac.c => milkymist-minimac2.c} | 297 ++++++++---------- hw/milkymist.c | 2 +- trace-events | 23 +- 5 files changed, 168 insertions(+), 176 deletions(-) rename hw/{milkymist-minimac.c => milkymist-minimac2.c} (55%) diff --git a/Makefile.target b/Makefile.target index 2501c63bb2..21f864afd2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -271,7 +271,7 @@ obj-lm32-y += lm32_sys.o obj-lm32-y += milkymist-ac97.o obj-lm32-y += milkymist-hpdmc.o obj-lm32-y += milkymist-memcard.o -obj-lm32-y += milkymist-minimac.o +obj-lm32-y += milkymist-minimac2.o obj-lm32-y += milkymist-pfpu.o obj-lm32-y += milkymist-softusb.o obj-lm32-y += milkymist-sysctl.o diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index 15acdbccd6..20de68ecce 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -1,6 +1,9 @@ #ifndef QEMU_HW_MILKYMIST_H #define QEMU_HW_MILKYMIST_H +#include "qdev.h" +#include "qdev-addr.h" + static inline DeviceState *milkymist_uart_create(target_phys_addr_t base, qemu_irq rx_irq, qemu_irq tx_irq) { @@ -183,6 +186,23 @@ static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base, return dev; } +static inline DeviceState *milkymist_minimac2_create(target_phys_addr_t base, + target_phys_addr_t buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) +{ + DeviceState *dev; + + qemu_check_nic_model(&nd_table[0], "minimac2"); + dev = qdev_create(NULL, "milkymist-minimac2"); + qdev_prop_set_taddr(dev, "buffers_base", buffers_base); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq); + + return dev; +} + static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base, qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size, uint32_t dmem_base, uint32_t dmem_size) diff --git a/hw/milkymist-minimac.c b/hw/milkymist-minimac2.c similarity index 55% rename from hw/milkymist-minimac.c rename to hw/milkymist-minimac2.c index b07f18d8a7..c4e28187b3 100644 --- a/hw/milkymist-minimac.c +++ b/hw/milkymist-minimac2.c @@ -1,7 +1,7 @@ /* - * QEMU model of the Milkymist minimac block. + * QEMU model of the Milkymist minimac2 block. * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> + * Copyright (c) 2011 Michael Walle <michael@walle.cc> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ * * * Specification available at: - * http://www.milkymist.org/socdoc/minimac.pdf + * not available yet * */ @@ -27,6 +27,7 @@ #include "trace.h" #include "net.h" #include "qemu-error.h" +#include "qdev-addr.h" #include <zlib.h> @@ -34,25 +35,15 @@ enum { R_SETUP = 0, R_MDIO, R_STATE0, - R_ADDR0, R_COUNT0, R_STATE1, - R_ADDR1, R_COUNT1, - R_STATE2, - R_ADDR2, - R_COUNT2, - R_STATE3, - R_ADDR3, - R_COUNT3, - R_TXADDR, R_TXCOUNT, R_MAX }; enum { - SETUP_RX_RST = (1<<0), - SETUP_TX_RST = (1<<2), + SETUP_PHY_RST = (1<<0), }; enum { @@ -85,9 +76,10 @@ enum { R_PHY_MAX = 32 }; -#define MINIMAC_MTU 1530 +#define MINIMAC2_MTU 1530 +#define MINIMAC2_BUFFER_SIZE 2048 -struct MilkymistMinimacMdioState { +struct MilkymistMinimac2MdioState { int last_clk; int count; uint32_t data; @@ -97,50 +89,55 @@ struct MilkymistMinimacMdioState { uint8_t phy_addr; uint8_t reg_addr; }; -typedef struct MilkymistMinimacMdioState MilkymistMinimacMdioState; +typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState; -struct MilkymistMinimacState { +struct MilkymistMinimac2State { SysBusDevice busdev; NICState *nic; NICConf conf; char *phy_model; + target_phys_addr_t buffers_base; qemu_irq rx_irq; qemu_irq tx_irq; uint32_t regs[R_MAX]; - MilkymistMinimacMdioState mdio; + MilkymistMinimac2MdioState mdio; uint16_t phy_regs[R_PHY_MAX]; + + uint8_t *rx0_buf; + uint8_t *rx1_buf; + uint8_t *tx_buf; }; -typedef struct MilkymistMinimacState MilkymistMinimacState; +typedef struct MilkymistMinimac2State MilkymistMinimac2State; static const uint8_t preamble_sfd[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5 }; -static void minimac_mdio_write_reg(MilkymistMinimacState *s, +static void minimac2_mdio_write_reg(MilkymistMinimac2State *s, uint8_t phy_addr, uint8_t reg_addr, uint16_t value) { - trace_milkymist_minimac_mdio_write(phy_addr, reg_addr, value); + trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value); /* nop */ } -static uint16_t minimac_mdio_read_reg(MilkymistMinimacState *s, +static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s, uint8_t phy_addr, uint8_t reg_addr) { uint16_t r = s->phy_regs[reg_addr]; - trace_milkymist_minimac_mdio_read(phy_addr, reg_addr, r); + trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r); return r; } -static void minimac_update_mdio(MilkymistMinimacState *s) +static void minimac2_update_mdio(MilkymistMinimac2State *s) { - MilkymistMinimacMdioState *m = &s->mdio; + MilkymistMinimac2MdioState *m = &s->mdio; /* detect rising clk edge */ if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) { @@ -173,7 +170,7 @@ static void minimac_update_mdio(MilkymistMinimacState *s) } if (m->state == MDIO_STATE_READING) { - m->data_out = minimac_mdio_read_reg(s, m->phy_addr, + m->data_out = minimac2_mdio_read_reg(s, m->phy_addr, m->reg_addr); } } @@ -192,7 +189,7 @@ static void minimac_update_mdio(MilkymistMinimacState *s) if (m->count == 0 && m->state) { if (m->state == MDIO_STATE_WRITING) { uint16_t data = m->data & 0xffff; - minimac_mdio_write_reg(s, m->phy_addr, m->reg_addr, data); + minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data); } m->state = MDIO_STATE_IDLE; } @@ -208,7 +205,7 @@ static size_t assemble_frame(uint8_t *buf, size_t size, uint32_t crc; if (size < payload_size + 12) { - error_report("milkymist_minimac: received too big ethernet frame"); + error_report("milkymist_minimac2: received too big ethernet frame"); return 0; } @@ -231,115 +228,102 @@ static size_t assemble_frame(uint8_t *buf, size_t size, return payload_size + 12; } -static void minimac_tx(MilkymistMinimacState *s) +static void minimac2_tx(MilkymistMinimac2State *s) { - uint8_t buf[MINIMAC_MTU]; uint32_t txcount = s->regs[R_TXCOUNT]; - - /* do nothing if transmission logic is in reset */ - if (s->regs[R_SETUP] & SETUP_TX_RST) { - return; - } + uint8_t *buf = s->tx_buf; if (txcount < 64) { - error_report("milkymist_minimac: ethernet frame too small (%u < %u)\n", + error_report("milkymist_minimac2: ethernet frame too small (%u < %u)\n", txcount, 64); - return; + goto err; } - if (txcount > MINIMAC_MTU) { - error_report("milkymist_minimac: MTU exceeded (%u > %u)\n", - txcount, MINIMAC_MTU); - return; + if (txcount > MINIMAC2_MTU) { + error_report("milkymist_minimac2: MTU exceeded (%u > %u)\n", + txcount, MINIMAC2_MTU); + goto err; } - /* dma */ - cpu_physical_memory_read(s->regs[R_TXADDR], buf, txcount); - if (memcmp(buf, preamble_sfd, 8) != 0) { - error_report("milkymist_minimac: frame doesn't contain the preamble " + error_report("milkymist_minimac2: frame doesn't contain the preamble " "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - return; + goto err; } - trace_milkymist_minimac_tx_frame(txcount - 12); + trace_milkymist_minimac2_tx_frame(txcount - 12); /* send packet, skipping preamble and sfd */ qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12); s->regs[R_TXCOUNT] = 0; - trace_milkymist_minimac_pulse_irq_tx(); +err: + trace_milkymist_minimac2_pulse_irq_tx(); qemu_irq_pulse(s->tx_irq); } -static ssize_t minimac_rx(VLANClientState *nc, const uint8_t *buf, size_t size) +static void update_rx_interrupt(MilkymistMinimac2State *s) { - MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + if (s->regs[R_STATE0] == STATE_PENDING + || s->regs[R_STATE1] == STATE_PENDING) { + trace_milkymist_minimac2_raise_irq_rx(); + qemu_irq_raise(s->rx_irq); + } else { + trace_milkymist_minimac2_lower_irq_rx(); + qemu_irq_lower(s->rx_irq); + } +} + +static ssize_t minimac2_rx(VLANClientState *nc, const uint8_t *buf, size_t size) +{ + MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; - uint32_t r_addr; uint32_t r_count; uint32_t r_state; + uint8_t *rx_buf; - uint8_t frame_buf[MINIMAC_MTU]; size_t frame_size; - trace_milkymist_minimac_rx_frame(buf, size); - - /* discard frames if nic is in reset */ - if (s->regs[R_SETUP] & SETUP_RX_RST) { - return size; - } + trace_milkymist_minimac2_rx_frame(buf, size); /* choose appropriate slot */ if (s->regs[R_STATE0] == STATE_LOADED) { - r_addr = R_ADDR0; r_count = R_COUNT0; r_state = R_STATE0; + rx_buf = s->rx0_buf; } else if (s->regs[R_STATE1] == STATE_LOADED) { - r_addr = R_ADDR1; r_count = R_COUNT1; r_state = R_STATE1; - } else if (s->regs[R_STATE2] == STATE_LOADED) { - r_addr = R_ADDR2; - r_count = R_COUNT2; - r_state = R_STATE2; - } else if (s->regs[R_STATE3] == STATE_LOADED) { - r_addr = R_ADDR3; - r_count = R_COUNT3; - r_state = R_STATE3; + rx_buf = s->rx1_buf; } else { - trace_milkymist_minimac_drop_rx_frame(buf); + trace_milkymist_minimac2_drop_rx_frame(buf); return size; } /* assemble frame */ - frame_size = assemble_frame(frame_buf, sizeof(frame_buf), buf, size); + frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size); if (frame_size == 0) { return size; } - trace_milkymist_minimac_rx_transfer(buf, frame_size); - - /* do dma */ - cpu_physical_memory_write(s->regs[r_addr], frame_buf, frame_size); + trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size); /* update slot */ s->regs[r_count] = frame_size; s->regs[r_state] = STATE_PENDING; - trace_milkymist_minimac_pulse_irq_rx(); - qemu_irq_pulse(s->rx_irq); + update_rx_interrupt(s); return size; } static uint32_t -minimac_read(void *opaque, target_phys_addr_t addr) +minimac2_read(void *opaque, target_phys_addr_t addr) { - MilkymistMinimacState *s = opaque; + MilkymistMinimac2State *s = opaque; uint32_t r = 0; addr >>= 2; @@ -347,39 +331,30 @@ minimac_read(void *opaque, target_phys_addr_t addr) case R_SETUP: case R_MDIO: case R_STATE0: - case R_ADDR0: case R_COUNT0: case R_STATE1: - case R_ADDR1: case R_COUNT1: - case R_STATE2: - case R_ADDR2: - case R_COUNT2: - case R_STATE3: - case R_ADDR3: - case R_COUNT3: - case R_TXADDR: case R_TXCOUNT: r = s->regs[addr]; break; default: - error_report("milkymist_minimac: read access to unknown register 0x" + error_report("milkymist_minimac2: read access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } - trace_milkymist_minimac_memory_read(addr << 2, r); + trace_milkymist_minimac2_memory_read(addr << 2, r); return r; } static void -minimac_write(void *opaque, target_phys_addr_t addr, uint32_t value) +minimac2_write(void *opaque, target_phys_addr_t addr, uint32_t value) { - MilkymistMinimacState *s = opaque; + MilkymistMinimac2State *s = opaque; - trace_milkymist_minimac_memory_read(addr, value); + trace_milkymist_minimac2_memory_read(addr, value); addr >>= 2; switch (addr) { @@ -394,58 +369,47 @@ minimac_write(void *opaque, target_phys_addr_t addr, uint32_t value) s->regs[R_MDIO] &= ~mdio_di; } - minimac_update_mdio(s); + minimac2_update_mdio(s); } break; case R_TXCOUNT: s->regs[addr] = value; if (value > 0) { - minimac_tx(s); + minimac2_tx(s); } break; - case R_SETUP: case R_STATE0: - case R_ADDR0: - case R_COUNT0: case R_STATE1: - case R_ADDR1: + s->regs[addr] = value; + update_rx_interrupt(s); + break; + case R_SETUP: + case R_COUNT0: case R_COUNT1: - case R_STATE2: - case R_ADDR2: - case R_COUNT2: - case R_STATE3: - case R_ADDR3: - case R_COUNT3: - case R_TXADDR: s->regs[addr] = value; break; default: - error_report("milkymist_minimac: write access to unknown register 0x" + error_report("milkymist_minimac2: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } } -static CPUReadMemoryFunc * const minimac_read_fn[] = { +static CPUReadMemoryFunc * const minimac2_read_fn[] = { NULL, NULL, - &minimac_read, + &minimac2_read, }; -static CPUWriteMemoryFunc * const minimac_write_fn[] = { +static CPUWriteMemoryFunc * const minimac2_write_fn[] = { NULL, NULL, - &minimac_write, + &minimac2_write, }; -static int minimac_can_rx(VLANClientState *nc) +static int minimac2_can_rx(VLANClientState *nc) { - MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; - - /* discard frames if nic is in reset */ - if (s->regs[R_SETUP] & SETUP_RX_RST) { - return 1; - } + MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; if (s->regs[R_STATE0] == STATE_LOADED) { return 1; @@ -453,27 +417,21 @@ static int minimac_can_rx(VLANClientState *nc) if (s->regs[R_STATE1] == STATE_LOADED) { return 1; } - if (s->regs[R_STATE2] == STATE_LOADED) { - return 1; - } - if (s->regs[R_STATE3] == STATE_LOADED) { - return 1; - } return 0; } -static void minimac_cleanup(VLANClientState *nc) +static void minimac2_cleanup(VLANClientState *nc) { - MilkymistMinimacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; s->nic = NULL; } -static void milkymist_minimac_reset(DeviceState *d) +static void milkymist_minimac2_reset(DeviceState *d) { - MilkymistMinimacState *s = - container_of(d, MilkymistMinimacState, busdev.qdev); + MilkymistMinimac2State *s = + container_of(d, MilkymistMinimac2State, busdev.qdev); int i; for (i = 0; i < R_MAX; i++) { @@ -488,81 +446,94 @@ static void milkymist_minimac_reset(DeviceState *d) s->phy_regs[R_PHY_ID2] = 0x161a; } -static NetClientInfo net_milkymist_minimac_info = { +static NetClientInfo net_milkymist_minimac2_info = { .type = NET_CLIENT_TYPE_NIC, .size = sizeof(NICState), - .can_receive = minimac_can_rx, - .receive = minimac_rx, - .cleanup = minimac_cleanup, + .can_receive = minimac2_can_rx, + .receive = minimac2_rx, + .cleanup = minimac2_cleanup, }; -static int milkymist_minimac_init(SysBusDevice *dev) +static int milkymist_minimac2_init(SysBusDevice *dev) { - MilkymistMinimacState *s = FROM_SYSBUS(typeof(*s), dev); + MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev); int regs; + ram_addr_t buffers; + size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE); sysbus_init_irq(dev, &s->rx_irq); sysbus_init_irq(dev, &s->tx_irq); - regs = cpu_register_io_memory(minimac_read_fn, minimac_write_fn, s, + regs = cpu_register_io_memory(minimac2_read_fn, minimac2_write_fn, s, DEVICE_NATIVE_ENDIAN); sysbus_init_mmio(dev, R_MAX * 4, regs); + /* register buffers memory */ + buffers = qemu_ram_alloc(NULL, "milkymist_minimac2.buffers", buffers_size); + s->rx0_buf = qemu_get_ram_ptr(buffers); + s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE; + s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE; + + cpu_register_physical_memory(s->buffers_base, buffers_size, + buffers | IO_MEM_RAM); + qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_milkymist_minimac_info, &s->conf, + s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, dev->qdev.info->name, dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; } -static const VMStateDescription vmstate_milkymist_minimac_mdio = { - .name = "milkymist_minimac_mdio", +static const VMStateDescription vmstate_milkymist_minimac2_mdio = { + .name = "milkymist-minimac2-mdio", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_INT32(last_clk, MilkymistMinimacMdioState), - VMSTATE_INT32(count, MilkymistMinimacMdioState), - VMSTATE_UINT32(data, MilkymistMinimacMdioState), - VMSTATE_UINT16(data_out, MilkymistMinimacMdioState), - VMSTATE_INT32(state, MilkymistMinimacMdioState), - VMSTATE_UINT8(phy_addr, MilkymistMinimacMdioState), - VMSTATE_UINT8(reg_addr, MilkymistMinimacMdioState), + VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState), + VMSTATE_INT32(count, MilkymistMinimac2MdioState), + VMSTATE_UINT32(data, MilkymistMinimac2MdioState), + VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState), + VMSTATE_INT32(state, MilkymistMinimac2MdioState), + VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState), + VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState), VMSTATE_END_OF_LIST() } }; -static const VMStateDescription vmstate_milkymist_minimac = { - .name = "milkymist-minimac", +static const VMStateDescription vmstate_milkymist_minimac2 = { + .name = "milkymist-minimac2", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistMinimacState, R_MAX), - VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimacState, R_PHY_MAX), - VMSTATE_STRUCT(mdio, MilkymistMinimacState, 0, - vmstate_milkymist_minimac_mdio, MilkymistMinimacMdioState), + VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX), + VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX), + VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0, + vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState), VMSTATE_END_OF_LIST() } }; -static SysBusDeviceInfo milkymist_minimac_info = { - .init = milkymist_minimac_init, - .qdev.name = "milkymist-minimac", - .qdev.size = sizeof(MilkymistMinimacState), - .qdev.vmsd = &vmstate_milkymist_minimac, - .qdev.reset = milkymist_minimac_reset, +static SysBusDeviceInfo milkymist_minimac2_info = { + .init = milkymist_minimac2_init, + .qdev.name = "milkymist-minimac2", + .qdev.size = sizeof(MilkymistMinimac2State), + .qdev.vmsd = &vmstate_milkymist_minimac2, + .qdev.reset = milkymist_minimac2_reset, .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(MilkymistMinimacState, conf), - DEFINE_PROP_STRING("phy_model", MilkymistMinimacState, phy_model), + DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State, + buffers_base, 0), + DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf), + DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model), DEFINE_PROP_END_OF_LIST(), } }; -static void milkymist_minimac_register(void) +static void milkymist_minimac2_register(void) { - sysbus_register_withprop(&milkymist_minimac_info); + sysbus_register_withprop(&milkymist_minimac2_info); } -device_init(milkymist_minimac_register) +device_init(milkymist_minimac2_register) diff --git a/hw/milkymist.c b/hw/milkymist.c index 8defad8024..787984040f 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -156,7 +156,7 @@ milkymist_init(ram_addr_t ram_size_not_used, milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]); milkymist_pfpu_create(0x60006000, irq[9]); milkymist_tmu2_create(0x60007000, irq[10]); - milkymist_minimac_create(0x60008000, irq[11], irq[12]); + milkymist_minimac2_create(0x60008000, 0x30000000, irq[11], irq[12]); milkymist_softusb_create(0x6000f000, irq[17], 0x20000000, 0x1000, 0x20020000, 0x2000); diff --git a/trace-events b/trace-events index 77c96a5978..4f965e2ebd 100644 --- a/trace-events +++ b/trace-events @@ -308,17 +308,18 @@ disable milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x v disable milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" disable milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -# hw/milkymist-minimac.c -disable milkymist_minimac_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -disable milkymist_minimac_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -disable milkymist_minimac_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" -disable milkymist_minimac_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" -disable milkymist_minimac_tx_frame(uint32_t length) "length %u" -disable milkymist_minimac_rx_frame(const void *buf, uint32_t length) "buf %p length %u" -disable milkymist_minimac_drop_rx_frame(const void *buf) "buf %p" -disable milkymist_minimac_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" -disable milkymist_minimac_pulse_irq_rx(void) "Pulse IRQ RX" -disable milkymist_minimac_pulse_irq_tx(void) "Pulse IRQ TX" +# hw/milkymist-minimac2.c +disable milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" +disable milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" +disable milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" +disable milkymist_minimac2_tx_frame(uint32_t length) "length %u" +disable milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u" +disable milkymist_minimac2_drop_rx_frame(const void *buf) "buf %p" +disable milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" +disable milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX" +disable milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX" +disable milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX" # hw/milkymist-pfpu.c disable milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" From e80fec7feb62c741df5360c1841ca49e4087c1cd Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Fri, 29 Apr 2011 10:58:12 +0200 Subject: [PATCH 381/386] qemu-img resize: Fix option parsing For shrinking images, you're supposed to use a negative size. However, the leading minus makes getopt think that it's an option and so you get the help text if you don't use -- like in 'qemu-img resize test.img -- -1G'. This patch handles the size first and removes it from the argument list so that getopt won't even try to interpret it and you don't need -- any more. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-img.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index ed5ba91117..e8251234b1 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1442,6 +1442,16 @@ static int img_resize(int argc, char **argv) { NULL } }; + /* Remove size from argv manually so that negative numbers are not treated + * as options by getopt. */ + if (argc < 3) { + help(); + return 1; + } + + size = argv[--argc]; + + /* Parse getopt arguments */ fmt = NULL; for(;;) { c = getopt(argc, argv, "f:h"); @@ -1458,11 +1468,10 @@ static int img_resize(int argc, char **argv) break; } } - if (optind + 1 >= argc) { + if (optind >= argc) { help(); } filename = argv[optind++]; - size = argv[optind++]; /* Choose grow, shrink, or absolute resize mode */ switch (size[0]) { From a7acf552e2cfb42ea1b27966b7f318eca2cc478a Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Thu, 28 Apr 2011 20:04:40 +0530 Subject: [PATCH 382/386] atapi: Move comment to proper place Move misplaced comment for media_is_dvd() Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 690a0abdda..86b18d894c 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -71,12 +71,12 @@ static void lba_to_msf(uint8_t *buf, int lba) buf[2] = lba % 75; } -/* XXX: DVDs that could fit on a CD will be reported as a CD */ static inline int media_present(IDEState *s) { return (s->nb_sectors > 0); } +/* XXX: DVDs that could fit on a CD will be reported as a CD */ static inline int media_is_dvd(IDEState *s) { return (media_present(s) && s->nb_sectors > CD_MAX_SECTORS); From 4a737d14d0788412eead23330b554eb75900af04 Mon Sep 17 00:00:00 2001 From: Amit Shah <amit.shah@redhat.com> Date: Thu, 28 Apr 2011 20:04:41 +0530 Subject: [PATCH 383/386] atapi: Explain why we need a 'media not present' state After the re-org of the atapi code, it might not be intuitive for a reader of the code to understand why we're inserting a 'media not present' state between cd changes. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 86b18d894c..58febc0285 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -1106,7 +1106,13 @@ void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_check_status(s); return; } - + /* + * When a CD gets changed, we have to report an ejected state and + * then a loaded state to guests so that they detect tray + * open/close and media change events. Guests that do not use + * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close + * states rely on this behavior. + */ if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); From ab71982716928577826b9aa7fc9a5102bfce5f0e Mon Sep 17 00:00:00 2001 From: Alon Levy <alevy@redhat.com> Date: Thu, 28 Apr 2011 16:34:39 +0300 Subject: [PATCH 384/386] ide/atapi: fix set but unused Signed-off-by: Alon Levy <alevy@redhat.com> Acked-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- hw/ide/atapi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 58febc0285..fe2fb0b806 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -1080,17 +1080,15 @@ static const struct { void ide_atapi_cmd(IDEState *s) { - const uint8_t *packet; uint8_t *buf; - packet = s->io_buffer; buf = s->io_buffer; #ifdef DEBUG_IDE_ATAPI { int i; printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); for(i = 0; i < ATAPI_PACKET_SIZE; i++) { - printf(" %02x", packet[i]); + printf(" %02x", buf[i]); } printf("\n"); } From 2ab3cb8c0ae79c96f38f6bfd35620cc18ddba19f Mon Sep 17 00:00:00 2001 From: Jes Sorensen <Jes.Sorensen@redhat.com> Date: Thu, 28 Apr 2011 13:58:30 +0200 Subject: [PATCH 385/386] qemu-progress.c: printf isn't signal safe Change the signal handling to indicate a signal is pending, rather then printing directly from the signal handler. In addition make the signal prints go to stderr, rather than stdout. Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- qemu-progress.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu-progress.c b/qemu-progress.c index e1feb89614..a4894c0dfc 100644 --- a/qemu-progress.c +++ b/qemu-progress.c @@ -37,6 +37,7 @@ struct progress_state { }; static struct progress_state state; +static volatile sig_atomic_t print_pending; /* * Simple progress print function. @@ -63,12 +64,16 @@ static void progress_simple_init(void) #ifdef CONFIG_POSIX static void sigusr_print(int signal) { - printf(" (%3.2f/100%%)\n", state.current); + print_pending = 1; } #endif static void progress_dummy_print(void) { + if (print_pending) { + fprintf(stderr, " (%3.2f/100%%)\n", state.current); + print_pending = 0; + } } static void progress_dummy_end(void) From d2d979c628e4b2c4a3cb71a31841875795c79043 Mon Sep 17 00:00:00 2001 From: Nick Thomas <nick@bytemark.co.uk> Date: Thu, 28 Apr 2011 16:20:01 +0100 Subject: [PATCH 386/386] NBD: Avoid leaking a couple of strings when the NBD device is closed Signed-off-by: Nick Thomas <nick@bytemark.co.uk> Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/nbd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/nbd.c b/block/nbd.c index 1d6b22561b..7a52f62e7e 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -239,6 +239,10 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num, static void nbd_close(BlockDriverState *bs) { + BDRVNBDState *s = bs->opaque; + qemu_free(s->export_name); + qemu_free(s->host_spec); + nbd_teardown_connection(bs); }