diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/baum.c | 9 | ||||
| -rw-r--r-- | hw/baum.h | 30 | ||||
| -rw-r--r-- | hw/elf_ops.h | 19 | ||||
| -rw-r--r-- | hw/loader.c | 75 | ||||
| -rw-r--r-- | hw/loader.h | 2 | ||||
| -rw-r--r-- | hw/mac_dbdma.c | 4 | ||||
| -rw-r--r-- | hw/msmouse.c | 10 | ||||
| -rw-r--r-- | hw/msmouse.h | 7 | ||||
| -rw-r--r-- | hw/ppc/mac_newworld.c | 2 | ||||
| -rw-r--r-- | hw/serial.c | 28 | ||||
| -rw-r--r-- | hw/serial.h | 2 | ||||
| -rw-r--r-- | hw/spapr.c | 1 | ||||
| -rw-r--r-- | hw/spapr_hcall.c | 31 | ||||
| -rw-r--r-- | hw/spapr_llan.c | 8 | ||||
| -rw-r--r-- | hw/virtio-console.c | 28 | ||||
| -rw-r--r-- | hw/virtio-serial-bus.c | 19 |
16 files changed, 169 insertions, 106 deletions
diff --git a/hw/baum.c b/hw/baum.c index 09dcb9cc74..d75b15007d 100644 --- a/hw/baum.c +++ b/hw/baum.c @@ -562,7 +562,7 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -CharDriverState *chr_baum_init(QemuOpts *opts) +static CharDriverState *chr_baum_init(QemuOpts *opts) { BaumDriverState *baum; CharDriverState *chr; @@ -625,3 +625,10 @@ fail_handle: g_free(baum); return NULL; } + +static void register_types(void) +{ + register_char_driver("braille", chr_baum_init); +} + +type_init(register_types); diff --git a/hw/baum.h b/hw/baum.h deleted file mode 100644 index 763588422a..0000000000 --- a/hw/baum.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * QEMU Baum - * - * Copyright (c) 2008 Samuel Thibault - * - * 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. - */ -#ifndef HW_BAUM_H -#define HW_BAUM_H 1 - -/* char device */ -CharDriverState *chr_baum_init(QemuOpts *opts); - -#endif diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 531a42553b..acc701e3a4 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -197,7 +197,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; - elf_word mem_size; + elf_word mem_size, file_size; uint64_t addr, low = (uint64_t)-1, high = 0; uint8_t *data = NULL; char label[128]; @@ -252,14 +252,16 @@ static int glue(load_elf, SZ)(const char *name, int fd, for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; if (ph->p_type == PT_LOAD) { - mem_size = ph->p_memsz; - /* XXX: avoid allocating */ - data = g_malloc0(mem_size); + mem_size = ph->p_memsz; /* Size of the ROM */ + file_size = ph->p_filesz; /* Size of the allocated data */ + data = g_malloc0(file_size); if (ph->p_filesz > 0) { - if (lseek(fd, ph->p_offset, SEEK_SET) < 0) + if (lseek(fd, ph->p_offset, SEEK_SET) < 0) { goto fail; - if (read(fd, data, ph->p_filesz) != ph->p_filesz) + } + if (read(fd, data, file_size) != file_size) { goto fail; + } } /* address_offset is hack for kernel images that are linked at the wrong physical address. */ @@ -281,7 +283,9 @@ static int glue(load_elf, SZ)(const char *name, int fd, } snprintf(label, sizeof(label), "phdr #%d: %s", i, name); - rom_add_blob_fixed(label, data, mem_size, addr); + + /* rom_add_elf_program() seize the ownership of 'data' */ + rom_add_elf_program(label, data, file_size, mem_size, addr); total_size += mem_size; if (addr < low) @@ -289,7 +293,6 @@ static int glue(load_elf, SZ)(const char *name, int fd, if ((addr + mem_size) > high) high = addr + mem_size; - g_free(data); data = NULL; } } diff --git a/hw/loader.c b/hw/loader.c index 995edc3f98..bd2b52d14e 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -533,7 +533,14 @@ typedef struct Rom Rom; struct Rom { char *name; char *path; + + /* datasize is the amount of memory allocated in "data". If datasize is less + * than romsize, it means that the area from datasize to romsize is filled + * with zeros. + */ size_t romsize; + size_t datasize; + uint8_t *data; int isrom; char *fw_dir; @@ -589,14 +596,15 @@ int rom_add_file(const char *file, const char *fw_dir, rom->fw_dir = g_strdup(fw_dir); rom->fw_file = g_strdup(file); } - rom->addr = addr; - rom->romsize = lseek(fd, 0, SEEK_END); - rom->data = g_malloc0(rom->romsize); + rom->addr = addr; + rom->romsize = lseek(fd, 0, SEEK_END); + rom->datasize = rom->romsize; + rom->data = g_malloc0(rom->datasize); lseek(fd, 0, SEEK_SET); - rc = read(fd, rom->data, rom->romsize); - if (rc != rom->romsize) { + rc = read(fd, rom->data, rom->datasize); + if (rc != rom->datasize) { fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", - rom->name, rc, rom->romsize); + rom->name, rc, rom->datasize); goto err; } close(fd); @@ -637,16 +645,37 @@ int rom_add_blob(const char *name, const void *blob, size_t len, { Rom *rom; - rom = g_malloc0(sizeof(*rom)); - rom->name = g_strdup(name); - rom->addr = addr; - rom->romsize = len; - rom->data = g_malloc0(rom->romsize); + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->romsize = len; + rom->datasize = len; + rom->data = g_malloc0(rom->datasize); memcpy(rom->data, blob, len); rom_insert(rom); return 0; } +/* This function is specific for elf program because we don't need to allocate + * all the rom. We just allocate the first part and the rest is just zeros. This + * is why romsize and datasize are different. Also, this function seize the + * memory ownership of "data", so we don't have to allocate and copy the buffer. + */ +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr) +{ + Rom *rom; + + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->datasize = datasize; + rom->romsize = romsize; + rom->data = data; + rom_insert(rom); + return 0; +} + int rom_add_vga(const char *file) { return rom_add_file(file, "vgaroms", 0, -1); @@ -668,7 +697,7 @@ static void rom_reset(void *unused) if (rom->data == NULL) { continue; } - cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize); + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); if (rom->isrom) { /* rom needs to be written only once */ g_free(rom->data); @@ -756,13 +785,33 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) d = dest + (rom->addr - addr); s = rom->data; - l = rom->romsize; + l = rom->datasize; if ((d + l) > (dest + size)) { l = dest - d; } memcpy(d, s, l); + + if (rom->romsize > rom->datasize) { + /* If datasize is less than romsize, it means that we didn't + * allocate all the ROM because the trailing data are only zeros. + */ + + d += l; + l = rom->romsize - rom->datasize; + + if ((d + l) > (dest + size)) { + /* Rom size doesn't fit in the destination area. Adjust to avoid + * overflow. + */ + l = dest - d; + } + + if (l > 0) { + memset(d, 0x0, l); + } + } } return (d + l) - dest; diff --git a/hw/loader.h b/hw/loader.h index 5e61c95b84..0958f06934 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -27,6 +27,8 @@ int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex); int rom_add_blob(const char *name, const void *blob, size_t len, hwaddr addr); +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr); int rom_load_all(void); void rom_set_fw(void *f); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index b894ab21aa..73d74c2c59 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -688,6 +688,10 @@ dbdma_control_write(DBDMA_channel *ch) if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { /* RUN is cleared */ status &= ~(ACTIVE|DEAD); + if ((status & FLUSH) && ch->flush) { + ch->flush(&ch->io); + status &= ~FLUSH; + } } DBDMA_DPRINTF(" status 0x%08x\n", status); diff --git a/hw/msmouse.c b/hw/msmouse.c index ef47aed4e9..407ec87784 100644 --- a/hw/msmouse.c +++ b/hw/msmouse.c @@ -25,7 +25,6 @@ #include "qemu-common.h" #include "char/char.h" #include "ui/console.h" -#include "msmouse.h" #define MSMOUSE_LO6(n) ((n) & 0x3f) #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) @@ -64,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) +static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) { CharDriverState *chr; @@ -76,3 +75,10 @@ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) return chr; } + +static void register_types(void) +{ + register_char_driver("msmouse", qemu_chr_open_msmouse); +} + +type_init(register_types); diff --git a/hw/msmouse.h b/hw/msmouse.h deleted file mode 100644 index 8cff3a71c3..0000000000 --- a/hw/msmouse.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef HW_MSMOUSE_H -#define HW_MSMOUSE_H 1 - -/* msmouse.c */ -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); - -#endif diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 065ea871b3..a08a6b2086 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -370,7 +370,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ - qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ diff --git a/hw/serial.c b/hw/serial.c index f0ce9b0c15..eb38f2231d 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -256,16 +256,17 @@ static void serial_update_msl(SerialState *s) qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100); } -static void serial_xmit(void *opaque) +static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { SerialState *s = opaque; - uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); if (s->tsr_retry <= 0) { if (s->fcr & UART_FCR_FE) { s->tsr = fifo_get(s,XMIT_FIFO); if (!s->xmit_fifo.count) s->lsr |= UART_LSR_THRE; + } else if ((s->lsr & UART_LSR_THRE)) { + return FALSE; } else { s->tsr = s->thr; s->lsr |= UART_LSR_THRE; @@ -277,30 +278,25 @@ static void serial_xmit(void *opaque) /* in loopback mode, say that we just received a char */ serial_receive1(s, &s->tsr, 1); } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { - if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { + if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) { s->tsr_retry++; - qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); - return; - } else if (s->poll_msl < 0) { - /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then - drop any further failed writes instantly, until we get one that goes through. - This is to prevent guests that log to unconnected pipes or pty's from stalling. */ - s->tsr_retry = -1; + return FALSE; } - } - else { + s->tsr_retry = 0; + } else { s->tsr_retry = 0; } s->last_xmit_ts = qemu_get_clock_ns(vm_clock); - if (!(s->lsr & UART_LSR_THRE)) - qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); if (s->lsr & UART_LSR_THRE) { s->lsr |= UART_LSR_TEMT; s->thr_ipending = 1; serial_update_irq(s); } + + return FALSE; } @@ -330,7 +326,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); } - serial_xmit(s); + serial_xmit(NULL, G_IO_OUT, s); } break; case 1: @@ -684,8 +680,6 @@ void serial_init_core(SerialState *s) s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s); s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); - s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s); - qemu_register_reset(serial_reset, s); qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, diff --git a/hw/serial.h b/hw/serial.h index 98ee4241be..e57375d03c 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -72,8 +72,6 @@ struct SerialState { struct QEMUTimer *fifo_timeout_timer; int timeout_ipending; /* timeout interrupt pending state */ - struct QEMUTimer *transmit_timer; - uint64_t char_transmit_time; /* time to transmit a char in ticks */ int poll_msl; diff --git a/hw/spapr.c b/hw/spapr.c index e88a27aa71..fadf70f952 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -260,6 +260,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_begin_node(fdt, ""))); _FDT((fdt_property_string(fdt, "device_type", "chrp"))); _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); + _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries"))); _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 7b8959488e..77c052fcb1 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -323,6 +323,36 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + uint8_t *hpte; + int i, ridx, n_entries = 1; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + if (flags & H_READ_4) { + /* Clear the two low order bits */ + pte_index &= ~(3ULL); + n_entries = 4; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + + for (i = 0, ridx = 0; i < n_entries; i++) { + args[ridx++] = ldq_p(hpte); + args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + hpte += HASH_PTE_SIZE_64; + } + + return H_SUCCESS; +} + static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -710,6 +740,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_ENTER, h_enter); spapr_register_hypercall(H_REMOVE, h_remove); spapr_register_hypercall(H_PROTECT, h_protect); + spapr_register_hypercall(H_READ, h_read); /* hcall-bulk */ spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 6ef29362f5..0ace2eb1f3 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -175,11 +175,19 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, return size; } +static void spapr_vlan_cleanup(NetClientState *nc) +{ + VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc); + + dev->nic = NULL; +} + static NetClientInfo net_spapr_vlan_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = spapr_vlan_can_receive, .receive = spapr_vlan_receive, + .cleanup = spapr_vlan_cleanup, }; static void spapr_vlan_reset(VIOsPAPRDevice *sdev) diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 46072a086f..194de6431e 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -20,6 +20,18 @@ typedef struct VirtConsole { CharDriverState *chr; } VirtConsole; +/* + * Callback function that's called from chardevs when backend becomes + * writable. + */ +static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + VirtConsole *vcon = opaque; + + virtio_serial_throttle_port(&vcon->port, false); + return FALSE; +} /* Callback function that's called when the guest sends us data */ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) @@ -35,19 +47,21 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) ret = qemu_chr_fe_write(vcon->chr, buf, len); trace_virtio_console_flush_buf(port->id, len, ret); - if (ret < 0) { + if (ret <= 0) { + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); + /* * Ideally we'd get a better error code than just -1, but * that's what the chardev interface gives us right now. If * we had a finer-grained message, like -EPIPE, we could close - * this connection. Absent such error messages, the most we - * can do is to return 0 here. - * - * This will prevent stray -1 values to go to - * virtio-serial-bus.c and cause abort()s in - * do_flush_queued_data(). + * this connection. */ ret = 0; + if (!k->is_console) { + virtio_serial_throttle_port(port, true); + qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked, + vcon); + } } return ret; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index aa7d0d7fc7..f76c5058ba 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -172,24 +172,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, port->elem.out_sg[i].iov_base + port->iov_offset, buf_size); - if (ret < 0 && ret != -EAGAIN) { - /* We don't handle any other type of errors here */ - abort(); - } - if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) { - /* - * this is a temporary check until chardevs can signal to - * frontends that they are writable again. This prevents - * the console from going into throttled mode (forever) - * if virtio-console is connected to a pty without a - * listener. Otherwise the guest spins forever. - * We can revert this if - * 1: chardevs can notify frondends - * 2: the guest driver does not spin in these cases - */ - if (!vsc->is_console) { - virtio_serial_throttle_port(port, true); - } + if (port->throttled) { port->iov_idx = i; if (ret > 0) { port->iov_offset += ret; |