From d0a981b2d50919bea53986f28234ee7402597f7c Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 31 Mar 2009 14:34:24 +0000 Subject: Avoid rounding problems in ptimer_get_count Signed-off-by: Paul Brook git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6961 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ptimer.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/hw/ptimer.c b/hw/ptimer.c index 9d3862724..b36f9a6f0 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -7,7 +7,7 @@ */ #include "hw.h" #include "qemu-timer.h" - +#include "host-utils.h" struct ptimer_state { @@ -78,9 +78,39 @@ uint64_t ptimer_get_count(ptimer_state *s) } else { uint64_t rem; uint64_t div; + uint32_t frac; + int clz1, clz2; + int shift; + + /* We need to divide time by period, where time is stored in + rem (64-bit integer) and period is stored in period/period_frac + (64.32 fixed point). + + Doing full precision division is hard, so scale values and + do a 64-bit division. The result should be rounded down, + so that the rounding error never causes the timer to go + backwards. + */ rem = s->next_event - now; div = s->period; + + clz1 = clz64(rem); + clz2 = clz64(div); + shift = clz1 < clz2 ? clz1 : clz2; + + rem <<= shift; + div <<= shift; + if (shift >= 32) { + div |= ((uint64_t)s->period_frac << (shift - 32)); + } else { + if (shift != 0) + div |= (s->period_frac >> (32 - shift)); + /* Look at remaining bits of period_frac and round div up if + necessary. */ + if ((uint32_t)(s->period_frac << shift)) + div += 1; + } counter = rem / div; } } else { -- cgit v1.2.3 From 9d479c119b42b8a548f8d79a8e5a1c1ce2932d91 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 31 Mar 2009 15:46:09 +0000 Subject: Update OpenBIOS images to r482 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6962 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-ppc | Bin 271336 -> 271336 bytes pc-bios/openbios-sparc32 | Bin 234116 -> 238212 bytes pc-bios/openbios-sparc64 | Bin 476064 -> 476064 bytes 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 4b9b2c5bb..162dfe807 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -42,7 +42,7 @@ firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for Sparc32, Sparc64 and PowerPC (for 32 and 64 bit - PPC CPUs) are built from OpenBIOS SVN revision 479. + PPC CPUs) are built from OpenBIOS SVN revision 482. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index d0fa6c930..00d9a78eb 100644 Binary files a/pc-bios/openbios-ppc and b/pc-bios/openbios-ppc differ diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 8f6289e05..7c84965b7 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index b23d3bbb2..76886f49c 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From 61f14e107473237323330134e721ffa76eeb1b1e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 31 Mar 2009 17:18:10 +0000 Subject: Remove unused variable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6963 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ptimer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ptimer.c b/hw/ptimer.c index b36f9a6f0..f1994bd2b 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -78,7 +78,6 @@ uint64_t ptimer_get_count(ptimer_state *s) } else { uint64_t rem; uint64_t div; - uint32_t frac; int clz1, clz2; int shift; -- cgit v1.2.3 From 602dafcf43d8a35ff77e33377c1f258515812e5b Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 1 Apr 2009 11:43:02 +0000 Subject: Use pixel_ops.h Signed-off-by: Paul Brook git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6964 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/hw/pl110.c b/hw/pl110.c index bc33da7d5..7ce74a2f6 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -59,30 +59,7 @@ static const unsigned char pl110_versatile_id[] = #define pl110_versatile_id pl110_id #endif -static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} +#include "pixel_ops.h" typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int); -- cgit v1.2.3 From 714fa308a3f86e1dc55021ff1282c1afe6954d3d Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 1 Apr 2009 12:27:59 +0000 Subject: Implement and use shared memory framebuffer device rendering reoutine. Use DMA mapping API. Signed-off-by: Paul Brook git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6965 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/framebuffer.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/framebuffer.h | 22 +++++++++ hw/omap.h | 2 +- hw/omap_lcd_template.h | 23 +++++----- hw/omap_lcdc.c | 96 +++++++++++++-------------------------- hw/pl110.c | 61 +++++-------------------- hw/pl110_template.h | 16 ++++--- hw/pxa2xx_lcd.c | 117 ++++++++++++------------------------------------ hw/pxa2xx_template.h | 27 ++++++----- 10 files changed, 253 insertions(+), 231 deletions(-) create mode 100644 hw/framebuffer.c create mode 100644 hw/framebuffer.h diff --git a/Makefile.target b/Makefile.target index f862d9091..046427d4f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -672,6 +672,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o OBJS+= tsc2005.o bt-hci-csr.o OBJS+= mst_fpga.o mainstone.o OBJS+= musicpal.o pflash_cfi02.o +OBJS+= framebuffer.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/framebuffer.c b/hw/framebuffer.c new file mode 100644 index 000000000..1086ba9d0 --- /dev/null +++ b/hw/framebuffer.c @@ -0,0 +1,119 @@ +/* + * Framebuffer device helper routines + * + * Copyright (c) 2009 CodeSourcery + * Written by Paul Brook + * + * This code is licensed under the GNU GPLv2. + */ + +/* TODO: + - Do something similar for framebuffers with local ram + - Handle rotation here instead of hacking dest_pitch + - Use common pixel conversion routines instead of per-device drawfn + - Remove all DisplayState knowledge from devices. + */ + +#include "hw.h" +#include "console.h" +#include "framebuffer.h" +#include "kvm.h" + +/* Render an image from a shared memory framebuffer. */ + +void framebuffer_update_display( + DisplayState *ds, + target_phys_addr_t base, + int cols, /* Width in pixels. */ + int rows, /* Leight in pixels. */ + int src_width, /* Length of source line, in bytes. */ + int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */ + int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */ + int invalidate, /* nonzero to redraw the whole image. */ + drawfn fn, + void *opaque, + int *first_row, /* Input and output. */ + int *last_row /* Output only */) +{ + target_phys_addr_t src_len; + uint8_t *dest; + uint8_t *src; + uint8_t *src_base; + int first, last = 0; + int dirty; + int i; + ram_addr_t addr; + ram_addr_t pd; + ram_addr_t pd2; + + i = *first_row; + *first_row = -1; + src_len = src_width * rows; + + if (kvm_enabled()) { + kvm_physical_sync_dirty_bitmap(base, src_len); + } + pd = cpu_get_physical_page_desc(base); + pd2 = cpu_get_physical_page_desc(base + src_len - 1); + /* We should reall check that this is a continuous ram region. + Instead we just check that the first and last pages are + both ram, and the right distance apart. */ + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM + || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + return; + } + pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK); + if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) { + return; + } + + src_base = cpu_physical_memory_map(base, &src_len, 0); + /* If we can't map the framebuffer then bail. We could try harder, + but it's not really worth it as dirty flag tracking will probably + already have failed above. */ + if (!src_base) + return; + if (src_len != src_width * rows) { + cpu_physical_memory_unmap(src_base, src_len, 0, 0); + return; + } + src = src_base; + dest = ds_get_data(ds); + if (dest_col_pitch < 0) + dest -= dest_col_pitch * (cols - 1); + first = -1; + addr = pd; + + addr += i * src_width; + src += i * src_width; + dest += i * dest_row_pitch; + + for (; i < rows; i++) { + target_phys_addr_t dirty_offset; + dirty = 0; + dirty_offset = 0; + while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) { + dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset, + VGA_DIRTY_FLAG); + dirty_offset += TARGET_PAGE_SIZE; + } + + if (dirty || invalidate) { + fn(opaque, dest, src, cols, dest_col_pitch); + if (first == -1) + first = i; + last = i; + } + addr += src_width; + src += src_width; + dest += dest_row_pitch; + } + cpu_physical_memory_unmap(src_base, src_len, 0, 0); + if (first < 0) { + return; + } + cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG); + *first_row = first; + *last_row = last; + return; +} diff --git a/hw/framebuffer.h b/hw/framebuffer.h new file mode 100644 index 000000000..a3a214649 --- /dev/null +++ b/hw/framebuffer.h @@ -0,0 +1,22 @@ +#ifndef QEMU_FRAMEBUFFER_H +#define QEMU_FRAMEBUFFER_H + +/* Framebuffer device helper routines. */ + +typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int); + +void framebuffer_update_display( + DisplayState *ds, + target_phys_addr_t base, + int cols, + int rows, + int src_width, + int dest_row_pitch, + int dest_col_pitch, + int invalidate, + drawfn fn, + void *opaque, + int *first_row, + int *last_row); + +#endif diff --git a/hw/omap.h b/hw/omap.h index 7965eb260..e94047460 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -490,7 +490,7 @@ struct omap_dma_lcd_channel_s { int dual; int current_frame; - ram_addr_t phys_framebuffer[2]; + target_phys_addr_t phys_framebuffer[2]; qemu_irq irq; struct omap_mpu_state_s *mpu; } *omap_dma_get_lcdch(struct soc_dma_s *s); diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h index 4e84fa1d9..0590e4501 100644 --- a/hw/omap_lcd_template.h +++ b/hw/omap_lcd_template.h @@ -43,9 +43,10 @@ /* * 2-bit colour */ -static void glue(draw_line2_, DEPTH)( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +static void glue(draw_line2_, DEPTH)(void *opaque, + uint8_t *d, const uint8_t *s, int width, int deststep) { + uint16_t *pal = opaque; uint8_t v, r, g, b; do { @@ -81,9 +82,10 @@ static void glue(draw_line2_, DEPTH)( /* * 4-bit colour */ -static void glue(draw_line4_, DEPTH)( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +static void glue(draw_line4_, DEPTH)(void *opaque, + uint8_t *d, const uint8_t *s, int width, int deststep) { + uint16_t *pal = opaque; uint8_t v, r, g, b; do { @@ -107,9 +109,10 @@ static void glue(draw_line4_, DEPTH)( /* * 8-bit colour */ -static void glue(draw_line8_, DEPTH)( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +static void glue(draw_line8_, DEPTH)(void *opaque, + uint8_t *d, const uint8_t *s, int width, int deststep) { + uint16_t *pal = opaque; uint8_t v, r, g, b; do { @@ -126,8 +129,8 @@ static void glue(draw_line8_, DEPTH)( /* * 12-bit colour */ -static void glue(draw_line12_, DEPTH)( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +static void glue(draw_line12_, DEPTH)(void *opaque, + uint8_t *d, const uint8_t *s, int width, int deststep) { uint16_t v; uint8_t r, g, b; @@ -146,8 +149,8 @@ static void glue(draw_line12_, DEPTH)( /* * 16-bit colour */ -static void glue(draw_line16_, DEPTH)( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +static void glue(draw_line16_, DEPTH)(void *opaque, + uint8_t *d, const uint8_t *s, int width, int deststep) { #if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) memcpy(d, s, width * 2); diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index a02d99d27..6a91b27d4 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -20,6 +20,7 @@ #include "hw.h" #include "console.h" #include "omap.h" +#include "framebuffer.h" struct omap_lcd_panel_s { qemu_irq irq; @@ -68,8 +69,7 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) #include "pixel_ops.h" -typedef void draw_line_func( - uint8_t *d, const uint8_t *s, int width, const uint16_t *pal); +#define draw_line_func drawfn #define DEPTH 8 #include "omap_lcd_template.h" @@ -80,31 +80,31 @@ typedef void draw_line_func( #define DEPTH 32 #include "omap_lcd_template.h" -static draw_line_func *draw_line_table2[33] = { +static draw_line_func draw_line_table2[33] = { [0 ... 32] = 0, [8] = draw_line2_8, [15] = draw_line2_15, [16] = draw_line2_16, [32] = draw_line2_32, -}, *draw_line_table4[33] = { +}, draw_line_table4[33] = { [0 ... 32] = 0, [8] = draw_line4_8, [15] = draw_line4_15, [16] = draw_line4_16, [32] = draw_line4_32, -}, *draw_line_table8[33] = { +}, draw_line_table8[33] = { [0 ... 32] = 0, [8] = draw_line8_8, [15] = draw_line8_15, [16] = draw_line8_16, [32] = draw_line8_32, -}, *draw_line_table12[33] = { +}, draw_line_table12[33] = { [0 ... 32] = 0, [8] = draw_line12_8, [15] = draw_line12_15, [16] = draw_line12_16, [32] = draw_line12_32, -}, *draw_line_table16[33] = { +}, draw_line_table16[33] = { [0 ... 32] = 0, [8] = draw_line16_8, [15] = draw_line16_15, @@ -115,11 +115,10 @@ static draw_line_func *draw_line_table2[33] = { static void omap_update_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; - draw_line_func *draw_line; - int size, dirty[2], minline, maxline, height; - int line, width, linesize, step, bpp, frame_offset; - ram_addr_t frame_base, scanline, newline, x; - uint8_t *s, *d; + draw_line_func draw_line; + int size, height, first, last; + int width, linesize, step, bpp, frame_offset; + target_phys_addr_t frame_base; if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state)) @@ -127,9 +126,9 @@ static void omap_update_display(void *opaque) frame_offset = 0; if (omap_lcd->plm != 2) { - memcpy(omap_lcd->palette, phys_ram_base + - omap_lcd->dma->phys_framebuffer[ - omap_lcd->dma->current_frame], 0x200); + cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[ + omap_lcd->dma->current_frame], + (void *)omap_lcd->palette, 0x200); switch (omap_lcd->palette[0] >> 12 & 7) { case 3 ... 7: frame_offset += 0x200; @@ -202,49 +201,28 @@ static void omap_update_display(void *opaque) if (!ds_get_bits_per_pixel(omap_lcd->state)) return; - line = 0; + first = 0; height = omap_lcd->height; if (omap_lcd->subpanel & (1 << 31)) { if (omap_lcd->subpanel & (1 << 29)) - line = (omap_lcd->subpanel >> 16) & 0x3ff; + first = (omap_lcd->subpanel >> 16) & 0x3ff; else height = (omap_lcd->subpanel >> 16) & 0x3ff; /* TODO: fill the rest of the panel with DPD */ } + step = width * bpp >> 3; - scanline = frame_base + step * line; - s = (uint8_t *) (phys_ram_base + scanline); - d = ds_get_data(omap_lcd->state); linesize = ds_get_linesize(omap_lcd->state); - - dirty[0] = dirty[1] = - cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG); - minline = height; - maxline = line; - for (; line < height; line ++) { - newline = scanline + step; - for (x = scanline + TARGET_PAGE_SIZE; x < newline; - x += TARGET_PAGE_SIZE) { - dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); - dirty[0] |= dirty[1]; - } - if (dirty[0] || omap_lcd->invalidate) { - draw_line(d, s, width, omap_lcd->palette); - if (line < minline) - minline = line; - maxline = line + 1; - } - scanline = newline; - dirty[0] = dirty[1]; - s += step; - d += linesize; - } - - if (maxline >= minline) { - dpy_update(omap_lcd->state, 0, minline, width, maxline); - cpu_physical_memory_reset_dirty(frame_base + step * minline, - frame_base + step * maxline, VGA_DIRTY_FLAG); + framebuffer_update_display(omap_lcd->state, + frame_base, width, height, + step, linesize, 0, + omap_lcd->invalidate, + draw_line, omap_lcd->palette, + &first, &last); + if (first >= 0) { + dpy_update(omap_lcd->state, 0, first, width, last - first + 1); } + omap_lcd->invalidate = 0; } static int ppm_save(const char *filename, uint8_t *data, @@ -336,25 +314,13 @@ static void omap_lcd_update(struct omap_lcd_panel_s *s) { return; } - if (s->dma->src == imif) { - /* Framebuffers are in SRAM */ - s->dma->phys_framebuffer[0] = s->imif_base + - s->dma->src_f1_top - OMAP_IMIF_BASE; - - s->dma->phys_framebuffer[1] = s->imif_base + - s->dma->src_f2_top - OMAP_IMIF_BASE; - } else { - /* Framebuffers are in RAM */ - s->dma->phys_framebuffer[0] = s->emiff_base + - s->dma->src_f1_top - OMAP_EMIFF_BASE; - - s->dma->phys_framebuffer[1] = s->emiff_base + - s->dma->src_f2_top - OMAP_EMIFF_BASE; - } + s->dma->phys_framebuffer[0] = s->dma->src_f1_top; + s->dma->phys_framebuffer[1] = s->dma->src_f2_top; if (s->plm != 2 && !s->palette_done) { - memcpy(s->palette, phys_ram_base + - s->dma->phys_framebuffer[s->dma->current_frame], 0x200); + cpu_physical_memory_read( + s->dma->phys_framebuffer[s->dma->current_frame], + (void *)s->palette, 0x200); s->palette_done = 1; omap_lcd_interrupts(s); } diff --git a/hw/pl110.c b/hw/pl110.c index 7ce74a2f6..f21b63b0c 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -10,6 +10,7 @@ #include "hw.h" #include "primecell.h" #include "console.h" +#include "framebuffer.h" #define PL110_CR_EN 0x001 #define PL110_CR_BGR 0x100 @@ -61,8 +62,6 @@ static const unsigned char pl110_versatile_id[] = #include "pixel_ops.h" -typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int); - #define BITS 8 #include "pl110_template.h" #define BITS 15 @@ -84,17 +83,11 @@ static void pl110_update_display(void *opaque) pl110_state *s = (pl110_state *)opaque; drawfn* fntable; drawfn fn; - uint32_t *pallette; - uint32_t addr; - uint32_t base; int dest_width; int src_width; - uint8_t *dest; - uint8_t *src; - int first, last = 0; - int dirty, new_dirty; - int i; int bpp_offset; + int first; + int last; if (!pl110_enabled(s)) return; @@ -159,47 +152,17 @@ static void pl110_update_display(void *opaque) break; } dest_width *= s->cols; - pallette = s->pallette; - base = s->upbase; - /* HACK: Arm aliases physical memory at 0x80000000. */ - if (base > 0x80000000) - base -= 0x80000000; - src = phys_ram_base + base; - dest = ds_get_data(s->ds); - first = -1; - addr = base; - - dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); - new_dirty = dirty; - for (i = 0; i < s->rows; i++) { - if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { - uint32_t tmp; - new_dirty = 0; - for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) { - new_dirty |= cpu_physical_memory_get_dirty(addr + tmp, - VGA_DIRTY_FLAG); - } - } - - if (dirty || new_dirty || s->invalidate) { - fn(pallette, dest, src, s->cols); - if (first == -1) - first = i; - last = i; - } - dirty = new_dirty; - addr += src_width; - dest += dest_width; - src += src_width; + first = 0; + framebuffer_update_display(s->ds, + s->upbase, s->cols, s->rows, + src_width, dest_width, 0, + s->invalidate, + fn, s->pallette, + &first, &last); + if (first >= 0) { + dpy_update(s->ds, 0, first, s->cols, last - first + 1); } - if (first < 0) - return; - s->invalidate = 0; - cpu_physical_memory_reset_dirty(base + first * src_width, - base + (last + 1) * src_width, - VGA_DIRTY_FLAG); - dpy_update(s->ds, 0, first, s->cols, last - first + 1); } static void pl110_invalidate_display(void * opaque) diff --git a/hw/pl110_template.h b/hw/pl110_template.h index 33483c027..5b5f47560 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -115,8 +115,9 @@ static drawfn glue(pl110_draw_fn_,BITS)[36] = #define FN_4(x, y) FN_2(x, y) FN_2(x+2, y) #define FN_8(y) FN_4(0, y) FN_4(4, y) -static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { + uint32_t *pallette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; @@ -142,8 +143,9 @@ static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const u } } -static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { + uint32_t *pallette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; @@ -169,8 +171,9 @@ static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const u } } -static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { + uint32_t *pallette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; @@ -196,8 +199,9 @@ static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const u } } -static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { + uint32_t *pallette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; @@ -219,7 +223,7 @@ static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const u } } -static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { uint32_t data; unsigned int r, g, b; @@ -265,7 +269,7 @@ static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const } } -static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { uint32_t data; unsigned int r, g, b; diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 5c2eff10e..49eafa722 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -13,8 +13,7 @@ #include "pixel_ops.h" /* FIXME: For graphic_rotate. Should probably be done in common code. */ #include "sysemu.h" - -typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); +#include "framebuffer.h" struct pxa2xx_lcdc_s { qemu_irq irq; @@ -56,7 +55,7 @@ struct pxa2xx_lcdc_s { int up; uint8_t palette[1024]; uint8_t pbuffer[1024]; - void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb, + void (*redraw)(struct pxa2xx_lcdc_s *s, target_phys_addr_t addr, int *miny, int *maxy); target_phys_addr_t descriptor; @@ -669,18 +668,15 @@ static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp) } static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, - uint8_t *fb, int *miny, int *maxy) + target_phys_addr_t addr, int *miny, int *maxy) { - int y, src_width, dest_width, dirty[2]; - uint8_t *src, *dest; - ram_addr_t x, addr, new_addr, start, end; + int src_width, dest_width; drawfn fn = 0; if (s->dest_width) fn = s->line_fn[s->transp][s->bpp]; if (!fn) return; - src = fb; src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) src_width *= 3; @@ -689,54 +685,25 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, else if (s->bpp > pxa_lcdc_8bpp) src_width *= 2; - dest = ds_get_data(s->ds); dest_width = s->xres * s->dest_width; - - addr = (ram_addr_t) (fb - phys_ram_base); - start = addr + s->yres * src_width; - end = addr; - dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); - for (y = 0; y < s->yres; y ++) { - new_addr = addr + src_width; - for (x = addr + TARGET_PAGE_SIZE; x < new_addr; - x += TARGET_PAGE_SIZE) { - dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); - dirty[0] |= dirty[1]; - } - if (dirty[0] || s->invalidated) { - fn((uint32_t *) s->dma_ch[0].palette, - dest, src, s->xres, s->dest_width); - if (addr < start) - start = addr; - end = new_addr; - if (y < *miny) - *miny = y; - if (y >= *maxy) - *maxy = y + 1; - } - addr = new_addr; - dirty[0] = dirty[1]; - src += src_width; - dest += dest_width; - } - - if (end > start) - cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); + *miny = 0; + framebuffer_update_display(s->ds, + addr, s->xres, s->yres, + src_width, dest_width, s->dest_width, + s->invalidated, + fn, s->dma_ch[0].palette, miny, maxy); } static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, - uint8_t *fb, int *miny, int *maxy) + target_phys_addr_t addr, int *miny, int *maxy) { - int y, src_width, dest_width, dirty[2]; - uint8_t *src, *dest; - ram_addr_t x, addr, new_addr, start, end; + int src_width, dest_width; drawfn fn = 0; if (s->dest_width) fn = s->line_fn[s->transp][s->bpp]; if (!fn) return; - src = fb; src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) src_width *= 3; @@ -746,38 +713,13 @@ static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, src_width *= 2; dest_width = s->yres * s->dest_width; - dest = ds_get_data(s->ds) + dest_width * (s->xres - 1); - - addr = (ram_addr_t) (fb - phys_ram_base); - start = addr + s->yres * src_width; - end = addr; - x = addr + TARGET_PAGE_SIZE; - dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); - for (y = 0; y < s->yres; y ++) { - new_addr = addr + src_width; - for (; x < new_addr; x += TARGET_PAGE_SIZE) { - dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); - dirty[0] |= dirty[1]; - } - if (dirty[0] || s->invalidated) { - fn((uint32_t *) s->dma_ch[0].palette, - dest, src, s->xres, -dest_width); - if (addr < start) - start = addr; - end = new_addr; - if (y < *miny) - *miny = y; - if (y >= *maxy) - *maxy = y + 1; - } - addr = new_addr; - dirty[0] = dirty[1]; - src += src_width; - dest += s->dest_width; - } - - if (end > start) - cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); + *miny = 0; + framebuffer_update_display(s->ds, + addr, s->xres, s->yres, + src_width, s->dest_width, -dest_width, + s->invalidated, + fn, s->dma_ch[0].palette, + miny, maxy); } static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s) @@ -803,7 +745,6 @@ static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s) static void pxa2xx_update_display(void *opaque) { struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; - uint8_t *fb; target_phys_addr_t fbptr; int miny, maxy; int ch; @@ -829,13 +770,11 @@ static void pxa2xx_update_display(void *opaque) pxa2xx_dma_ber_set(s, ch); continue; } - fbptr -= PXA2XX_SDRAM_BASE; - fb = phys_ram_base + fbptr; if (s->dma_ch[ch].command & LDCMD_PAL) { - memcpy(s->dma_ch[ch].pbuffer, fb, - MAX(LDCMD_LENGTH(s->dma_ch[ch].command), - sizeof(s->dma_ch[ch].pbuffer))); + cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer, + MAX(LDCMD_LENGTH(s->dma_ch[ch].command), + sizeof(s->dma_ch[ch].pbuffer))); pxa2xx_palette_parse(s, ch, s->bpp); } else { /* Do we need to reparse palette */ @@ -845,7 +784,7 @@ static void pxa2xx_update_display(void *opaque) /* ACK frame start */ pxa2xx_dma_sof_set(s, ch); - s->dma_ch[ch].redraw(s, fb, &miny, &maxy); + s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy); s->invalidated = 0; /* ACK frame completed */ @@ -859,10 +798,12 @@ static void pxa2xx_update_display(void *opaque) s->status[0] |= LCSR0_LDD; } - if (s->orientation) - dpy_update(s->ds, miny, 0, maxy, s->xres); - else - dpy_update(s->ds, 0, miny, s->xres, maxy); + if (miny >= 0) { + if (s->orientation) + dpy_update(s->ds, miny, 0, maxy, s->xres); + else + dpy_update(s->ds, 0, miny, s->xres, maxy); + } pxa2xx_lcdc_int_update(s); qemu_irq_raise(s->vsync_cb); diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h index 903df7b38..35312ec29 100644 --- a/hw/pxa2xx_template.h +++ b/hw/pxa2xx_template.h @@ -30,9 +30,10 @@ #define FN_2(x) FN(x + 1) FN(x) #define FN_4(x) FN_2(x + 2) FN_2(x) -static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line2_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *) src; @@ -54,9 +55,10 @@ static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line4_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *) src; @@ -78,9 +80,10 @@ static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line8_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *) src; @@ -102,7 +105,7 @@ static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line16_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -130,7 +133,7 @@ static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -166,7 +169,7 @@ static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line18_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -188,7 +191,7 @@ static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette, } /* The wicked packed format */ -static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data[3]; @@ -236,7 +239,7 @@ static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line19_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -262,7 +265,7 @@ static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette, } /* The wicked packed format */ -static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data[3]; @@ -326,7 +329,7 @@ static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line24_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -347,7 +350,7 @@ static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; @@ -372,7 +375,7 @@ static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette, } } -static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette, +static void glue(pxa2xx_draw_line25_, BITS)(void *opaque, uint8_t *dest, const uint8_t *src, int width, int deststep) { uint32_t data; -- cgit v1.2.3 From 852d481faf7070ac6e46653b77f6c9ecbdfb9efc Mon Sep 17 00:00:00 2001 From: edgar_igl Date: Wed, 1 Apr 2009 23:10:46 +0000 Subject: SH: Improve movca.l/ocbi emulation. Author: Vladimir Prus Fix movcal.l/ocbi emulation. * target-sh4/cpu.h (memory_content): New. (CPUSH4State): New fields movcal_backup and movcal_backup_tail. * target-sh4/helper.h (helper_movcal) (helper_discard_movcal_backup, helper_ocbi): New. * target-sh4/op_helper.c (helper_movcal) (helper_discard_movcal_backup, helper_ocbi): New. * target-sh4/translate.c (DisasContext): New field has_movcal. (sh4_defs): Update CVS for SH7785. (cpu_sh4_init): Initialize env->movcal_backup_tail. (_decode_opc): Discard movca.l-backup. Make use of helper_movcal and helper_ocbi. (gen_intermediate_code_internal): Initialize has_movcal to 1. Thanks to Shin-ichiro KAWASAKI and Paul Mundt for valuable feedback. Acked-by: Edgar E. Iglesias git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6966 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/cpu.h | 15 ++++++++++++++- target-sh4/helper.c | 44 ++++++++++++++++++++++++++++++++++++++++++ target-sh4/helper.h | 4 ++++ target-sh4/op_helper.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-sh4/translate.c | 46 ++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 156 insertions(+), 5 deletions(-) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index aea7108fc..e597f653a 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -100,6 +100,12 @@ enum sh_features { SH_FEATURE_BCR3_AND_BCR4 = 2, }; +typedef struct memory_content { + uint32_t address; + uint32_t value; + struct memory_content *next; +} memory_content; + typedef struct CPUSH4State { int id; /* CPU model */ @@ -148,6 +154,8 @@ typedef struct CPUSH4State { tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ void *intc_handle; int intr_at_halt; /* SR_BL ignored during sleep */ + memory_content *movcal_backup; + memory_content **movcal_backup_tail; } CPUSH4State; CPUSH4State *cpu_sh4_init(const char *cpu_model); @@ -162,6 +170,8 @@ void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value); +int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr); + static inline void cpu_set_tls(CPUSH4State *env, target_ulong newtls) { env->gbr = newtls; @@ -293,6 +303,8 @@ static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) env->flags = tb->flags; } +#define TB_FLAG_PENDING_MOVCA (1 << 4) + static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -302,7 +314,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */ | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ | (env->sr & (SR_MD | SR_RB)) /* Bits 29-30 */ - | (env->sr & SR_FD); /* Bit 15 */ + | (env->sr & SR_FD) /* Bit 15 */ + | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */ } #endif /* _CPU_SH4_H */ diff --git a/target-sh4/helper.c b/target-sh4/helper.c index c50608661..d2e9b3b89 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -644,4 +644,48 @@ void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, } } +int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) +{ + int n; + int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; + + /* check area */ + if (env->sr & SR_MD) { + /* For previledged mode, P2 and P4 area is not cachable. */ + if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr) + return 0; + } else { + /* For user mode, only U0 area is cachable. */ + if (0x80000000 <= addr) + return 0; + } + + /* + * TODO : Evaluate CCR and check if the cache is on or off. + * Now CCR is not in CPUSH4State, but in SH7750State. + * When you move the ccr inot CPUSH4State, the code will be + * as follows. + */ +#if 0 + /* check if operand cache is enabled or not. */ + if (!(env->ccr & 1)) + return 0; +#endif + + /* if MMU is off, no check for TLB. */ + if (env->mmucr & MMUCR_AT) + return 1; + + /* check TLB */ + n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid); + if (n >= 0) + return env->itlb[n].c; + + n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid); + if (n >= 0) + return env->utlb[n].c; + + return 0; +} + #endif diff --git a/target-sh4/helper.h b/target-sh4/helper.h index e66518558..4b2fcdd53 100644 --- a/target-sh4/helper.h +++ b/target-sh4/helper.h @@ -9,6 +9,10 @@ DEF_HELPER_0(debug, void) DEF_HELPER_1(sleep, void, i32) DEF_HELPER_1(trapa, void, i32) +DEF_HELPER_2(movcal, void, i32, i32) +DEF_HELPER_0(discard_movcal_backup, void) +DEF_HELPER_1(ocbi, void, i32) + DEF_HELPER_2(addv, i32, i32, i32) DEF_HELPER_2(addc, i32, i32, i32) DEF_HELPER_2(subv, i32, i32, i32) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 84e1ad331..616b4f9a4 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA */ #include +#include #include "exec.h" #include "helper.h" @@ -122,6 +123,57 @@ void helper_trapa(uint32_t tra) cpu_loop_exit(); } +void helper_movcal(uint32_t address, uint32_t value) +{ + if (cpu_sh4_is_cached (env, address)) + { + memory_content *r = malloc (sizeof(memory_content)); + r->address = address; + r->value = value; + r->next = NULL; + + *(env->movcal_backup_tail) = r; + env->movcal_backup_tail = &(r->next); + } +} + +void helper_discard_movcal_backup(void) +{ + memory_content *current = env->movcal_backup; + + while(current) + { + memory_content *next = current->next; + free (current); + env->movcal_backup = current = next; + if (current == 0) + env->movcal_backup_tail = &(env->movcal_backup); + } +} + +void helper_ocbi(uint32_t address) +{ + memory_content **current = &(env->movcal_backup); + while (*current) + { + uint32_t a = (*current)->address; + if ((a & ~0x1F) == (address & ~0x1F)) + { + memory_content *next = (*current)->next; + stl(a, (*current)->value); + + if (next == 0) + { + env->movcal_backup_tail = current; + } + + free (*current); + *current = next; + break; + } + } +} + uint32_t helper_addc(uint32_t arg0, uint32_t arg1) { uint32_t tmp0, tmp1; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index cc9f88681..4ced176b3 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -50,6 +50,7 @@ typedef struct DisasContext { uint32_t delayed_pc; int singlestep_enabled; uint32_t features; + int has_movcal; } DisasContext; #if defined(CONFIG_USER_ONLY) @@ -283,6 +284,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model) env = qemu_mallocz(sizeof(CPUSH4State)); env->features = def->features; cpu_exec_init(env); + env->movcal_backup_tail = &(env->movcal_backup); sh4_translate_init(); env->cpu_model_str = cpu_model; cpu_sh4_reset(env); @@ -495,6 +497,37 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) static void _decode_opc(DisasContext * ctx) { + /* This code tries to make movcal emulation sufficiently + accurate for Linux purposes. This instruction writes + memory, and prior to that, always allocates a cache line. + It is used in two contexts: + - in memcpy, where data is copied in blocks, the first write + of to a block uses movca.l for performance. + - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used + to flush the cache. Here, the data written by movcal.l is never + written to memory, and the data written is just bogus. + + To simulate this, we simulate movcal.l, we store the value to memory, + but we also remember the previous content. If we see ocbi, we check + if movcal.l for that address was done previously. If so, the write should + not have hit the memory, so we restore the previous content. + When we see an instruction that is neither movca.l + nor ocbi, the previous content is discarded. + + To optimize, we only try to flush stores when we're at the start of + TB, or if we already saw movca.l in this TB and did not flush stores + yet. */ + if (ctx->has_movcal) + { + int opcode = ctx->opcode & 0xf0ff; + if (opcode != 0x0093 /* ocbi */ + && opcode != 0x00c3 /* movca.l */) + { + gen_helper_discard_movcal_backup (); + ctx->has_movcal = 0; + } + } + #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); #endif @@ -1545,7 +1578,13 @@ static void _decode_opc(DisasContext * ctx) } return; case 0x00c3: /* movca.l R0,@Rm */ - tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + { + TCGv val = tcg_temp_new(); + tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx); + gen_helper_movcal (REG(B11_8), val); + tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + } + ctx->has_movcal = 1; return; case 0x40a9: /* MOVUA.L @Rm,R0 (Rm) -> R0 @@ -1594,9 +1633,7 @@ static void _decode_opc(DisasContext * ctx) break; case 0x0093: /* ocbi @Rn */ { - TCGv dummy = tcg_temp_new(); - tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); - tcg_temp_free(dummy); + gen_helper_ocbi (REG(B11_8)); } return; case 0x00a3: /* ocbp @Rn */ @@ -1876,6 +1913,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; ctx.features = env->features; + ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA); #ifdef DEBUG_DISAS qemu_log_mask(CPU_LOG_TB_CPU, -- cgit v1.2.3 From d19076faca944c31bb051b95d285e75ec67902f7 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 2 Apr 2009 01:16:39 +0000 Subject: Temporary workaround for ppc on ppc target-ppc/translate.c puts values of type opcode_t into .opcodes section, using GCC extension to do so, and hoping that this will make them appear contiguously and in the source order in the resulting executable. This assumption is not safe and is known to be violated with certain versions of GCC, certain flags passed to it and on certain platforms (gcc 4.3.0, -O and PPC/PPC64 for instance) The workaround consists of adding -fno-unit-at-a-time to the list of GCC command line options while building PPC translate.o on a PPC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6967 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile.target b/Makefile.target index 046427d4f..e855dc33b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -84,6 +84,10 @@ ifeq ($(ARCH),i386) HELPER_CFLAGS+=-fomit-frame-pointer endif +ifeq ($(subst ppc64,ppc,$(ARCH))$(TARGET_BASE_ARCH),ppcppc) +translate.o: CFLAGS := $(CFLAGS) $(call cc-option, $(CFLAGS), -fno-unit-at-a-time,) +endif + ifeq ($(ARCH),sparc) CFLAGS+=-ffixed-g2 -ffixed-g3 ifneq ($(CONFIG_SOLARIS),yes) -- cgit v1.2.3 From 8cd6345d00a25ffa8828bce31154c88f76fb7fc6 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 2 Apr 2009 22:54:35 +0000 Subject: Immediate versions of ro[lr] git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6968 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 04ef295ce..cd2e3263e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1551,7 +1551,6 @@ static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2) tcg_gen_shri_tl(ret, arg1, -arg2); } -/* XXX: add faster immediate case */ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, int is_right) { @@ -1648,6 +1647,83 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, tcg_temp_free(a0); } +static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, + int is_right) +{ + int mask; + int data_bits; + TCGv t0, t1, a0; + + /* XXX: inefficient, but we must use local temps */ + t0 = tcg_temp_local_new(); + t1 = tcg_temp_local_new(); + a0 = tcg_temp_local_new(); + + if (ot == OT_QUAD) + mask = 0x3f; + else + mask = 0x1f; + + /* load */ + if (op1 == OR_TMP0) { + tcg_gen_mov_tl(a0, cpu_A0); + gen_op_ld_v(ot + s->mem_index, t0, a0); + } else { + gen_op_mov_v_reg(ot, t0, op1); + } + + gen_extu(ot, t0); + tcg_gen_mov_tl(t1, t0); + + op2 &= mask; + data_bits = 8 << ot; + if (op2 != 0) { + int shift = op2 & ((1 << (3 + ot)) - 1); + if (is_right) { + tcg_gen_shri_tl(cpu_tmp4, t0, shift); + tcg_gen_shli_tl(t0, t0, data_bits - shift); + } + else { + tcg_gen_shli_tl(cpu_tmp4, t0, shift); + tcg_gen_shri_tl(t0, t0, data_bits - shift); + } + tcg_gen_or_tl(t0, t0, cpu_tmp4); + } + + /* store */ + if (op1 == OR_TMP0) { + gen_op_st_v(ot + s->mem_index, t0, a0); + } else { + gen_op_mov_reg_v(ot, op1, t0); + } + + if (op2 != 0) { + /* update eflags */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + gen_compute_eflags(cpu_cc_src); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); + tcg_gen_xor_tl(cpu_tmp0, t1, t0); + tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + if (is_right) { + tcg_gen_shri_tl(t0, t0, data_bits - 1); + } + tcg_gen_andi_tl(t0, t0, CC_C); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); + + tcg_gen_discard_tl(cpu_cc_dst); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); + s->cc_op = CC_OP_EFLAGS; + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(a0); +} + /* XXX: add faster immediate = 1 case */ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, int is_right) @@ -1862,6 +1938,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) { switch(op) { + case OP_ROL: + gen_rot_rm_im(s1, ot, d, c, 0); + break; + case OP_ROR: + gen_rot_rm_im(s1, ot, d, c, 1); + break; case OP_SHL: case OP_SHL1: gen_shift_rm_im(s1, ot, d, c, 0, 0); -- cgit v1.2.3 From 3c1adf12350b65197d70c4d2911be4d7440d0cfc Mon Sep 17 00:00:00 2001 From: edgar_igl Date: Fri, 3 Apr 2009 07:29:38 +0000 Subject: SH: Add cpu_sh4_is_cached for linux-user. The entire U0 area is assumed to be cacheable. Signed-off-by: Edgar E. Iglesias git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6969 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index d2e9b3b89..178bfae99 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -60,6 +60,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) return addr; } +int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) +{ + /* For user mode, only U0 area is cachable. */ + return !!(addr & 0x80000000); +} + #else /* !CONFIG_USER_ONLY */ #define MMU_OK 0 -- cgit v1.2.3 From 679dee3c6ca84c9111087808d3bfeb768d402566 Mon Sep 17 00:00:00 2001 From: edgar_igl Date: Fri, 3 Apr 2009 07:33:24 +0000 Subject: SH: Fix linux-user _is_cached typo. Signed-off-by: Edgar E. Iglesias git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6970 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 178bfae99..d8e08e305 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -63,7 +63,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) { /* For user mode, only U0 area is cachable. */ - return !!(addr & 0x80000000); + return !(addr & 0x80000000); } #else /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From 9ddff3d2c44ceeba8dcbb5294183404ce73448c2 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Apr 2009 07:41:20 +0000 Subject: Make i386-softmmu boot on Sparc host git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6971 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index cf7c1fba7..0ce3f988e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -253,6 +253,11 @@ int cpu_exec(CPUState *env1) /* prepare setjmp context for exception handling */ for(;;) { if (setjmp(env->jmp_env) == 0) { +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif env->current_tb = NULL; /* if an exception is pending, we execute it here */ if (env->exception_index >= 0) { @@ -390,6 +395,11 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); intno = cpu_get_pic_interrupt(env); qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#undef env + env = cpu_single_env; +#define env cpu_single_env +#endif do_interrupt(intno, 0, 0, 0, 1); /* ensure that no TB jump will be modified as the program flow was changed */ -- cgit v1.2.3 From 762e823086ad37453c2308bccf01223f07759eab Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Apr 2009 09:21:28 +0000 Subject: Compile all files with -ffixed-g5 etc. to avoid env (%g5) corruption git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6972 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 10 ---------- configure | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Makefile.target b/Makefile.target index e855dc33b..535d6d2e3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -89,21 +89,11 @@ translate.o: CFLAGS := $(CFLAGS) $(call cc-option, $(CFLAGS), -fno-unit-at-a-tim endif ifeq ($(ARCH),sparc) - CFLAGS+=-ffixed-g2 -ffixed-g3 ifneq ($(CONFIG_SOLARIS),yes) - CFLAGS+=-ffixed-g1 -ffixed-g6 HELPER_CFLAGS+=-ffixed-i0 endif endif -ifeq ($(ARCH),sparc64) - ifneq ($(CONFIG_SOLARIS),yes) - CFLAGS+=-ffixed-g5 -ffixed-g6 -ffixed-g7 - else - CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 - endif -endif - ifeq ($(ARCH),alpha) # Ensure there's only a single GP CFLAGS+=-msmall-data diff --git a/configure b/configure index 5c62c594e..fa779379f 100755 --- a/configure +++ b/configure @@ -498,6 +498,10 @@ case "$cpu" in ARCH_CFLAGS="${SP_CFLAGS}" ARCH_LDFLAGS="${SP_LDFLAGS}" fi + ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g2 -ffixed-g3" + if test "$solaris" = "no" ; then + ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g1 -ffixed-g6" + fi ;; sparc64) if test -z "$sparc_cpu" ; then ARCH_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__" @@ -506,6 +510,11 @@ case "$cpu" in ARCH_CFLAGS="${SP_CFLAGS}" ARCH_LDFLAGS="${SP_LDFLAGS}" fi + if test "$solaris" = "no" ; then + ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g5 -ffixed-g6 -ffixed-g7" + else + ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g1 -ffixed-g5 -ffixed-g6 -ffixed-g7" + fi ;; s390) ARCH_CFLAGS="-march=z900" -- cgit v1.2.3 From f843e5282a67aeaafd6309e9ce6b633e13e6744c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Apr 2009 15:33:03 +0000 Subject: Allocate space for static call args, increase stack frame size on Sparc64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6973 c046a42c-6fe2-441c-8c8c-71466251a162 --- tcg/sparc/tcg-target.c | 18 ++++++++++++------ tcg/sparc/tcg-target.h | 8 +++++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 2c571a782..ea08aa762 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -578,9 +578,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, global registers */ // delay slot tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); /* data_reg = sign_extend(arg0) */ switch(opc) { @@ -781,9 +783,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, global registers */ // delay slot tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); /* will become: ba label2 */ @@ -905,9 +909,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, global registers */ // delay slot tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_ST_OP); tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, - TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP); + TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - + sizeof(long), HOST_LD_OP); break; case INDEX_op_jmp: case INDEX_op_br: diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 43ec8180f..97f353305 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -75,12 +75,14 @@ enum { #define TCG_REG_CALL_STACK TCG_REG_I6 #ifdef __arch64__ // Reserve space for AREG0 -#define TCG_TARGET_STACK_MINFRAME (176 + 2 * (int)sizeof(long)) -#define TCG_TARGET_CALL_STACK_OFFSET (2047 + TCG_TARGET_STACK_MINFRAME) +#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16) #define TCG_TARGET_STACK_ALIGN 16 #else // AREG0 + one word for alignment -#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long)) +#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) #define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME #define TCG_TARGET_STACK_ALIGN 8 #endif -- cgit v1.2.3 From 1da92db280961b3949712609b8771f582dab1f4a Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Apr 2009 19:10:26 +0000 Subject: Fix branches and TLB matches for 64 bit targets git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6974 c046a42c-6fe2-441c-8c8c-71466251a162 --- tcg/sparc/tcg-target.c | 88 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index ea08aa762..23cd9cdbe 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -117,6 +117,13 @@ static void patch_reloc(uint8_t *code_ptr, int type, tcg_abort(); *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value; break; + case R_SPARC_WDISP19: + value -= (long)code_ptr; + value >>= 2; + if (!check_fit_tl(value, 19)) + tcg_abort(); + *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value; + break; default: tcg_abort(); } @@ -185,6 +192,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define INSN_ASI(x) ((x) << 5) #define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff)) +#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff) #define INSN_OFF22(x) (((x) >> 2) & 0x3fffff) #define INSN_COND(x, a) (((x) << 25) | ((a) << 29)) @@ -421,7 +429,7 @@ static inline void tcg_out_nop(TCGContext *s) tcg_out_sethi(s, TCG_REG_G0, 0); } -static void tcg_out_branch(TCGContext *s, int opc, int label_index) +static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index) { int32_t val; TCGLabel *l = &s->labels[label_index]; @@ -436,6 +444,25 @@ static void tcg_out_branch(TCGContext *s, int opc, int label_index) } } +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) +{ + int32_t val; + TCGLabel *l = &s->labels[label_index]; + + if (l->has_value) { + val = l->u.value - (tcg_target_long)s->code_ptr; + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | + INSN_OFF19(l->u.value - (unsigned long)s->code_ptr))); + } else { + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0); + tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | + (0x5 << 19) | 0)); + } +} +#endif + static const uint8_t tcg_cond_to_bcond[10] = { [TCG_COND_EQ] = COND_E, [TCG_COND_NE] = COND_NE, @@ -449,9 +476,9 @@ static const uint8_t tcg_cond_to_bcond[10] = { [TCG_COND_GTU] = COND_GU, }; -static void tcg_out_brcond(TCGContext *s, int cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - int label_index) +static void tcg_out_brcond_i32(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) { if (const_arg2 && arg2 == 0) /* orcc %g0, r, %g0 */ @@ -459,10 +486,26 @@ static void tcg_out_brcond(TCGContext *s, int cond, else /* subcc r1, r2, %g0 */ tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC); - tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index); tcg_out_nop(s); } +#if defined(__sparc_v9__) && !defined(__sparc_v8plus__) +static void tcg_out_brcond_i64(TCGContext *s, int cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +{ + if (const_arg2 && arg2 == 0) + /* orcc %g0, r, %g0 */ + tcg_out_arith(s, TCG_REG_G0, TCG_REG_G0, arg1, ARITH_ORCC); + else + /* subcc r1, r2, %g0 */ + tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC); + tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index); + tcg_out_nop(s); +} +#endif + /* Generate global QEMU prologue and epilogue code */ void tcg_target_qemu_prologue(TCGContext *s) { @@ -559,7 +602,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); /* will become: - be label1 */ + be label1 + or + be,pt %xcc label1 */ label1_ptr = (uint32_t *)s->code_ptr; tcg_out32(s, 0); @@ -627,9 +672,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_nop(s); /* label1: */ +#if TARGET_LONG_BITS == 32 + /* be label1 */ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | INSN_OFF22((unsigned long)s->code_ptr - (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif /* ld [arg1 + x], arg1 */ tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - @@ -761,7 +814,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); /* will become: - be label1 */ + be label1 + or + be,pt %xcc label1 */ label1_ptr = (uint32_t *)s->code_ptr; tcg_out32(s, 0); @@ -797,10 +852,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, /* nop (delay slot) */ tcg_out_nop(s); - /* label1: */ +#if TARGET_LONG_BITS == 32 + /* be label1 */ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | INSN_OFF22((unsigned long)s->code_ptr - (unsigned long)label1_ptr)); +#else + /* be,pt %xcc label1 */ + *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | + (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label1_ptr)); +#endif /* ld [arg1 + x], arg1 */ tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - @@ -917,7 +979,7 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, break; case INDEX_op_jmp: case INDEX_op_br: - tcg_out_branch(s, COND_A, args[0]); + tcg_out_branch_i32(s, COND_A, args[0]); tcg_out_nop(s); break; case INDEX_op_movi_i32: @@ -1009,8 +1071,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, #endif case INDEX_op_brcond_i32: - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], - args[3]); + tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1], + args[3]); break; case INDEX_op_qemu_ld8u: @@ -1074,8 +1136,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, goto gen_arith32; case INDEX_op_brcond_i64: - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], - args[3]); + tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1], + args[3]); break; case INDEX_op_qemu_ld64: tcg_out_qemu_ld(s, args, 3); -- cgit v1.2.3 From 8eca6b1bc770982595db2f7207c65051572436cb Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:08 +0000 Subject: Fix oops on 2.6.25 guest (Rusty Russell) I believe this is behind the following: https://bugs.edge.launchpad.net/ubuntu/jaunty/+source/linux/+bug/331128 virtio_pci in 2.6.25 didn't do feature negotiation correctly: it acked every bit. Fortunately, we can detect this. Signed-off-by: Rusty Russell Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6975 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/virtio-net.c | 16 ++++++++++++++++ hw/virtio.c | 9 ++++++++- hw/virtio.h | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index ad55bb761..ae9b7d92c 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -113,6 +113,21 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) return features; } +static uint32_t virtio_net_bad_features(VirtIODevice *vdev) +{ + uint32_t features = 0; + + /* Linux kernel 2.6.25. It understood MAC (as everyone must), + * but also these: */ + features |= (1 << VIRTIO_NET_F_MAC); + features |= (1 << VIRTIO_NET_F_GUEST_CSUM); + features |= (1 << VIRTIO_NET_F_GUEST_TSO4); + features |= (1 << VIRTIO_NET_F_GUEST_TSO6); + features |= (1 << VIRTIO_NET_F_GUEST_ECN); + + return features & virtio_net_get_features(vdev); +} + static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); @@ -580,6 +595,7 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) n->vdev.set_config = virtio_net_set_config; n->vdev.get_features = virtio_net_get_features; n->vdev.set_features = virtio_net_set_features; + n->vdev.bad_features = virtio_net_bad_features; n->vdev.reset = virtio_net_reset; n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); diff --git a/hw/virtio.c b/hw/virtio.c index 8a72d8d21..93a7de689 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -451,6 +451,13 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) switch (addr) { case VIRTIO_PCI_GUEST_FEATURES: + /* Guest does not negotiate properly? We have to assume nothing. */ + if (val & (1 << VIRTIO_F_BAD_FEATURE)) { + if (vdev->bad_features) + val = vdev->bad_features(vdev); + else + val = 0; + } if (vdev->set_features) vdev->set_features(vdev, val); vdev->features = val; @@ -490,7 +497,7 @@ static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) switch (addr) { case VIRTIO_PCI_HOST_FEATURES: ret = vdev->get_features(vdev); - ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); + ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE); break; case VIRTIO_PCI_GUEST_FEATURES: ret = vdev->features; diff --git a/hw/virtio.h b/hw/virtio.h index 18c7a1a7c..cce8a4747 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -32,6 +32,8 @@ /* We notify when the ring is completely used, even if the guest is supressing * callbacks */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 +/* A guest should never accept this. It implies negotiation is broken. */ +#define VIRTIO_F_BAD_FEATURE 30 /* from Linux's linux/virtio_ring.h */ @@ -82,6 +84,7 @@ struct VirtIODevice size_t config_len; void *config; uint32_t (*get_features)(VirtIODevice *vdev); + uint32_t (*bad_features)(VirtIODevice *vdev); void (*set_features)(VirtIODevice *vdev, uint32_t val); void (*get_config)(VirtIODevice *vdev, uint8_t *config); void (*set_config)(VirtIODevice *vdev, const uint8_t *config); -- cgit v1.2.3 From e68b98dc7237d76fdef5c5d403d0613b443102da Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:34 +0000 Subject: Document QEMU coding style (v2) (Avi Kivity) With the help of some Limoncino I noted several aspects of the QEMU coding style, particularly where it differs from the Linux coding style as many contributors work on both projects. Signed-off-by: Avi Kivity Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6976 c046a42c-6fe2-441c-8c8c-71466251a162 --- CODING_STYLE | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 CODING_STYLE diff --git a/CODING_STYLE b/CODING_STYLE new file mode 100644 index 000000000..1ab13b686 --- /dev/null +++ b/CODING_STYLE @@ -0,0 +1,78 @@ +Qemu Coding Style +================= + +1. Whitespace + +Of course, the most important aspect in any coding style is whitespace. +Crusty old coders who have trouble spotting the glasses on their noses +can tell the difference between a tab and eight spaces from a distance +of approximately fifteen parsecs. Many a flamewar have been fought and +lost on this issue. + +QEMU indents are four spaces. Tabs are never used, except in Makefiles +where they have been irreversibly coded into the syntax by some moron. +Spaces of course are superior to tabs because: + + - You have just one way to specify whitespace, not two. Ambiguity breeds + mistakes. + - The confusion surrounding 'use tabs to indent, spaces to justify' is gone. + - Tab indents push your code to the right, making your screen seriously + unbalanced. + - Tabs will be rendered incorrectly on editors who are misconfigured not + to use tab stops of eight positions. + - Tabs are rendered badly in patches, causing off-by-one errors in almost + every line. + - It is the QEMU coding style. + +Do not leave whitespace dangling off the ends of lines. + +2. Line width + +Lines are 80 characters; not longer. + +Rationale: + - Some people like to tile their 24" screens with a 6x4 matrix of 80x24 + xterms and use vi in all of them. The best way to punish them is to + let them keep doing it. + - Code and especially patches is much more readable if limited to a sane + line length. Eighty is traditional. + - It is the QEMU coding style. + +3. Naming + +Variables are lower_case_with_underscores; easy to type and read. Structured +type names are in CamelCase; harder to type but standing out. Scalar type +names are lower_case_with_underscores_ending_with_a_t, like the POSIX +uint64_t and family. Note that this last convention contradicts POSIX +and is therefore likely to be changed. + +Typedefs are used to eliminate the redundant 'struct' keyword. It is the +QEMU coding style. + +4. Block structure + +Every indented statement is braced; even if the block contains just one +statement. The opening brace is on the line that contains the control +flow statement that introduces the new block; the closing brace is on the +same line as the else keyword, or on a line by itself if there is no else +keyword. Example: + + if (a == 5) { + printf("a was 5.\n"); + } else if (a == 6) { + printf("a was 6.\n"); + } else { + printf("a was something else entirely.\n"); + } + +An exception is the opening brace for a function; for reasons of tradition +and clarity it comes on a line by itself: + + void a_function(void) + { + do_something(); + } + +Rationale: a consistent (except for functions...) bracing style reduces +ambiguity and avoids needless churn when lines are added or removed. +Furthermore, it is the QEMU coding style. -- cgit v1.2.3 From f8de16605cf9864e258d91e95be0ed76bdeac744 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:38 +0000 Subject: Fix (at least one cause of) qcow2 corruption. (Nolan Leake) qcow2's get_cluster_offset() scans forward in the l2 table to find other clusters that have the same allocation status as the first cluster. This is used by (among others) qcow_is_allocated(). Unfortunately, it was not checking to be sure that it didn't fall off the end of the l2 table. This patch adds that check. The symptom that motivated me to look into this was that bdrv_is_allocated() was returning false when there was in fact data there. This is one of many ways this bug could lead to data corruption. I checked the other place that scans for consecutive unallocated blocks (alloc_cluster_offset()) and it appears to be OK: nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); appears to prevent the same problem from occurring. Signed-off-by: Nolan Leake sigbus.net> Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6977 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block-qcow2.c b/block-qcow2.c index 60d87a4b8..0e507ca48 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -761,6 +761,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, nb_available = (nb_available >> 9) + index_in_cluster; + if (nb_needed > nb_available) { + nb_needed = nb_available; + } + cluster_offset = 0; /* seek the the l2 offset in the l1 table */ -- cgit v1.2.3 From 93c65b47a6fb9ba0e2b89269a751ba3433a33427 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:43 +0000 Subject: Add host_device support to qemu-img. (Nolan Leake) This patch allows the use a host_device as the destination for "qemu-img convert". I added a ->bdrv_create function host_device. It merely verifies that the device exists and is large enough. A check is needed in the qemu-img convert loop to ensure that we write out all 0 sectors to the host_device. Otherwise they end up with stale garbage where all zero sectors were expected. I also made the check against bdrv_is_allocated enabled for everything _except_ host devices, since there is no point in making the block backend write a bunch of zeros just so that we can memcmp them immediately afterwards. Host devices can't benefit from this because there is no way to differentiate between a sector being unallocated because it was never written, or because it was written with all zeros and then made a trip through qemu-img convert. Finally, there is an unrelated fix for a typo in the error message printed if the destination device does not support ->bdrv_create. Signed-off-by: Nolan Leake sigbus.net> Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6978 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw-posix.c | 36 ++++++++++++++++++++++++++++++++++++ qemu-img.c | 34 +++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/block-raw-posix.c b/block-raw-posix.c index 4874b8e4a..bff822ea6 100644 --- a/block-raw-posix.c +++ b/block-raw-posix.c @@ -1378,11 +1378,47 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, } #endif /* !linux && !FreeBSD */ +#if defined(__linux__) || defined(__FreeBSD__) +static int hdev_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd; + int ret = 0; + struct stat stat_buf; + + if (flags || backing_file) + return -ENOTSUP; + + fd = open(filename, O_WRONLY | O_BINARY); + if (fd < 0) + return -EIO; + + if (fstat(fd, &stat_buf) < 0) + ret = -EIO; + else if (!S_ISBLK(stat_buf.st_mode)) + ret = -EIO; + else if (lseek(fd, 0, SEEK_END) < total_size * 512) + ret = -ENOSPC; + + close(fd); + return ret; +} + +#else /* !(linux || freebsd) */ + +static int hdev_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + return -ENOTSUP; +} +#endif + BlockDriver bdrv_host_device = { .format_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_open = hdev_open, .bdrv_close = raw_close, + .bdrv_create = hdev_create, .bdrv_flush = raw_flush, #ifdef CONFIG_AIO diff --git a/qemu-img.c b/qemu-img.c index ab380c8a4..913ad34bf 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -493,7 +493,7 @@ static int img_convert(int argc, char **argv) ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags); if (ret < 0) { if (ret == -ENOTSUP) { - error("Formatting not supported for file format '%s'", fmt); + error("Formatting not supported for file format '%s'", out_fmt); } else { error("Error while formatting '%s'", out_filename); } @@ -592,18 +592,17 @@ static int img_convert(int argc, char **argv) if (n > bs_offset + bs_sectors - sector_num) n = bs_offset + bs_sectors - sector_num; - /* If the output image is being created as a copy on write image, - assume that sectors which are unallocated in the input image - are present in both the output's and input's base images (no - need to copy them). */ - if (out_baseimg) { - if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) { - sector_num += n1; - continue; - } - /* The next 'n1' sectors are allocated in the input image. Copy - only those as they may be followed by unallocated sectors. */ - n = n1; + if (drv != &bdrv_host_device) { + if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, + n, &n1)) { + sector_num += n1; + continue; + } + /* The next 'n1' sectors are allocated in the input image. Copy + only those as they may be followed by unallocated sectors. */ + n = n1; + } else { + n1 = n; } if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) @@ -615,8 +614,13 @@ static int img_convert(int argc, char **argv) while (n > 0) { /* If the output image is being created as a copy on write image, copy all sectors even the ones containing only NUL bytes, - because they may differ from the sectors in the base image. */ - if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) { + because they may differ from the sectors in the base image. + + If the output is to a host device, we also write out + sectors that are entirely 0, since whatever data was + already there is garbage, not 0s. */ + if (drv == &bdrv_host_device || out_baseimg || + is_allocated_sectors(buf1, n, &n1)) { if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) error("error while writing"); } -- cgit v1.2.3 From 0d00e56353a061b182196b922d33dd0ca60d8442 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:46 +0000 Subject: build system: silent generation of doc files and qemu-options.h (Jan Kiszka) Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6979 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 26 ++++++++++++++++---------- Makefile.target | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 2bee52cb8..37c7182bc 100644 --- a/Makefile +++ b/Makefile @@ -283,28 +283,34 @@ cscope: # documentation %.html: %.texi - texi2html -I=. -monolithic -number $< + $(call quiet-command,texi2html -I=. -monolithic -number $<," GEN $@") %.info: %.texi - makeinfo -I . $< -o $@ + $(call quiet-command,makeinfo -I . $< -o $@," GEN $@") %.dvi: %.texi - texi2dvi -I . $< + $(call quiet-command,texi2dvi -I . $<," GEN $@") qemu-options.texi: $(SRC_PATH)/qemu-options.hx - sh $(SRC_PATH)/hxtool -t < $< > $@ + $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@") qemu.1: qemu-doc.texi - perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod - pod2man --section=1 --center=" " --release=" " qemu.pod > $@ + $(call quiet-command, \ + perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \ + pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \ + " GEN $@") qemu-img.1: qemu-img.texi - perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod - pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ + $(call quiet-command, \ + perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \ + pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \ + " GEN $@") qemu-nbd.8: qemu-nbd.texi - perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod - pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@ + $(call quiet-command, \ + perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \ + pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \ + " GEN $@") info: qemu-doc.info qemu-tech.info diff --git a/Makefile.target b/Makefile.target index 535d6d2e3..ec366a737 100644 --- a/Makefile.target +++ b/Makefile.target @@ -741,7 +741,7 @@ else endif qemu-options.h: $(SRC_PATH)/qemu-options.hx - sh $(SRC_PATH)/hxtool -h < $< > $@ + $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o qemu-options.h -- cgit v1.2.3 From 016c62c81bf0f434f3213d69962add45ebd4df24 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:50 +0000 Subject: build system: clean qemu-options.texi and gdbstub-xml.c (Jan Kiszka) Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6980 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 37c7182bc..50914c430 100644 --- a/Makefile +++ b/Makefile @@ -219,7 +219,7 @@ clean: done distclean: clean - rm -f config-host.mak config-host.h $(DOCS) + rm -f config-host.mak config-host.h $(DOCS) qemu-options.texi rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr} for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ diff --git a/Makefile.target b/Makefile.target index ec366a737..353ba6c91 100644 --- a/Makefile.target +++ b/Makefile.target @@ -744,7 +744,7 @@ qemu-options.h: $(SRC_PATH)/qemu-options.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") clean: - rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o qemu-options.h + rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o qemu-options.h gdbstub-xml.c rm -f *.d */*.d tcg/*.o install: all -- cgit v1.2.3 From 8707eccac83bda82d802c0cfa04fc0ff6bcdce27 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:55 +0000 Subject: pci_add storage: fix error handling for 'if' parameter (Eduardo Habkost) This fixes: - The error message to show the actual if= argument value. It was showing the filename instead, because 'buf' is reaused on the filename parsing. - A bug that makes a block device to be created even when an unsupported if= arg is passed to pci_add. Signed-off-by: Eduardo Habkost Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6981 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci-hotplug.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index a01efe096..d968a14ec 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -97,19 +97,22 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus, type = IF_SCSI; else if (!strcmp(buf, "virtio")) { type = IF_VIRTIO; + } else { + monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); + goto out; } } else { monitor_printf(mon, "no if= specified\n"); - return NULL; + goto out; } if (get_param_value(buf, sizeof(buf), "file", opts)) { drive_idx = add_init_drive(opts); if (drive_idx < 0) - return NULL; + goto out; } else if (type == IF_VIRTIO) { monitor_printf(mon, "virtio requires a backing file/device.\n"); - return NULL; + goto out; } switch (type) { @@ -122,10 +125,9 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus, case IF_VIRTIO: opaque = virtio_blk_init (pci_bus, drives_table[drive_idx].bdrv); break; - default: - monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf); } +out: return opaque; } -- cgit v1.2.3 From 2d2431f03fc78b532f3a1c5f858cf78859d50fc3 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:40:58 +0000 Subject: qcow2: fix image creation for large, > ~2TB, images (Chris Wright) When creating large disk images w/ qcow2 format, qcow2_create is hard coded to creating a single refcount block. This is insufficient for large images, and will cause qemu-img to segfault as it walks off the end of the refcount block. Keep track of the space needed during image create and create proper number of refcount blocks accordingly. https://bugzilla.redhat.com/show_bug.cgi?id=491943 Signed-off-by: Chris Wright Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6982 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 0e507ca48..d99811d3f 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1555,7 +1555,7 @@ static int qcow_create2(const char *filename, int64_t total_size, { int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; - int backing_format_len = 0; + int ref_clusters, backing_format_len = 0; QCowHeader header; uint64_t tmp, offset; QCowCreateState s1, *s = &s1; @@ -1604,22 +1604,28 @@ static int qcow_create2(const char *filename, int64_t total_size, offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); s->refcount_table = qemu_mallocz(s->cluster_size); - s->refcount_block = qemu_mallocz(s->cluster_size); s->refcount_table_offset = offset; header.refcount_table_offset = cpu_to_be64(offset); header.refcount_table_clusters = cpu_to_be32(1); offset += s->cluster_size; - - s->refcount_table[0] = cpu_to_be64(offset); s->refcount_block_offset = offset; - offset += s->cluster_size; + + /* count how many refcount blocks needed */ + tmp = offset >> s->cluster_bits; + ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1; + for (i=0; i < ref_clusters; i++) { + s->refcount_table[i] = cpu_to_be64(offset); + offset += s->cluster_size; + } + + s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size); /* update refcounts */ create_refcount_update(s, 0, header_size); create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t)); create_refcount_update(s, s->refcount_table_offset, s->cluster_size); - create_refcount_update(s, s->refcount_block_offset, s->cluster_size); + create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size); /* write all the data */ write(fd, &header, sizeof(header)); @@ -1648,7 +1654,7 @@ static int qcow_create2(const char *filename, int64_t total_size, write(fd, s->refcount_table, s->cluster_size); lseek(fd, s->refcount_block_offset, SEEK_SET); - write(fd, s->refcount_block, s->cluster_size); + write(fd, s->refcount_block, ref_clusters * s->cluster_size); qemu_free(s->refcount_table); qemu_free(s->refcount_block); -- cgit v1.2.3 From 1625af873aa8c9e4d22ad50a08e877110bf40623 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 17:41:02 +0000 Subject: Make binary stripping conditional (Riku Voipio) Currently qemu unconditionally strips binaries on install. This is a problem for packagers who may want to store/ship debug symbols of compiled packages for debugging purposes. Keep stripping as default for the oldtimers and add a --disable-strip flag to override. Signed-off-by: Riku Voipio Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6983 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 2 +- configure | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 50914c430..a9e851f75 100644 --- a/Makefile +++ b/Makefile @@ -251,7 +251,7 @@ endif install: all $(if $(BUILD_DOCS),install-doc) mkdir -p "$(DESTDIR)$(bindir)" ifneq ($(TOOLS),) - $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)" endif ifneq ($(BLOBS),) mkdir -p "$(DESTDIR)$(datadir)" diff --git a/Makefile.target b/Makefile.target index 353ba6c91..b32d1af68 100644 --- a/Makefile.target +++ b/Makefile.target @@ -749,7 +749,7 @@ clean: install: all ifneq ($(PROGS),) - $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 $(STRIP_OPT) $(PROGS) "$(DESTDIR)$(bindir)" endif # Include automatically generated dependency files diff --git a/configure b/configure index fa779379f..e97483445 100755 --- a/configure +++ b/configure @@ -154,6 +154,7 @@ case "$cpu" in esac gprof="no" sparse="no" +strip_opt="yes" bigendian="no" mingw32="no" EXESUF="" @@ -396,6 +397,8 @@ for opt do ;; --disable-sparse) sparse="no" ;; + --disable-strip) strip_opt="no" + ;; --disable-vnc-tls) vnc_tls="no" ;; --disable-vnc-sasl) vnc_sasl="no" @@ -556,6 +559,7 @@ echo " --install=INSTALL use specified install [$install]" echo " --static enable static build [$static]" echo " --enable-sparse enable sparse checker" echo " --disable-sparse disable sparse checker (default)" +echo " --disable-strip disable stripping binaries" echo " --disable-werror disable compilation abort on warning" echo " --disable-sdl disable SDL" echo " --enable-cocoa enable COCOA (Mac OS X only)" @@ -1177,6 +1181,7 @@ echo "host big endian $bigendian" echo "target list $target_list" echo "gprof enabled $gprof" echo "sparse enabled $sparse" +echo "strip binaries $strip_opt" echo "profiler $profiler" echo "static build $static" echo "-Werror enabled $werror" @@ -1251,7 +1256,6 @@ echo "INSTALL=$install" >> $config_mak echo "CC=$cc" >> $config_mak echo "HOST_CC=$host_cc" >> $config_mak echo "AR=$ar" >> $config_mak -echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak # XXX: only use CFLAGS and LDFLAGS ? # XXX: should export HOST_CFLAGS and HOST_LDFLAGS for cross # compilation of dyngen tool (useful for win32 build on Linux host) @@ -1338,6 +1342,9 @@ if test "$sparse" = "yes" ; then echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_mak echo "CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_mak fi +if test "$strip_opt" = "yes" ; then + echo "STRIP_OPT=-s" >> $config_mak +fi if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> $config_mak echo "#define WORDS_BIGENDIAN 1" >> $config_h -- cgit v1.2.3 From b9e82a5946d902af445a53727c69b4851b1b20ff Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 5 Apr 2009 18:03:31 +0000 Subject: Fix some win32 compile warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6984 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw-win32.c | 4 ++-- exec.c | 1 - nbd.c | 2 +- net.c | 2 +- slirp/misc.c | 6 +++++- slirp/socket.h | 1 + tap-win32.c | 10 +++++----- vl.c | 17 ++++++++++++----- 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/block-raw-win32.c b/block-raw-win32.c index 11638b8d4..af9cc6db3 100644 --- a/block-raw-win32.c +++ b/block-raw-win32.c @@ -166,7 +166,7 @@ static void raw_close(BlockDriverState *bs) static int raw_truncate(BlockDriverState *bs, int64_t offset) { BDRVRawState *s = bs->opaque; - DWORD low, high; + LONG low, high; low = offset; high = offset >> 32; @@ -188,7 +188,7 @@ static int64_t raw_getlength(BlockDriverState *bs) switch(s->type) { case FTYPE_FILE: - l.LowPart = GetFileSize(s->hfile, &l.HighPart); + l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) return -EIO; break; diff --git a/exec.c b/exec.c index 5e94a8fee..94bc92802 100644 --- a/exec.c +++ b/exec.c @@ -19,7 +19,6 @@ */ #include "config.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN #include #else #include diff --git a/nbd.c b/nbd.c index 77b3e1692..1586ea755 100644 --- a/nbd.c +++ b/nbd.c @@ -579,7 +579,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, if ((request.from + request.len) > size) { LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 ", Offset: %" PRIu64 "\n", - request.from, request.len, size, dev_offset); + request.from, request.len, (uint64_t)size, dev_offset); LOG("requested operation past EOF--bad client?"); errno = EINVAL; return -1; diff --git a/net.c b/net.c index 395ee4f5f..f67b5b807 100644 --- a/net.c +++ b/net.c @@ -1903,9 +1903,9 @@ done: void net_cleanup(void) { +#if !defined(_WIN32) VLANState *vlan; -#if !defined(_WIN32) /* close network clients */ for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { VLANClientState *vc; diff --git a/slirp/misc.c b/slirp/misc.c index 581db880d..0137e75ed 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -777,7 +777,11 @@ void fd_nonblock(int fd) { #ifdef FIONBIO - int opt = 1; +#ifdef _WIN32 + long opt = 1; +#else + int opt = 1; +#endif ioctlsocket(fd, FIONBIO, &opt); #else diff --git a/slirp/socket.h b/slirp/socket.h index 72b473d63..f5adaba6e 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -87,6 +87,7 @@ void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); +struct iovec; /* For win32 */ size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); int soreadbuf(struct socket *so, const char *buf, int size); diff --git a/tap-win32.c b/tap-win32.c index df31fda49..e8a04dc7c 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -254,7 +254,7 @@ static int is_tap_win32_dev(const char *guid) component_id_string, NULL, &data_type, - component_id, + (LPBYTE)component_id, &len); if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { @@ -264,7 +264,7 @@ static int is_tap_win32_dev(const char *guid) net_cfg_instance_id_string, NULL, &data_type, - net_cfg_instance_id, + (LPBYTE)net_cfg_instance_id, &len); if (status == ERROR_SUCCESS && data_type == REG_SZ) { @@ -353,7 +353,7 @@ static int get_device_guid( name_string, NULL, &name_type, - name_data, + (LPBYTE)name_data, &len); if (status != ERROR_SUCCESS || name_type != REG_SZ) { @@ -560,7 +560,7 @@ static int tap_win32_read(tap_win32_overlapped_t *overlapped, } static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, - char* pbuf) + uint8_t *pbuf) { tun_buffer_t* buffer = (tun_buffer_t*)pbuf; put_buffer_on_free_list(overlapped, buffer); @@ -580,7 +580,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, unsigned long minor; unsigned long debug; } version; - LONG version_len; + DWORD version_len; DWORD idThread; HANDLE hThread; diff --git a/vl.c b/vl.c index 5e6c621f2..a2de1f35f 100644 --- a/vl.c +++ b/vl.c @@ -245,7 +245,9 @@ int no_reboot = 0; int no_shutdown = 0; int cursor_hide = 1; int graphic_rotate = 0; +#ifndef _WIN32 int daemonize = 0; +#endif const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; @@ -1297,8 +1299,9 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id) } #ifdef _WIN32 -void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, - DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, + DWORD_PTR dwUser, DWORD_PTR dw1, + DWORD_PTR dw2) #else static void host_alarm_handler(int host_signum) #endif @@ -4262,14 +4265,18 @@ int main(int argc, char **argv, char **envp) const char *cpu_model; const char *usb_devices[MAX_USB_CMDLINE]; int usb_devices_index; +#ifndef _WIN32 int fds[2]; +#endif int tb_size; const char *pid_file = NULL; const char *incoming = NULL; +#ifndef _WIN32 int fd = 0; struct passwd *pwd = NULL; const char *chroot_dir = NULL; const char *run_as = NULL; +#endif qemu_cache_utils_init(envp); @@ -5015,7 +5022,6 @@ int main(int argc, char **argv, char **envp) signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); } -#endif if (pid_file && qemu_create_pidfile(pid_file) != 0) { if (daemonize) { @@ -5025,6 +5031,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "Could not acquire pid file\n"); exit(1); } +#endif #ifdef USE_KQEMU if (smp_cpus > 1) @@ -5385,6 +5392,7 @@ int main(int argc, char **argv, char **envp) if (autostart) vm_start(); +#ifndef _WIN32 if (daemonize) { uint8_t status = 0; ssize_t len; @@ -5403,7 +5411,6 @@ int main(int argc, char **argv, char **envp) exit(1); } -#ifndef _WIN32 if (run_as) { pwd = getpwnam(run_as); if (!pwd) { @@ -5434,7 +5441,6 @@ int main(int argc, char **argv, char **envp) exit(1); } } -#endif if (daemonize) { dup2(fd, 0); @@ -5443,6 +5449,7 @@ int main(int argc, char **argv, char **envp) close(fd); } +#endif main_loop(); quit_timers(); -- cgit v1.2.3 From 9586fefefe383a9aa25ad99bde9a6b240309ca33 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 18:41:18 +0000 Subject: Fix display breakage when resizing the screen (v2) (Avi Kivity) When the vga resolution changes, a new display surface is not allocated immediately; instead that is deferred until the next update. However, if we're running without a display client attached, that won't happen and the next bitblt is likely to cause a segfault by overflowing the display surface. Fix by reallocating the display immediately when the resolution changes. Tested with (Windows|Linux) x (cirrus|std) x (curses|sdl). Changes from v1: - fix segfault when switching virtual consoles with curses Signed-off-by: Avi Kivity Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6989 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 11 ++- hw/vga.c | 275 ++++++++++++++++++++++++++++++++------------------------ hw/vga_int.h | 4 + 3 files changed, 170 insertions(+), 120 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 08fd4c29a..223008e0f 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1392,6 +1392,8 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) break; } + vga_update_resolution((VGAState *)s); + return CIRRUS_HOOK_HANDLED; } @@ -1419,6 +1421,7 @@ static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) #endif } s->cirrus_hidden_dac_lockindex = 0; + vga_update_resolution((VGAState *)s); } /*************************************** @@ -1705,6 +1708,8 @@ cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) break; } + vga_update_resolution((VGAState *)s); + return CIRRUS_HOOK_HANDLED; } @@ -2830,6 +2835,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (s->ar_flip_flop == 0) { val &= 0x3f; s->ar_index = val; + vga_update_resolution((VGAState *)s); } else { index = s->ar_index & 0x1f; switch (index) { @@ -2923,6 +2929,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* can always write bit 4 of CR7 */ if (s->cr_index == 7) s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); + vga_update_resolution((VGAState *)s); return; } switch (s->cr_index) { @@ -2951,6 +2958,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->update_retrace_info((VGAState *) s); break; } + vga_update_resolution((VGAState *)s); break; case 0x3ba: case 0x3da: @@ -3157,7 +3165,8 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) cirrus_update_memory_access(s); /* force refresh */ - s->graphic_mode = -1; + vga_update_resolution((VGAState *)s); + s->want_full_update = 1; cirrus_update_bank_ptr(s, 0); cirrus_update_bank_ptr(s, 1); return 0; diff --git a/hw/vga.c b/hw/vga.c index b1e43730d..54d0246c8 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -36,6 +36,10 @@ //#define DEBUG_BOCHS_VBE +#define GMODE_TEXT 0 +#define GMODE_GRAPH 1 +#define GMODE_BLANK 2 + /* force some bits to zero */ const uint8_t sr_mask[8] = { 0x03, @@ -393,6 +397,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (s->ar_flip_flop == 0) { val &= 0x3f; s->ar_index = val; + vga_update_resolution(s); } else { index = s->ar_index & 0x1f; switch(index) { @@ -433,6 +438,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; if (s->sr_index == 1) s->update_retrace_info(s); + vga_update_resolution(s); break; case 0x3c7: s->dac_read_index = val; @@ -460,6 +466,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); #endif s->gr[s->gr_index] = val & gr_mask[s->gr_index]; + vga_update_resolution(s); break; case 0x3b4: case 0x3d4: @@ -475,6 +482,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* can always write bit 4 of CR7 */ if (s->cr_index == 7) s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); + vga_update_resolution(s); return; } switch(s->cr_index) { @@ -502,6 +510,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->update_retrace_info(s); break; } + vga_update_resolution(s); break; case 0x3ba: case 0x3da: @@ -581,11 +590,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { s->vbe_regs[s->vbe_index] = val; } + vga_update_resolution(s); break; case VBE_DISPI_INDEX_YRES: if (val <= VBE_DISPI_MAX_YRES) { s->vbe_regs[s->vbe_index] = val; } + vga_update_resolution(s); break; case VBE_DISPI_INDEX_BPP: if (val == 0) @@ -594,6 +605,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) val == 16 || val == 24 || val == 32) { s->vbe_regs[s->vbe_index] = val; } + vga_update_resolution(s); break; case VBE_DISPI_INDEX_BANK: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { @@ -662,6 +674,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0; s->vbe_regs[s->vbe_index] = val; + vga_update_resolution(s); break; case VBE_DISPI_INDEX_VIRT_WIDTH: { @@ -682,6 +695,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; s->vbe_line_offset = line_offset; } + vga_update_resolution(s); break; case VBE_DISPI_INDEX_X_OFFSET: case VBE_DISPI_INDEX_Y_OFFSET: @@ -696,6 +710,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); s->vbe_start_addr >>= 2; } + vga_update_resolution(s); break; default: break; @@ -1302,7 +1317,6 @@ static void vga_draw_text(VGAState *s, int full_update) s->plane_updated = 0; full_update = 1; } - full_update |= update_basic_params(s); line_offset = s->line_offset; s1 = s->vram_ptr + (s->start_addr * 4); @@ -1314,18 +1328,6 @@ static void vga_draw_text(VGAState *s, int full_update) return; } - if (width != s->last_width || height != s->last_height || - cw != s->last_cw || cheight != s->last_ch || s->last_depth) { - s->last_scr_width = width * cw; - s->last_scr_height = height * cheight; - qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); - s->last_depth = 0; - s->last_width = width; - s->last_height = height; - s->last_ch = cheight; - s->last_cw = cw; - full_update = 1; - } s->rgb_to_pixel = rgb_to_pixel_dup_table[get_depth_index(s->ds)]; full_update |= update_palette16(s); @@ -1582,39 +1584,21 @@ static void vga_sync_dirty_bitmap(VGAState *s) vga_dirty_log_start(s); } -/* - * graphic modes - */ -static void vga_draw_graphic(VGAState *s, int full_update) +static void vga_update_resolution_graphics(VGAState *s) { - int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask, depth; - int width, height, shift_control, line_offset, page0, page1, bwidth, bits; + int depth = s->get_bpp(s); + int width, height, shift_control, double_scan; int disp_width, multi_scan, multi_run; - uint8_t *d; - uint32_t v, addr1, addr; - vga_draw_line_func *vga_draw_line; - - full_update |= update_basic_params(s); - - if (!full_update) - vga_sync_dirty_bitmap(s); s->get_resolution(s, &width, &height); disp_width = width; shift_control = (s->gr[0x05] >> 5) & 3; double_scan = (s->cr[0x09] >> 7); - if (shift_control != 1) { - multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; - } else { - /* in CGA modes, multi_scan is ignored */ - /* XXX: is it correct ? */ - multi_scan = double_scan; - } - multi_run = multi_scan; + if (shift_control != s->shift_control || double_scan != s->double_scan) { - full_update = 1; + s->want_full_update = 1; s->shift_control = shift_control; s->double_scan = double_scan; } @@ -1628,12 +1612,28 @@ static void vga_draw_graphic(VGAState *s, int full_update) disp_width <<= 1; } } + disp_width = width; + + if (shift_control != 1) { + multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; + } else { + /* in CGA modes, multi_scan is ignored */ + /* XXX: is it correct ? */ + multi_scan = double_scan; + } + + multi_run = multi_scan; - depth = s->get_bpp(s); if (s->line_offset != s->last_line_offset || disp_width != s->last_width || height != s->last_height || - s->last_depth != depth) { + s->last_depth != depth || + s->multi_run != multi_run || + s->multi_scan != multi_scan || + s->want_full_update) { + if (s->ds->surface->pf.depth == 0) { + goto dont_touch_display_surface; + } #if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) if (depth == 16 || depth == 32) { #else @@ -1650,14 +1650,91 @@ static void vga_draw_graphic(VGAState *s, int full_update) } else { qemu_console_resize(s->ds, disp_width, height); } + dont_touch_display_surface: s->last_scr_width = disp_width; s->last_scr_height = height; s->last_width = disp_width; s->last_height = height; s->last_line_offset = s->line_offset; s->last_depth = depth; - full_update = 1; - } else if (is_buffer_shared(s->ds->surface) && + s->multi_run = multi_run; + s->multi_scan = multi_scan; + s->want_full_update = 1; + } +} + +static void vga_update_resolution_text(VGAState *s) +{ + int width, height, cw, cheight; + + vga_get_text_resolution(s, &width, &height, &cw, &cheight); + if (width != s->last_width || height != s->last_height || + cw != s->last_cw || cheight != s->last_ch || s->last_depth) { + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + if (s->ds->surface->pf.depth != 0) { + qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); + } else { + /* + * curses expects width and height to be in character cell + * dimensions, not pixels. + */ + s->ds->surface->width = width; + s->ds->surface->height = height; + dpy_resize(s->ds); + } + s->last_depth = 0; + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; + s->want_full_update = 1; + } +} + +void vga_update_resolution(VGAState *s) +{ + int graphic_mode; + + if (!(s->ar_index & 0x20)) { + graphic_mode = GMODE_BLANK; + } else { + graphic_mode = s->gr[6] & 1; + } + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; + s->want_full_update = 1; + } + s->want_full_update |= update_basic_params(s); + switch (graphic_mode) { + case GMODE_TEXT: + vga_update_resolution_text(s); + break; + case GMODE_GRAPH: + vga_update_resolution_graphics(s); + break; + } +} + +/* + * graphic modes + */ +static void vga_draw_graphic(VGAState *s, int full_update) +{ + int y1, y, update, linesize, y_start, mask; + int width, height, line_offset, bwidth, bits; + int multi_run; + uint8_t *d; + uint32_t v, addr1, addr; + long page0, page1, page_min, page_max; + vga_draw_line_func *vga_draw_line; + + if (!full_update) + vga_sync_dirty_bitmap(s); + + s->get_resolution(s, &width, &height); + multi_run = s->multi_run; + if (is_buffer_shared(s->ds->surface) && (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) { s->ds->surface->data = s->vram_ptr + (s->start_addr * 4); dpy_setdata(s->ds); @@ -1666,7 +1743,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) s->rgb_to_pixel = rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - if (shift_control == 0) { + if (s->shift_control == 0) { full_update |= update_palette16(s); if (s->sr[0x01] & 8) { v = VGA_DRAW_LINE4D2; @@ -1674,7 +1751,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) v = VGA_DRAW_LINE4; } bits = 4; - } else if (shift_control == 1) { + } else if (s->shift_control == 1) { full_update |= update_palette16(s); if (s->sr[0x01] & 8) { v = VGA_DRAW_LINE2D2; @@ -1770,7 +1847,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (y_start >= 0) { /* flush to display */ dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); + s->last_width, y - y_start); y_start = -1; } } @@ -1779,7 +1856,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) if ((y1 & mask) == mask) addr1 += line_offset; y1++; - multi_run = multi_scan; + multi_run = s->multi_scan; } else { multi_run--; } @@ -1791,7 +1868,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (y_start >= 0) { /* flush to display */ dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); + s->last_width, y - y_start); } /* reset modified pages */ if (page_max != -1) { @@ -1828,29 +1905,17 @@ static void vga_draw_blank(VGAState *s, int full_update) s->last_scr_width, s->last_scr_height); } -#define GMODE_TEXT 0 -#define GMODE_GRAPH 1 -#define GMODE_BLANK 2 - static void vga_update_display(void *opaque) { VGAState *s = (VGAState *)opaque; - int full_update, graphic_mode; + int full_update; if (ds_get_bits_per_pixel(s->ds) == 0) { /* nothing to do */ } else { - full_update = 0; - if (!(s->ar_index & 0x20)) { - graphic_mode = GMODE_BLANK; - } else { - graphic_mode = s->gr[6] & 1; - } - if (graphic_mode != s->graphic_mode) { - s->graphic_mode = graphic_mode; - full_update = 1; - } - switch(graphic_mode) { + full_update = s->want_full_update; + s->want_full_update = 0; + switch(s->graphic_mode) { case GMODE_TEXT: vga_draw_text(s, full_update); break; @@ -1870,8 +1935,8 @@ static void vga_invalidate_display(void *opaque) { VGAState *s = (VGAState *)opaque; - s->last_width = -1; - s->last_height = -1; + vga_update_resolution(s); + s->want_full_update = 1; } void vga_reset(void *opaque) @@ -1915,7 +1980,6 @@ void vga_reset(void *opaque) s->vbe_bank_mask = (s->vram_size >> 16) - 1; #endif memset(s->font_offsets, '\0', sizeof(s->font_offsets)); - s->graphic_mode = -1; /* force full update */ s->shift_control = 0; s->double_scan = 0; s->line_offset = 0; @@ -1941,6 +2005,7 @@ void vga_reset(void *opaque) memset(&s->retrace_info, 0, sizeof (s->retrace_info)); break; } + vga_update_resolution(s); } #define TEXTMODE_X(x) ((x) % width) @@ -1952,50 +2017,28 @@ void vga_reset(void *opaque) static void vga_update_text(void *opaque, console_ch_t *chardata) { VGAState *s = (VGAState *) opaque; - int graphic_mode, i, cursor_offset, cursor_visible; + int i, cursor_offset, cursor_visible; int cw, cheight, width, height, size, c_min, c_max; uint32_t *src; console_ch_t *dst, val; char msg_buffer[80]; - int full_update = 0; - - if (!(s->ar_index & 0x20)) { - graphic_mode = GMODE_BLANK; - } else { - graphic_mode = s->gr[6] & 1; - } - if (graphic_mode != s->graphic_mode) { - s->graphic_mode = graphic_mode; - full_update = 1; - } - if (s->last_width == -1) { - s->last_width = 0; - full_update = 1; - } + int full_update = s->want_full_update; - switch (graphic_mode) { + s->want_full_update = 0; + switch (s->graphic_mode) { case GMODE_TEXT: /* TODO: update palette */ - full_update |= update_basic_params(s); - /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; - cw = 8; - if (!(s->sr[1] & 0x01)) - cw = 9; - if (s->sr[1] & 0x08) - cw = 16; /* NOTE: no 18 pixel wide */ - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { - /* ugly hack for CGA 160x100x16 - explain me the logic */ - height = 100; - } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1) / cheight; + vga_get_text_resolution(s, &width, &height, &cw, &cheight); + + if (s->ds->surface->width != width + || s->ds->surface->height != height) { + s->ds->surface->width = width; + s->ds->surface->height = height; + dpy_resize(s->ds); } + /* total width & height */ size = (height * width); if (size > CH_ATTR_SIZE) { if (!full_update) @@ -2006,20 +2049,6 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) break; } - if (width != s->last_width || height != s->last_height || - cw != s->last_cw || cheight != s->last_ch) { - s->last_scr_width = width * cw; - s->last_scr_height = height * cheight; - s->ds->surface->width = width; - s->ds->surface->height = height; - dpy_resize(s->ds); - s->last_width = width; - s->last_height = height; - s->last_ch = cheight; - s->last_cw = cw; - full_update = 1; - } - /* Update "hardware" cursor */ cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; if (cursor_offset != s->cursor_offset || @@ -2218,7 +2247,8 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) #endif /* force refresh */ - s->graphic_mode = -1; + vga_update_resolution(s); + s->want_full_update = 1; return 0; } @@ -2641,7 +2671,8 @@ static void vga_screen_dump_common(VGAState *s, const char *filename, ds->surface = qemu_create_displaysurface(ds, w, h); s->ds = ds; - s->graphic_mode = -1; + vga_update_resolution(s); + s->want_full_update = 1; vga_update_display(s); ppm_save(filename, ds->surface); @@ -2672,10 +2703,16 @@ static void vga_screen_dump(void *opaque, const char *filename) { VGAState *s = (VGAState *)opaque; - if (!(s->ar_index & 0x20)) - vga_screen_dump_blank(s, filename); - else if (s->gr[6] & 1) - vga_screen_dump_graphic(s, filename); - else + switch (s->graphic_mode) { + case GMODE_TEXT: vga_screen_dump_text(s, filename); + break; + case GMODE_GRAPH: + vga_screen_dump_graphic(s, filename); + break; + case GMODE_BLANK: + default: + vga_screen_dump_blank(s, filename); + break; + } } diff --git a/hw/vga_int.h b/hw/vga_int.h index f97e98fc9..6ab974267 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -147,8 +147,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); DisplayState *ds; \ uint32_t font_offsets[2]; \ int graphic_mode; \ + int want_full_update; \ uint8_t shift_control; \ uint8_t double_scan; \ + uint8_t multi_run; \ + uint8_t multi_scan; \ uint32_t line_offset; \ uint32_t line_compare; \ uint32_t start_addr; \ @@ -195,6 +198,7 @@ void vga_common_init(VGAState *s, uint8_t *vga_ram_base, ram_addr_t vga_ram_offset, int vga_ram_size); void vga_init(VGAState *s); void vga_reset(void *s); +void vga_update_resolution(VGAState *s); void vga_dirty_log_start(VGAState *s); void vga_dirty_log_stop(VGAState *s); -- cgit v1.2.3 From 0a8e1acd4dced15f2069df484df3c4d14c9534a9 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 18:41:23 +0000 Subject: qemu-io - an I/O path exerciser (Christoph Hellwig) This patch adds a new qemu-io tool that links against the block layer and image formats and allow to exercise them without needing a guest image. It is inspired by the xfs_io tool which does the same for plain file I/O. In fact the libxcmd library which is the backend of xfs_io is reused by this tool in a limited fashing (cmd.[ch] files). This version tests out most of the plain block I/O commands with the most notable absent commands beeing snapshot handling and real aio. This tool is the basis of the I/O path test suite I'm working on right now. Signed-off-by: Christoph Hellwig Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6990 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +++- configure | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a9e851f75..633774e2d 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,9 @@ qemu-img$(EXESUF): qemu-img.o qemu-tool.o osdep.o $(BLOCK_OBJS) qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS) -qemu-img$(EXESUF) qemu-nbd$(EXESUF): LIBS += -lz +qemu-io$(EXESUF): qemu-io.o qemu-tool.o osdep.o cmd.o $(BLOCK_OBJS) + +qemu-img$(EXESUF) qemu-nbd$(EXESUF) qemu-io$(EXESUF): LIBS += -lz clean: # avoid old build problems by removing potentially incorrect old files diff --git a/configure b/configure index e97483445..be8e38d5e 100755 --- a/configure +++ b/configure @@ -1551,7 +1551,7 @@ esac tools= if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then - tools="qemu-img\$(EXESUF) $tools" + tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" if [ "$linux" = "yes" ] ; then tools="qemu-nbd\$(EXESUF) $tools" fi -- cgit v1.2.3 From bc14ca2453f22f20569699bda5f12e892131092c Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 18:43:37 +0000 Subject: Make `-icount' help fit 80 chars screen width (Robert Riebisch) On Windows default screen width for the command prompt (A.K.A. "DOS window") is 80 chars. `-icount' help is 87 chars wide. So make it fit. Signed-off-by: Robert Riebisch Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6991 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-options.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 6c58e2a45..32f936fed 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1368,7 +1368,8 @@ ETEXI DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ "-icount [N|auto]\n" \ - " enable virtual instruction counter with 2^N clock ticks per instruction\n") + " enable virtual instruction counter with 2^N clock ticks per\n" \ + " instruction\n") STEXI @item -icount [N|auto] Enable virtual instruction counter. The virtual cpu will execute one -- cgit v1.2.3 From 59030a8cd4000fcf92d9b8225c6083f9e6ab86b8 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 18:43:41 +0000 Subject: gdbstub: Rework configuration via command line and monitor (Jan Kiszka) Introduce a more canonical gdbstub configuration (system emulation only) via the new switch '-gdb dev'. Keep '-s' as shorthand for '-gdb tcp::1234'. Use the same syntax also for the corresponding monitor command 'gdbserver'. Its default remains to listen on TCP port 1234. Changes in v4: - Rebased over new command line switches meta file Changes in v3: - Fix documentation Changes in v2: - Support for pipe-based like to gdb (target remote | qemu -gdb stdio) - Properly update the qemu-doc Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6992 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 41 +++++++++++++++++++++++++++-------------- monitor.c | 19 ++++++++++--------- qemu-options.hx | 26 ++++++++++++++++---------- vl.c | 25 ++++++++----------------- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 518c939f4..316f5e817 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2337,27 +2337,40 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -int gdbserver_start(const char *port) +#ifndef _WIN32 +static void gdb_sigterm_handler(int signal) +{ + if (vm_running) + vm_stop(EXCP_INTERRUPT); +} +#endif + +int gdbserver_start(const char *device) { GDBState *s; - char gdbstub_port_name[128]; - int port_num; - char *p; + char gdbstub_device_name[128]; CharDriverState *chr = NULL; CharDriverState *mon_chr; - if (!port || !*port) - return -1; - if (strcmp(port, "none") != 0) { - port_num = strtol(port, &p, 10); - if (*p == 0) { - /* A numeric value is interpreted as a port number. */ - snprintf(gdbstub_port_name, sizeof(gdbstub_port_name), - "tcp::%d,nowait,nodelay,server", port_num); - port = gdbstub_port_name; + if (!device) + return -1; + if (strcmp(device, "none") != 0) { + if (strstart(device, "tcp:", NULL)) { + /* enforce required TCP attributes */ + snprintf(gdbstub_device_name, sizeof(gdbstub_device_name), + "%s,nowait,nodelay,server", device); + device = gdbstub_device_name; } +#ifndef _WIN32 + else if (strcmp(device, "stdio") == 0) { + struct sigaction act; - chr = qemu_chr_open("gdb", port, NULL); + memset(&act, 0, sizeof(act)); + act.sa_handler = gdb_sigterm_handler; + sigaction(SIGINT, &act, NULL); + } +#endif + chr = qemu_chr_open("gdb", device, NULL); if (!chr) return -1; diff --git a/monitor.c b/monitor.c index c6fe968ff..75c8663a1 100644 --- a/monitor.c +++ b/monitor.c @@ -570,17 +570,18 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) } #ifdef CONFIG_GDBSTUB -static void do_gdbserver(Monitor *mon, const char *port) -{ - if (!port) - port = DEFAULT_GDBSTUB_PORT; - if (gdbserver_start(port) < 0) { - monitor_printf(mon, "Could not open gdbserver socket on port '%s'\n", - port); - } else if (strcmp(port, "none") == 0) { +static void do_gdbserver(Monitor *mon, const char *device) +{ + if (!device) + device = "tcp::" DEFAULT_GDBSTUB_PORT; + if (gdbserver_start(device) < 0) { + monitor_printf(mon, "Could not open gdbserver on device '%s'\n", + device); + } else if (strcmp(device, "none") == 0) { monitor_printf(mon, "Disabled gdbserver\n"); } else { - monitor_printf(mon, "Waiting gdb connection on port '%s'\n", port); + monitor_printf(mon, "Waiting for gdb connection on device '%s'\n", + device); } } #endif diff --git a/qemu-options.hx b/qemu-options.hx index 32f936fed..51593a398 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1216,19 +1216,25 @@ STEXI Do not start CPU at startup (you must type 'c' in the monitor). ETEXI -DEF("s", 0, QEMU_OPTION_s, \ - "-s wait gdb connection to port\n") -STEXI -@item -s -Wait gdb connection to port 1234 (@pxref{gdb_usage}). +DEF("gdb", HAS_ARG, QEMU_OPTION_gdb, \ + "-gdb dev wait for gdb connection on 'dev'\n") +STEXI +@item -gdb @var{dev} +Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical +connections will likely be TCP-based, but also UDP, pseudo TTY, or even +stdio are reasonable use case. The latter is allowing to start qemu from +within gdb and establish the connection via a pipe: +@example +(gdb) target remote | exec qemu -gdb stdio ... +@end example ETEXI -DEF("p", HAS_ARG, QEMU_OPTION_p, \ - "-p port set gdb connection port [default=%s]\n") +DEF("s", 0, QEMU_OPTION_s, \ + "-s shorthand for -gdb tcp::%s\n") STEXI -@item -p @var{port} -Change gdb connection port. @var{port} can be either a decimal number -to specify a TCP port, or a host device (same devices as the serial port). +@item -s +Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234 +(@pxref{gdb_usage}). ETEXI DEF("d", HAS_ARG, QEMU_OPTION_d, \ diff --git a/vl.c b/vl.c index a2de1f35f..1048bd456 100644 --- a/vl.c +++ b/vl.c @@ -4233,8 +4233,7 @@ static void termsig_setup(void) int main(int argc, char **argv, char **envp) { #ifdef CONFIG_GDBSTUB - int use_gdbstub; - const char *gdbstub_port; + const char *gdbstub_dev = NULL; #endif uint32_t boot_devices_bitmap = 0; int i; @@ -4317,10 +4316,6 @@ int main(int argc, char **argv, char **envp) initrd_filename = NULL; ram_size = 0; vga_ram_size = VGA_RAM_SIZE; -#ifdef CONFIG_GDBSTUB - use_gdbstub = 0; - gdbstub_port = DEFAULT_GDBSTUB_PORT; -#endif snapshot = 0; nographic = 0; curses = 0; @@ -4653,10 +4648,10 @@ int main(int argc, char **argv, char **envp) break; #ifdef CONFIG_GDBSTUB case QEMU_OPTION_s: - use_gdbstub = 1; + gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT; break; - case QEMU_OPTION_p: - gdbstub_port = optarg; + case QEMU_OPTION_gdb: + gdbstub_dev = optarg; break; #endif case QEMU_OPTION_L: @@ -5370,14 +5365,10 @@ int main(int argc, char **argv, char **envp) } #ifdef CONFIG_GDBSTUB - if (use_gdbstub) { - /* XXX: use standard host:port notation and modify options - accordingly. */ - if (gdbserver_start(gdbstub_port) < 0) { - fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n", - gdbstub_port); - exit(1); - } + if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { + fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", + gdbstub_dev); + exit(1); } #endif -- cgit v1.2.3 From 8185d2c9a20975114ebb59b0f46b615cbb83c730 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:10:50 +0000 Subject: Fix the build for --disable-aio This was reported by malc. Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6993 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw-posix.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block-raw-posix.c b/block-raw-posix.c index bff822ea6..50aad587d 100644 --- a/block-raw-posix.c +++ b/block-raw-posix.c @@ -1018,8 +1018,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) s->fd_open_flags = open_flags; /* open will not fail even if no floppy is inserted */ open_flags |= O_NONBLOCK; +#ifdef CONFIG_AIO } else if (strstart(filename, "/dev/sg", NULL)) { bs->sg = 1; +#endif } #endif #if defined(__FreeBSD__) @@ -1210,6 +1212,7 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) return ioctl(s->fd, req, buf); } +#ifdef CONFIG_AIO static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, unsigned long int req, void *buf, BlockDriverCompletionFunc *cb, void *opaque) @@ -1228,6 +1231,7 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, return &acb->common; } +#endif #elif defined(__FreeBSD__) @@ -1439,5 +1443,7 @@ BlockDriver bdrv_host_device = { .bdrv_set_locked = raw_set_locked, /* generic scsi device */ .bdrv_ioctl = raw_ioctl, +#ifdef CONFIG_AIO .bdrv_aio_ioctl = raw_aio_ioctl, +#endif }; -- cgit v1.2.3 From 178e08a58f40dd5aef2ce774fe0850f5d0e56918 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:10:55 +0000 Subject: Fix savevm after BDRV_FILE size enforcement We now enforce that you cannot write beyond the end of a non-growable file. qcow2 files are not growable but we rely on them being growable to do savevm/loadvm. Temporarily allow them to be growable by introducing a new API specifically for savevm read/write operations. Reported-by: malc Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6994 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 28 ++++++++++++++++++++++++++++ block.c | 20 ++++++++++++++++++++ block.h | 5 +++++ block_int.h | 5 +++++ savevm.c | 12 ++++++------ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index d99811d3f..6eba524a2 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -2721,6 +2721,31 @@ static void dump_refcounts(BlockDriverState *bs) #endif #endif +static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf, + int64_t pos, int size) +{ + int growable = bs->growable; + + bs->growable = 1; + bdrv_pwrite(bs, pos, buf, size); + bs->growable = growable; + + return size; +} + +static int qcow_get_buffer(BlockDriverState *bs, uint8_t *buf, + int64_t pos, int size) +{ + int growable = bs->growable; + int ret; + + bs->growable = 1; + ret = bdrv_pread(bs, pos, buf, size); + bs->growable = growable; + + return ret; +} + BlockDriver bdrv_qcow2 = { .format_name = "qcow2", .instance_size = sizeof(BDRVQcowState), @@ -2745,5 +2770,8 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_list = qcow_snapshot_list, .bdrv_get_info = qcow_get_info, + .bdrv_put_buffer = qcow_put_buffer, + .bdrv_get_buffer = qcow_get_buffer, + .bdrv_create2 = qcow_create2, }; diff --git a/block.c b/block.c index 4da3bcba1..dd40b565c 100644 --- a/block.c +++ b/block.c @@ -1146,6 +1146,26 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return drv->bdrv_get_info(bs, bdi); } +int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_put_buffer) + return -ENOTSUP; + return drv->bdrv_put_buffer(bs, buf, pos, size); +} + +int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_get_buffer) + return -ENOTSUP; + return drv->bdrv_get_buffer(bs, buf, pos, size); +} + /**************************************************************/ /* handling of snapshots */ diff --git a/block.h b/block.h index 6701d3450..f1919b668 100644 --- a/block.h +++ b/block.h @@ -178,4 +178,9 @@ void path_combine(char *dest, int dest_size, const char *base_path, const char *filename); +int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, + int64_t pos, int size); + +int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size); + #endif diff --git a/block_int.h b/block_int.h index af6dff6bd..dc4335982 100644 --- a/block_int.h +++ b/block_int.h @@ -78,6 +78,11 @@ struct BlockDriver { QEMUSnapshotInfo **psn_info); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + int (*bdrv_put_buffer)(BlockDriverState *bs, const uint8_t *buf, + int64_t pos, int size); + int (*bdrv_get_buffer)(BlockDriverState *bs, uint8_t *buf, + int64_t pos, int size); + /* removable device specific */ int (*bdrv_is_inserted)(BlockDriverState *bs); int (*bdrv_media_changed)(BlockDriverState *bs); diff --git a/savevm.c b/savevm.c index ce1262808..793ea7069 100644 --- a/savevm.c +++ b/savevm.c @@ -310,18 +310,18 @@ typedef struct QEMUFileBdrv int64_t base_offset; } QEMUFileBdrv; -static int bdrv_put_buffer(void *opaque, const uint8_t *buf, +static int block_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBdrv *s = opaque; - bdrv_pwrite(s->bs, s->base_offset + pos, buf, size); + bdrv_put_buffer(s->bs, buf, s->base_offset + pos, size); return size; } -static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) { QEMUFileBdrv *s = opaque; - return bdrv_pread(s->bs, s->base_offset + pos, buf, size); + return bdrv_get_buffer(s->bs, buf, s->base_offset + pos, size); } static int bdrv_fclose(void *opaque) @@ -341,9 +341,9 @@ static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_wr s->base_offset = offset; if (is_writable) - return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL); + return qemu_fopen_ops(s, block_put_buffer, NULL, bdrv_fclose, NULL); - return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL); + return qemu_fopen_ops(s, NULL, block_get_buffer, bdrv_fclose, NULL); } QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, -- cgit v1.2.3 From e3aff4f611bd920768f616e8275945a2adecb6d5 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:14:04 +0000 Subject: Add files not included in previous commit. Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6995 c046a42c-6fe2-441c-8c8c-71466251a162 --- cmd.c | 565 ++++++++++++++++++++++++++++++++ cmd.h | 78 +++++ qemu-io.c | 1074 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1717 insertions(+) create mode 100644 cmd.c create mode 100644 cmd.h create mode 100644 qemu-io.c diff --git a/cmd.c b/cmd.c new file mode 100644 index 000000000..e2f4486a1 --- /dev/null +++ b/cmd.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2003-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "cmd.h" + +#define _(x) x /* not gettext support yet */ + +extern int optind; + +/* from libxcmd/command.c */ + +cmdinfo_t *cmdtab; +int ncmds; + +static argsfunc_t args_func; +static checkfunc_t check_func; +static int ncmdline; +static char **cmdline; + +static int +compare(const void *a, const void *b) +{ + return strcmp(((const cmdinfo_t *)a)->name, + ((const cmdinfo_t *)b)->name); +} + +void +add_command( + const cmdinfo_t *ci) +{ + cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); + cmdtab[ncmds - 1] = *ci; + qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); +} + +static int +check_command( + const cmdinfo_t *ci) +{ + if (check_func) + return check_func(ci); + return 1; +} + +void +add_check_command( + checkfunc_t cf) +{ + check_func = cf; +} + +int +command_usage( + const cmdinfo_t *ci) +{ + printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); + return 0; +} + +int +command( + const cmdinfo_t *ct, + int argc, + char **argv) +{ + char *cmd = argv[0]; + + if (!check_command(ct)) + return 0; + + if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { + if (ct->argmax == -1) + fprintf(stderr, + _("bad argument count %d to %s, expected at least %d arguments\n"), + argc-1, cmd, ct->argmin); + else if (ct->argmin == ct->argmax) + fprintf(stderr, + _("bad argument count %d to %s, expected %d arguments\n"), + argc-1, cmd, ct->argmin); + else + fprintf(stderr, + _("bad argument count %d to %s, expected between %d and %d arguments\n"), + argc-1, cmd, ct->argmin, ct->argmax); + return 0; + } + optind = 0; + return ct->cfunc(argc, argv); +} + +const cmdinfo_t * +find_command( + const char *cmd) +{ + cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + if (strcmp(ct->name, cmd) == 0 || + (ct->altname && strcmp(ct->altname, cmd) == 0)) + return (const cmdinfo_t *)ct; + } + return NULL; +} + +void +add_user_command(char *optarg) +{ + ncmdline++; + cmdline = realloc(cmdline, sizeof(char*) * (ncmdline)); + if (!cmdline) { + perror("realloc"); + exit(1); + } + cmdline[ncmdline-1] = optarg; +} + +static int +args_command( + int index) +{ + if (args_func) + return args_func(index); + return 0; +} + +void +add_args_command( + argsfunc_t af) +{ + args_func = af; +} + +void +command_loop(void) +{ + int c, i, j = 0, done = 0; + char *input; + char **v; + const cmdinfo_t *ct; + + for (i = 0; !done && i < ncmdline; i++) { + input = strdup(cmdline[i]); + if (!input) { + fprintf(stderr, + _("cannot strdup command '%s': %s\n"), + cmdline[i], strerror(errno)); + exit(1); + } + v = breakline(input, &c); + if (c) { + ct = find_command(v[0]); + if (ct) { + if (ct->flags & CMD_FLAG_GLOBAL) + done = command(ct, c, v); + else { + j = 0; + while (!done && (j = args_command(j))) + done = command(ct, c, v); + } + } else + fprintf(stderr, _("command \"%s\" not found\n"), + v[0]); + } + doneline(input, v); + } + if (cmdline) { + free(cmdline); + return; + } + while (!done) { + if ((input = fetchline()) == NULL) + break; + v = breakline(input, &c); + if (c) { + ct = find_command(v[0]); + if (ct) + done = command(ct, c, v); + else + fprintf(stderr, _("command \"%s\" not found\n"), + v[0]); + } + doneline(input, v); + } +} + +/* from libxcmd/input.c */ + +#if defined(ENABLE_READLINE) +# include +# include +#elif defined(ENABLE_EDITLINE) +# include +#endif + +extern char *progname; + +static char * +get_prompt(void) +{ + static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; + + if (!prompt[0]) + snprintf(prompt, sizeof(prompt), "%s> ", progname); + return prompt; +} + +#if defined(ENABLE_READLINE) +char * +fetchline(void) +{ + char *line; + + line = readline(get_prompt()); + if (line && *line) + add_history(line); + return line; +} +#elif defined(ENABLE_EDITLINE) +static char *el_get_prompt(EditLine *e) { return get_prompt(); } +char * +fetchline(void) +{ + static EditLine *el; + static History *hist; + HistEvent hevent; + char *line; + int count; + + if (!el) { + hist = history_init(); + history(hist, &hevent, H_SETSIZE, 100); + el = el_init(progname, stdin, stdout, stderr); + el_source(el, NULL); + el_set(el, EL_SIGNAL, 1); + el_set(el, EL_PROMPT, el_get_prompt); + el_set(el, EL_HIST, history, (const char *)hist); + } + line = strdup(el_gets(el, &count)); + if (line) { + if (count > 0) + line[count-1] = '\0'; + if (*line) + history(hist, &hevent, H_ENTER, line); + } + return line; +} +#else +# define MAXREADLINESZ 1024 +char * +fetchline(void) +{ + char *p, *line = malloc(MAXREADLINESZ); + + if (!line) + return NULL; + printf("%s", get_prompt()); + fflush(stdout); + if (!fgets(line, MAXREADLINESZ, stdin)) { + free(line); + return NULL; + } + p = line + strlen(line); + if (p != line && p[-1] == '\n') + p[-1] = '\0'; + return line; +} +#endif + +char ** +breakline( + char *input, + int *count) +{ + int c = 0; + char *p; + char **rval = calloc(sizeof(char *), 1); + + while (rval && (p = strsep(&input, " ")) != NULL) { + if (!*p) + continue; + c++; + rval = realloc(rval, sizeof(*rval) * (c + 1)); + if (!rval) { + c = 0; + break; + } + rval[c - 1] = p; + rval[c] = NULL; + } + *count = c; + return rval; +} + +void +doneline( + char *input, + char **vec) +{ + free(input); + free(vec); +} + +#define EXABYTES(x) ((long long)(x) << 60) +#define PETABYTES(x) ((long long)(x) << 50) +#define TERABYTES(x) ((long long)(x) << 40) +#define GIGABYTES(x) ((long long)(x) << 30) +#define MEGABYTES(x) ((long long)(x) << 20) +#define KILOBYTES(x) ((long long)(x) << 10) + +long long +cvtnum( + char *s) +{ + long long i; + char *sp; + int c; + + i = strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return -1LL; + if (*sp == '\0') + return i; + + if (sp[1] != '\0') + return -1LL; + + c = tolower(*sp); + switch (c) { + default: + return i; + case 'k': + return KILOBYTES(i); + case 'm': + return MEGABYTES(i); + case 'g': + return GIGABYTES(i); + case 't': + return TERABYTES(i); + case 'p': + return PETABYTES(i); + case 'e': + return EXABYTES(i); + } + return -1LL; +} + +#define TO_EXABYTES(x) ((x) / EXABYTES(1)) +#define TO_PETABYTES(x) ((x) / PETABYTES(1)) +#define TO_TERABYTES(x) ((x) / TERABYTES(1)) +#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) +#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) +#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) + +void +cvtstr( + double value, + char *str, + size_t size) +{ + const char *fmt; + int precise; + + precise = ((double)value * 1000 == (double)(int)value * 1000); + + if (value >= EXABYTES(1)) { + fmt = precise ? "%.f EiB" : "%.3f EiB"; + snprintf(str, size, fmt, TO_EXABYTES(value)); + } else if (value >= PETABYTES(1)) { + fmt = precise ? "%.f PiB" : "%.3f PiB"; + snprintf(str, size, fmt, TO_PETABYTES(value)); + } else if (value >= TERABYTES(1)) { + fmt = precise ? "%.f TiB" : "%.3f TiB"; + snprintf(str, size, fmt, TO_TERABYTES(value)); + } else if (value >= GIGABYTES(1)) { + fmt = precise ? "%.f GiB" : "%.3f GiB"; + snprintf(str, size, fmt, TO_GIGABYTES(value)); + } else if (value >= MEGABYTES(1)) { + fmt = precise ? "%.f MiB" : "%.3f MiB"; + snprintf(str, size, fmt, TO_MEGABYTES(value)); + } else if (value >= KILOBYTES(1)) { + fmt = precise ? "%.f KiB" : "%.3f KiB"; + snprintf(str, size, fmt, TO_KILOBYTES(value)); + } else { + snprintf(str, size, "%f bytes", value); + } +} + +struct timeval +tsub(struct timeval t1, struct timeval t2) +{ + t1.tv_usec -= t2.tv_usec; + if (t1.tv_usec < 0) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + t1.tv_sec -= t2.tv_sec; + return t1; +} + +double +tdiv(double value, struct timeval tv) +{ + return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); +} + +#define HOURS(sec) ((sec) / (60 * 60)) +#define MINUTES(sec) (((sec) % (60 * 60)) / 60) +#define SECONDS(sec) ((sec) % 60) + +void +timestr( + struct timeval *tv, + char *ts, + size_t size, + int format) +{ + double usec = (double)tv->tv_usec / 1000000.0; + + if (format & TERSE_FIXED_TIME) { + if (!HOURS(tv->tv_sec)) { + snprintf(ts, size, "%u:%02u.%02u", + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) usec * 100); + return; + } + format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ + } + + if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { + snprintf(ts, size, "%u:%02u:%02u.%02u", + (unsigned int) HOURS(tv->tv_sec), + (unsigned int) MINUTES(tv->tv_sec), + (unsigned int) SECONDS(tv->tv_sec), + (unsigned int) usec * 100); + } else { + snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000); + } +} + + +/* from libxcmd/quit.c */ + +static cmdinfo_t quit_cmd; + +/* ARGSUSED */ +static int +quit_f( + int argc, + char **argv) +{ + return 1; +} + +void +quit_init(void) +{ + quit_cmd.name = _("quit"); + quit_cmd.altname = _("q"); + quit_cmd.cfunc = quit_f; + quit_cmd.argmin = -1; + quit_cmd.argmax = -1; + quit_cmd.flags = CMD_FLAG_GLOBAL; + quit_cmd.oneline = _("exit the program"); + + add_command(&quit_cmd); +} + +/* from libxcmd/help.c */ + +static cmdinfo_t help_cmd; +static void help_onecmd(const char *cmd, const cmdinfo_t *ct); +static void help_oneline(const char *cmd, const cmdinfo_t *ct); + +static void +help_all(void) +{ + const cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) + help_oneline(ct->name, ct); + printf(_("\nUse 'help commandname' for extended help.\n")); +} + +static int +help_f( + int argc, + char **argv) +{ + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); + return 0; + } + ct = find_command(argv[1]); + if (ct == NULL) { + printf(_("command %s not found\n"), argv[1]); + return 0; + } + help_onecmd(argv[1], ct); + return 0; +} + +static void +help_onecmd( + const char *cmd, + const cmdinfo_t *ct) +{ + help_oneline(cmd, ct); + if (ct->help) + ct->help(); +} + +static void +help_oneline( + const char *cmd, + const cmdinfo_t *ct) +{ + if (cmd) + printf("%s ", cmd); + else { + printf("%s ", ct->name); + if (ct->altname) + printf("(or %s) ", ct->altname); + } + if (ct->args) + printf("%s ", ct->args); + printf("-- %s\n", ct->oneline); +} + +void +help_init(void) +{ + help_cmd.name = _("help"); + help_cmd.altname = _("?"); + help_cmd.cfunc = help_f; + help_cmd.argmin = 0; + help_cmd.argmax = 1; + help_cmd.flags = CMD_FLAG_GLOBAL; + help_cmd.args = _("[command]"); + help_cmd.oneline = _("help for one or all commands"); + + add_command(&help_cmd); +} diff --git a/cmd.h b/cmd.h new file mode 100644 index 000000000..5ca8fcf07 --- /dev/null +++ b/cmd.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ + +typedef int (*cfunc_t)(int argc, char **argv); +typedef void (*helpfunc_t)(void); + +typedef struct cmdinfo { + const char *name; + const char *altname; + cfunc_t cfunc; + int argmin; + int argmax; + int canpush; + int flags; + const char *args; + const char *oneline; + helpfunc_t help; +} cmdinfo_t; + +extern cmdinfo_t *cmdtab; +extern int ncmds; + +extern void help_init(void); +extern void quit_init(void); + +typedef int (*argsfunc_t)(int index); +typedef int (*checkfunc_t)(const cmdinfo_t *ci); + +extern void add_command(const cmdinfo_t *ci); +extern void add_user_command(char *optarg); +extern void add_args_command(argsfunc_t af); +extern void add_check_command(checkfunc_t cf); + +extern const cmdinfo_t *find_command(const char *cmd); + +extern void command_loop(void); +extern int command_usage(const cmdinfo_t *ci); +extern int command(const cmdinfo_t *ci, int argc, char **argv); + +/* from input.h */ +extern char **breakline(char *input, int *count); +extern void doneline(char *input, char **vec); +extern char *fetchline(void); + +extern long long cvtnum(char *s); +extern void cvtstr(double value, char *str, size_t sz); + +extern struct timeval tsub(struct timeval t1, struct timeval t2); +extern double tdiv(double value, struct timeval tv); + +enum { + DEFAULT_TIME = 0x0, + TERSE_FIXED_TIME = 0x1, + VERBOSE_FIXED_TIME = 0x2 +}; + +extern void timestr(struct timeval *tv, char *str, size_t sz, int flags); + +#endif /* __COMMAND_H__ */ diff --git a/qemu-io.c b/qemu-io.c new file mode 100644 index 000000000..466d22cb3 --- /dev/null +++ b/qemu-io.c @@ -0,0 +1,1074 @@ +/* + * Command line utility to exercise the QEMU I/O path. + * + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (c) 2003-2005 Silicon Graphics, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include +#include +#include +#include + +#include "qemu-common.h" +#include "block_int.h" +#include "cmd.h" + +#define VERSION "0.0.1" + +#define CMD_NOFILE_OK 0x01 + +char *progname; +static BlockDriverState *bs; + +static int misalign; + +/* + * Memory allocation helpers. + * + * Make sure memory is aligned by default, or purposefully misaligned if + * that is specified on the command line. + */ + +#define MISALIGN_OFFSET 16 +static void *qemu_io_alloc(size_t len, int pattern) +{ + void *buf; + + if (misalign) + len += MISALIGN_OFFSET; + buf = qemu_memalign(512, len); + memset(buf, pattern, len); + if (misalign) + buf += MISALIGN_OFFSET; + return buf; +} + +static void qemu_io_free(void *p) +{ + if (misalign) + p -= MISALIGN_OFFSET; + qemu_vfree(p); +} + +static void +dump_buffer(char *buffer, int64_t offset, int len) +{ + int i, j; + char *p; + + for (i = 0, p = buffer; i < len; i += 16) { + char *s = p; + + printf("%08llx: ", (unsigned long long)offset + i); + for (j = 0; j < 16 && i + j < len; j++, p++) + printf("%02x ", *p); + printf(" "); + for (j = 0; j < 16 && i + j < len; j++, s++) { + if (isalnum((int)*s)) + printf("%c", *s); + else + printf("."); + } + printf("\n"); + } +} + +static void +print_report(const char *op, struct timeval *t, int64_t offset, + int count, int total, int cnt, int Cflag) +{ + char s1[64], s2[64], ts[64]; + + timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); + if (!Cflag) { + cvtstr((double)total, s1, sizeof(s1)); + cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); + printf("%s %d/%d bytes at offset %lld\n", + op, total, count, (long long)offset); + printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", + s1, cnt, ts, s2, tdiv((double)cnt, *t)); + } else {/* bytes,ops,time,bytes/sec,ops/sec */ + printf("%d,%d,%s,%.3f,%.3f\n", + total, cnt, ts, + tdiv((double)total, *t), + tdiv((double)cnt, *t)); + } +} + +static int do_read(char *buf, int64_t offset, int count, int *total) +{ + int ret; + + ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) + return ret; + *total = count; + return 1; +} + +static int do_write(char *buf, int64_t offset, int count, int *total) +{ + int ret; + + ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) + return ret; + *total = count; + return 1; +} + +static int do_pread(char *buf, int64_t offset, int count, int *total) +{ + *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + if (*total < 0) + return *total; + return 1; +} + +static int do_pwrite(char *buf, int64_t offset, int count, int *total) +{ + *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + if (*total < 0) + return *total; + return 1; +} + +#define NOT_DONE 0x7fffffff +static void aio_rw_done(void *opaque, int ret) +{ + *(int *)opaque = ret; +} + +static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) +{ + BlockDriverAIOCB *acb; + int async_ret = NOT_DONE; + + acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); + if (!acb) + return -EIO; + + while (async_ret == NOT_DONE) + qemu_aio_wait(); + + *total = qiov->size; + return async_ret < 0 ? async_ret : 1; +} + +static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) +{ + BlockDriverAIOCB *acb; + int async_ret = NOT_DONE; + + acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, + aio_rw_done, &async_ret); + if (!acb) + return -EIO; + + while (async_ret == NOT_DONE) + qemu_aio_wait(); + + *total = qiov->size >> 9; + return async_ret < 0 ? async_ret : 1; +} + + +static const cmdinfo_t read_cmd; + +static void +read_help(void) +{ + printf( +"\n" +" reads a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" +"\n" +" Reads a segment of the currently open file, optionally dumping it to the\n" +" standard output stream (with -v option) for subsequent inspection.\n" +" -p, -- use bdrv_pread to read the file\n" +" -C, -- report statistics in a machine parsable format\n" +" -v, -- dump buffer to standard output\n" +" -q, -- quite mode, do not show I/O statistics\n" +"\n"); +} + +static int +read_f(int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; + int c, cnt; + char *buf; + int64_t offset; + int count, total; + + while ((c = getopt(argc, argv, "Cpqv")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + return command_usage(&read_cmd); + } + } + + if (optind != argc - 2) + return command_usage(&read_cmd); + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + if (!pflag) + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + return 0; + + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + } + + buf = qemu_io_alloc(count, 0xab); + + gettimeofday(&t1, NULL); + if (pflag) + cnt = do_pread(buf, offset, count, &total); + else + cnt = do_read(buf, offset, count, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("read failed: %s\n", strerror(-cnt)); + return 0; + } + + if (qflag) + return 0; + + if (vflag) + dump_buffer(buf, offset, count); + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("read", &t2, offset, count, total, cnt, Cflag); + + qemu_io_free(buf); + + return 0; +} + +static const cmdinfo_t read_cmd = { + .name = "read", + .altname = "r", + .cfunc = read_f, + .argmin = 2, + .argmax = -1, + .args = "[-aCpqv] off len", + .oneline = "reads a number of bytes at a specified offset", + .help = read_help, +}; + +static const cmdinfo_t readv_cmd; + +static void +readv_help(void) +{ + printf( +"\n" +" reads a range of bytes from the given offset into multiple buffers\n" +"\n" +" Example:\n" +" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" +"\n" +" Reads a segment of the currently open file, optionally dumping it to the\n" +" standard output stream (with -v option) for subsequent inspection.\n" +" Uses multiple iovec buffers if more than one byte range is specified.\n" +" -C, -- report statistics in a machine parsable format\n" +" -v, -- dump buffer to standard output\n" +" -q, -- quite mode, do not show I/O statistics\n" +"\n"); +} + +static int +readv_f(int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0, vflag = 0; + int c, cnt; + char *buf, *p; + int64_t offset; + int count = 0, total; + int nr_iov, i; + QEMUIOVector qiov; + + while ((c = getopt(argc, argv, "Cqv")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + return command_usage(&readv_cmd); + } + } + + if (optind > argc - 2) + return command_usage(&readv_cmd); + + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + optind++; + + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + return 0; + } + + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + + for (i = optind; i < argc; i++) { + size_t len; + + len = cvtnum(argv[i]); + if (len < 0) { + printf("non-numeric length argument -- %s\n", argv[i]); + return 0; + } + count += len; + } + + nr_iov = argc - optind; + qemu_iovec_init(&qiov, nr_iov); + buf = p = qemu_io_alloc(count, 0xab); + for (i = 0; i < nr_iov; i++) { + size_t len; + + len = cvtnum(argv[optind]); + if (len < 0) { + printf("non-numeric length argument -- %s\n", + argv[optind]); + return 0; + } + + qemu_iovec_add(&qiov, p, len); + p += len; + optind++; + } + + gettimeofday(&t1, NULL); + cnt = do_aio_readv(&qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("readv failed: %s\n", strerror(-cnt)); + return 0; + } + + if (qflag) + return 0; + + if (vflag) + dump_buffer(buf, offset, qiov.size); + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); + + qemu_io_free(buf); + + return 0; +} + +static const cmdinfo_t readv_cmd = { + .name = "readv", + .cfunc = readv_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cqv] off len [len..]", + .oneline = "reads a number of bytes at a specified offset", + .help = readv_help, +}; + +static const cmdinfo_t write_cmd; + +static void +write_help(void) +{ + printf( +"\n" +" writes a range of bytes from the given offset\n" +"\n" +" Example:\n" +" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd).\n" +" -p, -- use bdrv_pwrite to write the file\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quite mode, do not show I/O statistics\n" +"\n"); +} + +static int +write_f(int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0; + int c, cnt; + char *buf; + int64_t offset; + int count, total; + int pattern = 0xcd; + + while ((c = getopt(argc, argv, "CpP:q")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'P': + pattern = atoi(optarg); + break; + case 'q': + qflag = 1; + break; + default: + return command_usage(&write_cmd); + } + } + + if (optind != argc - 2) + return command_usage(&write_cmd); + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + + if (!pflag) { + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + return 0; + } + + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + } + + buf = qemu_io_alloc(count, pattern); + + gettimeofday(&t1, NULL); + if (pflag) + cnt = do_pwrite(buf, offset, count, &total); + else + cnt = do_write(buf, offset, count, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("write failed: %s\n", strerror(-cnt)); + return 0; + } + + if (qflag) + return 0; + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("wrote", &t2, offset, count, total, cnt, Cflag); + + qemu_io_free(buf); + + return 0; +} + +static const cmdinfo_t write_cmd = { + .name = "write", + .altname = "w", + .cfunc = write_f, + .argmin = 2, + .argmax = -1, + .args = "[-aCpq] [-P pattern ] off len", + .oneline = "writes a number of bytes at a specified offset", + .help = write_help, +}; + +static const cmdinfo_t writev_cmd; + +static void +writev_help(void) +{ + printf( +"\n" +" writes a range of bytes from the given offset source from multiple buffers\n" +"\n" +" Example:\n" +" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +"\n" +" Writes into a segment of the currently open file, using a buffer\n" +" filled with a set pattern (0xcdcdcdcd).\n" +" -P, -- use different pattern to fill file\n" +" -C, -- report statistics in a machine parsable format\n" +" -q, -- quite mode, do not show I/O statistics\n" +"\n"); +} + +static int +writev_f(int argc, char **argv) +{ + struct timeval t1, t2; + int Cflag = 0, qflag = 0; + int c, cnt; + char *buf, *p; + int64_t offset; + int count = 0, total; + int nr_iov, i; + int pattern = 0xcd; + QEMUIOVector qiov; + + while ((c = getopt(argc, argv, "CqP:")) != EOF) { + switch (c) { + case 'C': + Cflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'P': + pattern = atoi(optarg); + break; + default: + return command_usage(&writev_cmd); + } + } + + if (optind > argc - 2) + return command_usage(&writev_cmd); + + offset = cvtnum(argv[optind]); + if (offset < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; + } + optind++; + + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + return 0; + } + + if (count & 0x1ff) { + printf("count %d is not sector aligned\n", + count); + return 0; + } + + + for (i = optind; i < argc; i++) { + size_t len; + + len = cvtnum(argv[optind]); + if (len < 0) { + printf("non-numeric length argument -- %s\n", argv[i]); + return 0; + } + count += len; + } + + nr_iov = argc - optind; + qemu_iovec_init(&qiov, nr_iov); + buf = p = qemu_io_alloc(count, 0xab); + for (i = 0; i < nr_iov; i++) { + size_t len; + + len = cvtnum(argv[optind]); + if (len < 0) { + printf("non-numeric length argument -- %s\n", + argv[optind]); + return 0; + } + + qemu_iovec_add(&qiov, p, len); + p += len; + optind++; + } + + gettimeofday(&t1, NULL); + cnt = do_aio_writev(&qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { + printf("writev failed: %s\n", strerror(-cnt)); + return 0; + } + + if (qflag) + return 0; + + /* Finally, report back -- -C gives a parsable format */ + t2 = tsub(t2, t1); + print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); + + qemu_io_free(buf); + + return 0; +} + +static const cmdinfo_t writev_cmd = { + .name = "writev", + .cfunc = writev_f, + .argmin = 2, + .argmax = -1, + .args = "[-Cq] [-P pattern ] off len [len..]", + .oneline = "writes a number of bytes at a specified offset", + .help = writev_help, +}; + +static int +flush_f(int argc, char **argv) +{ + bdrv_flush(bs); + return 0; +} + +static const cmdinfo_t flush_cmd = { + .name = "flush", + .altname = "f", + .cfunc = flush_f, + .oneline = "flush all in-core file state to disk", +}; + +static int +truncate_f(int argc, char **argv) +{ + int64_t offset; + int ret; + + offset = cvtnum(argv[1]); + if (offset < 0) { + printf("non-numeric truncate argument -- %s\n", argv[1]); + return 0; + } + + ret = bdrv_truncate(bs, offset); + if (ret < 0) { + printf("truncate: %s", strerror(ret)); + return 0; + } + + return 0; +} + +static const cmdinfo_t truncate_cmd = { + .name = "truncate", + .altname = "t", + .cfunc = truncate_f, + .argmin = 1, + .argmax = 1, + .args = "off", + .oneline = "truncates the current file at the given offset", +}; + +static int +length_f(int argc, char **argv) +{ + int64_t size; + char s1[64]; + + size = bdrv_getlength(bs); + if (size < 0) { + printf("getlength: %s", strerror(size)); + return 0; + } + + cvtstr(size, s1, sizeof(s1)); + printf("%s\n", s1); + return 0; +} + + +static const cmdinfo_t length_cmd = { + .name = "length", + .altname = "l", + .cfunc = length_f, + .oneline = "gets the length of the current file", +}; + + +static int +info_f(int argc, char **argv) +{ + BlockDriverInfo bdi; + char s1[64], s2[64]; + int ret; + + if (bs->drv && bs->drv->format_name) + printf("format name: %s\n", bs->drv->format_name); + if (bs->drv && bs->drv->protocol_name) + printf("format name: %s\n", bs->drv->protocol_name); + + ret = bdrv_get_info(bs, &bdi); + if (ret) + return 0; + + cvtstr(bdi.cluster_size, s1, sizeof(s1)); + cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); + + printf("cluster size: %s\n", s1); + printf("vm state offset: %s\n", s2); + + return 0; +} + + + +static const cmdinfo_t info_cmd = { + .name = "info", + .altname = "i", + .cfunc = info_f, + .oneline = "prints information about the current file", +}; + +static int +alloc_f(int argc, char **argv) +{ + int64_t offset; + int nb_sectors; + char s1[64]; + int num; + int ret; + + offset = cvtnum(argv[1]); + if (offset & 0x1ff) { + printf("offset %lld is not sector aligned\n", + (long long)offset); + return 0; + } + + if (argc == 3) + nb_sectors = cvtnum(argv[2]); + else + nb_sectors = 1; + + ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num); + if (ret) { + printf("is_allocated: %s", strerror(ret)); + return 0; + } + + cvtstr(offset, s1, sizeof(s1)); + + if (nb_sectors == 1) + printf("sector allocated at offset %s\n", s1); + else + printf("%d/%d sectors allocated at offset %s\n", + num, nb_sectors, s1); + return 0; +} + +static const cmdinfo_t alloc_cmd = { + .name = "alloc", + .altname = "a", + .argmin = 1, + .argmax = 2, + .cfunc = alloc_f, + .args = "off [sectors]", + .oneline = "checks if a sector is present in the file", +}; + +static int +close_f(int argc, char **argv) +{ + bdrv_close(bs); + bs = NULL; + return 0; +} + +static const cmdinfo_t close_cmd = { + .name = "close", + .altname = "c", + .cfunc = close_f, + .oneline = "close the current open file", +}; + +static int openfile(char *name, int flags) +{ + if (bs) { + fprintf(stderr, "file open already, try 'help close'\n"); + return 1; + } + + bs = bdrv_new("hda"); + if (!bs) + return 1; + + if (bdrv_open(bs, name, flags) == -1) { + fprintf(stderr, "%s: can't open device %s\n", progname, name); + bs = NULL; + return 1; + } + + return 0; +} + +static void +open_help(void) +{ + printf( +"\n" +" opens a new file in the requested mode\n" +"\n" +" Example:\n" +" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" +"\n" +" Opens a file for subsequent use by all of the other qemu-io commands.\n" +" -C, -- create new file if it doesn't exist\n" +" -r, -- open file read-only\n" +" -s, -- use snapshot file\n" +" -n, -- disable host cache\n" +"\n"); +} + +static const cmdinfo_t open_cmd; + +static int +open_f(int argc, char **argv) +{ + int flags = 0; + int readonly = 0; + int c; + + while ((c = getopt(argc, argv, "snCr")) != EOF) { + switch (c) { + case 's': + flags |= BDRV_O_SNAPSHOT; + break; + case 'n': + flags |= BDRV_O_NOCACHE; + break; + case 'C': + flags |= BDRV_O_CREAT; + break; + case 'r': + readonly = 1; + break; + default: + return command_usage(&open_cmd); + } + } + + if (readonly) + flags |= BDRV_O_RDONLY; + else + flags |= BDRV_O_RDWR; + + if (optind != argc - 1) + return command_usage(&open_cmd); + + return openfile(argv[optind], flags); +} + +static const cmdinfo_t open_cmd = { + .name = "open", + .altname = "o", + .cfunc = open_f, + .argmin = 1, + .argmax = -1, + .flags = CMD_NOFILE_OK, + .args = "[-Crsn] [path]", + .oneline = "open the file specified by path", + .help = open_help, +}; + +static int +init_args_command( + int index) +{ + /* only one device allowed so far */ + if (index >= 1) + return 0; + return ++index; +} + +static int +init_check_command( + const cmdinfo_t *ct) +{ + if (ct->flags & CMD_FLAG_GLOBAL) + return 1; + if (!(ct->flags & CMD_NOFILE_OK) && !bs) { + fprintf(stderr, "no file open, try 'help open'\n"); + return 0; + } + return 1; +} + +static void usage(const char *name) +{ + printf( +"Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n" +"QEMU Disk excerciser\n" +"\n" +" -C, --create create new file if it doesn't exist\n" +" -c, --cmd command to execute\n" +" -r, --read-only export read-only\n" +" -s, --snapshot use snapshot file\n" +" -n, --nocache disable host cache\n" +" -m, --misalign misalign allocations for O_DIRECT\n" +" -h, --help display this help and exit\n" +" -V, --version output version information and exit\n" +"\n", + name); +} + + +int main(int argc, char **argv) +{ + int readonly = 0; + const char *sopt = "hVc:Crsnm"; + struct option lopt[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "offset", 1, 0, 'o' }, + { "cmd", 1, 0, 'c' }, + { "create", 0, 0, 'C' }, + { "read-only", 0, 0, 'r' }, + { "snapshot", 0, 0, 's' }, + { "nocache", 0, 0, 'n' }, + { "misalign", 0, 0, 'm' }, + { NULL, 0, 0, 0 } + }; + int c; + int opt_index = 0; + int flags = 0; + + progname = basename(argv[0]); + + while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { + switch (c) { + case 's': + flags |= BDRV_O_SNAPSHOT; + break; + case 'n': + flags |= BDRV_O_NOCACHE; + break; + case 'c': + add_user_command(optarg); + break; + case 'C': + flags |= BDRV_O_CREAT; + break; + case 'r': + readonly = 1; + break; + case 'm': + misalign = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + exit(0); + case 'h': + usage(progname); + exit(0); + default: + usage(progname); + exit(1); + } + } + + if ((argc - optind) > 1) { + usage(progname); + exit(1); + } + + bdrv_init(); + + /* initialize commands */ + quit_init(); + help_init(); + add_command(&open_cmd); + add_command(&close_cmd); + add_command(&read_cmd); + add_command(&readv_cmd); + add_command(&write_cmd); + add_command(&writev_cmd); + add_command(&flush_cmd); + add_command(&truncate_cmd); + add_command(&length_cmd); + add_command(&info_cmd); + add_command(&alloc_cmd); + + add_args_command(init_args_command); + add_check_command(init_check_command); + + /* open the device */ + if (readonly) + flags |= BDRV_O_RDONLY; + else + flags |= BDRV_O_RDWR; + + if ((argc - optind) == 1) + openfile(argv[optind], flags); + command_loop(); + + if (bs) + bdrv_close(bs); + return 0; +} -- cgit v1.2.3 From 3dd1f8ef0fb7f52414acecf15656fca6ced626fd Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:29:26 +0000 Subject: Disable qemu-io on Win32 It breaks the build. Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6996 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index be8e38d5e..15b785604 100755 --- a/configure +++ b/configure @@ -1551,9 +1551,9 @@ esac tools= if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then - tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" + tools="qemu-img\$(EXESUF) $tools" if [ "$linux" = "yes" ] ; then - tools="qemu-nbd\$(EXESUF) $tools" + tools="qemu-nbd\$(EXESUF) qemu-io\$(EXESUF) $tools" fi fi echo "TOOLS=$tools" >> $config_mak -- cgit v1.2.3 From b161d123e77ffbd6ee96edcfb8a02541c5e9439b Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:30:33 +0000 Subject: propagate error on failed completion (Glauber Costa) migrate_fd_put_ready() calls qemu_savevm_state_complete(), but the later can fail. If it happens, re-start the vm and propagate the error up Based on a patch by Yaniv Kamay Signed-off-by: Glauber Costa Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6997 c046a42c-6fe2-441c-8c8c-71466251a162 --- migration.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/migration.c b/migration.c index b3904b2d4..859d94543 100644 --- a/migration.c +++ b/migration.c @@ -220,13 +220,19 @@ void migrate_fd_put_ready(void *opaque) dprintf("iterate\n"); if (qemu_savevm_state_iterate(s->file) == 1) { + int state; dprintf("done iterating\n"); vm_stop(0); bdrv_flush_all(); - qemu_savevm_state_complete(s->file); - s->state = MIG_STATE_COMPLETED; + if ((qemu_savevm_state_complete(s->file)) < 0) { + vm_start(); + state = MIG_STATE_ERROR; + } else { + state = MIG_STATE_COMPLETED; + } migrate_fd_cleanup(s); + s->state = state; } } -- cgit v1.2.3 From 4dabe24883ed9e538266a5deee7e2d1f1922208c Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:30:51 +0000 Subject: create qemu_file_set_error (Glauber Costa) This is mainly for consistency, since we don't want anything outside of savevm setting it explicitly. There are current no users of that in qemu tree, but there are potential candidates on kvm-userspace. And avi is a nice guy, let's be nice with him. Based on a patch by Yaniv Kamay Signed-off-by: Glauber Costa Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6998 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/hw.h | 1 + savevm.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/hw/hw.h b/hw/hw.h index eab7bb4db..e9628d46f 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -67,6 +67,7 @@ unsigned int qemu_get_be32(QEMUFile *f); uint64_t qemu_get_be64(QEMUFile *f); int qemu_file_rate_limit(QEMUFile *f); int qemu_file_has_error(QEMUFile *f); +void qemu_file_set_error(QEMUFile *f); /* Try to send any outstanding data. This function is useful when output is * halted due to rate limiting or EAGAIN errors occur as it can be used to diff --git a/savevm.c b/savevm.c index 793ea7069..70500dd57 100644 --- a/savevm.c +++ b/savevm.c @@ -370,6 +370,11 @@ int qemu_file_has_error(QEMUFile *f) return f->has_error; } +void qemu_file_set_error(QEMUFile *f) +{ + f->has_error = 1; +} + void qemu_fflush(QEMUFile *f) { if (!f->put_buffer) -- cgit v1.2.3 From 8215e91463d9000e782c111b4a8f63c242cd92b6 Mon Sep 17 00:00:00 2001 From: aliguori Date: Sun, 5 Apr 2009 19:30:55 +0000 Subject: stop dirty tracking just at the end of migration (Glauber Costa) If there is still work to do, it is not safe to assume we can end the dirty tracking. Specifically, kvm can update the dirty tracking log inside ram_save_block(), leaving pages still out of sync if we go with the current code. Based on a patch by Yaniv Kamay Signed-off-by: Glauber Costa Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6999 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 1048bd456..b294380a4 100644 --- a/vl.c +++ b/vl.c @@ -3252,10 +3252,10 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) /* try transferring iterative blocks of memory */ if (stage == 3) { - cpu_physical_memory_set_dirty_tracking(0); /* flush all remaining blocks regardless of rate limiting */ while (ram_save_block(f) != 0); + cpu_physical_memory_set_dirty_tracking(0); } qemu_put_be64(f, RAM_SAVE_FLAG_EOS); -- cgit v1.2.3 From 79d342dc6bc04c3bc4c1141760ad6e241059b139 Mon Sep 17 00:00:00 2001 From: aurel32 Date: Sun, 5 Apr 2009 20:08:50 +0000 Subject: tcg/x86_64: optimize register allocation order The beginning of the register allocation order list on the TCG x86_64 target matches the list of clobbered registers. This means that when an helper is called, there is almost always clobbered registers that have to be spilled. The same way register %rsi and %rdi are at the top of the register allocation order list, while they can't be used for load/store operations. This means the data and/or address registers are very often %rsi and %rdi, and their values have to be spilled, and then moved back to another register. This patches changes to the allocation order to avoid those effects. It results in a 8% gain speed in qemu-x86_64 to compress a bzip2 file, and a 6% gain in qemu-system-mips64 to compile a small application. Signed-off-by: Aurelien Jarno git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7003 c046a42c-6fe2-441c-8c8c-71466251a162 --- tcg/x86_64/tcg-target.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c index 92f0733ef..5378e8510 100644 --- a/tcg/x86_64/tcg-target.c +++ b/tcg/x86_64/tcg-target.c @@ -44,22 +44,21 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #endif static const int tcg_target_reg_alloc_order[] = { - TCG_REG_RDI, - TCG_REG_RSI, - TCG_REG_RDX, - TCG_REG_RCX, - TCG_REG_R8, - TCG_REG_R9, - TCG_REG_RAX, - TCG_REG_R10, - TCG_REG_R11, - TCG_REG_RBP, TCG_REG_RBX, TCG_REG_R12, TCG_REG_R13, TCG_REG_R14, TCG_REG_R15, + TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R9, + TCG_REG_R8, + TCG_REG_RCX, + TCG_REG_RDX, + TCG_REG_RSI, + TCG_REG_RDI, + TCG_REG_RAX, }; static const int tcg_target_call_iarg_regs[6] = { -- cgit v1.2.3 From 1b530a6dfcfe4510f66cb90a1717698063ac7a4f Mon Sep 17 00:00:00 2001 From: aurel32 Date: Sun, 5 Apr 2009 20:08:59 +0000 Subject: Add new command line option -singlestep for tcg single stepping. This replaces a compile time option for some targets and adds this feature to targets which did not have a compile time option. Add monitor command to enable or disable single step mode. Modify monitor command "info status" to display single step mode. Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7004 c046a42c-6fe2-441c-8c8c-71466251a162 --- bsd-user/main.c | 5 +++++ darwin-user/main.c | 5 +++++ exec-all.h | 4 ++++ linux-user/main.c | 5 +++++ monitor.c | 23 ++++++++++++++++++++--- qemu-doc.texi | 10 ++++++++++ qemu-options.hx | 7 +++++++ target-alpha/translate.c | 8 ++++---- target-arm/translate.c | 1 + target-cris/translate.c | 1 + target-i386/translate.c | 5 +++++ target-m68k/translate.c | 1 + target-mips/translate.c | 7 +++---- target-ppc/translate.c | 5 +---- target-sh4/translate.c | 5 ++--- target-sparc/translate.c | 2 +- vl.c | 4 ++++ 17 files changed, 79 insertions(+), 19 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 0dc9b996e..34a6b0762 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -33,6 +33,8 @@ #define DEBUG_LOGFILE "/tmp/qemu.log" +int singlestep; + static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; extern char **environ; @@ -378,6 +380,7 @@ static void usage(void) "Debug options:\n" "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" + "-singlestep always run in singlestep mode\n" "-strace log system calls\n" "\n" "Environment variables:\n" @@ -500,6 +503,8 @@ int main(int argc, char **argv) usage(); } optind++; + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; } else diff --git a/darwin-user/main.c b/darwin-user/main.c index 9b8a3dccc..51c6aa0f4 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -41,6 +41,8 @@ #include #include +int singlestep; + const char *interp_prefix = ""; asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); @@ -751,6 +753,7 @@ void usage(void) "-d options activate log (logfile='%s')\n" "-g wait for gdb on port 1234\n" "-p pagesize set the host page size to 'pagesize'\n", + "-singlestep always run in singlestep mode\n" TARGET_ARCH, TARGET_ARCH, interp_prefix, @@ -842,6 +845,8 @@ int main(int argc, char **argv) #endif exit(1); } + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else { usage(); diff --git a/exec-all.h b/exec-all.h index 143aca184..33ccb7b44 100644 --- a/exec-all.h +++ b/exec-all.h @@ -384,4 +384,8 @@ static inline int kqemu_is_ok(CPUState *env) typedef void (CPUDebugExcpHandler)(CPUState *env); CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); + +/* vl.c */ +extern int singlestep; + #endif diff --git a/linux-user/main.c b/linux-user/main.c index feb303617..3b9dfc767 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -39,6 +39,8 @@ char *exec_path; +int singlestep; + static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; @@ -2217,6 +2219,7 @@ static void usage(void) "Debug options:\n" "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" + "-singlestep always run in singlestep mode\n" "-strace log system calls\n" "\n" "Environment variables:\n" @@ -2359,6 +2362,8 @@ int main(int argc, char **argv, char **envp) } } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; } else diff --git a/monitor.c b/monitor.c index 75c8663a1..ca1c11c47 100644 --- a/monitor.c +++ b/monitor.c @@ -527,6 +527,17 @@ static void do_log(Monitor *mon, const char *items) cpu_set_log(mask); } +static void do_singlestep(Monitor *mon, const char *option) +{ + if (!option || !strcmp(option, "on")) { + singlestep = 1; + } else if (!strcmp(option, "off")) { + singlestep = 0; + } else { + monitor_printf(mon, "unexpected option %s\n", option); + } +} + static void do_stop(Monitor *mon) { vm_stop(EXCP_INTERRUPT); @@ -1511,9 +1522,13 @@ static void do_inject_nmi(Monitor *mon, int cpu_index) static void do_info_status(Monitor *mon) { - if (vm_running) - monitor_printf(mon, "VM status: running\n"); - else + if (vm_running) { + if (singlestep) { + monitor_printf(mon, "VM status: running (single step mode)\n"); + } else { + monitor_printf(mon, "VM status: running\n"); + } + } else monitor_printf(mon, "VM status: paused\n"); } @@ -1644,6 +1659,8 @@ static const mon_cmd_t mon_cmds[] = { "tag|id", "restore a VM snapshot from its tag or id" }, { "delvm", "s", do_delvm, "tag|id", "delete a VM snapshot from its tag or id" }, + { "singlestep", "s?", do_singlestep, + "[on|off]", "run emulation in singlestep mode or switch to normal mode", }, { "stop", "", do_stop, "", "stop emulation", }, { "c|cont", "", do_cont, diff --git a/qemu-doc.texi b/qemu-doc.texi index 61a08eeae..3742b4598 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -490,6 +490,10 @@ Set the whole virtual machine to the snapshot identified by the tag @item delvm @var{tag}|@var{id} Delete the snapshot identified by @var{tag} or @var{id}. +@item singlestep [off] +Run the emulation in single step mode. +If called with option off, the emulation returns to normal mode. + @item stop Stop emulation. @@ -2370,6 +2374,8 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @item -g port Wait gdb connection to port +@item -singlestep +Run the emulation in single step mode. @end table Environment variables: @@ -2488,6 +2494,8 @@ Debug options: Activate log (logfile=/tmp/qemu.log) @item -p pagesize Act as if the host page size was 'pagesize' bytes +@item -singlestep +Run the emulation in single step mode. @end table @node BSD User space emulator @@ -2550,6 +2558,8 @@ Debug options: Activate log (logfile=/tmp/qemu.log) @item -p pagesize Act as if the host page size was 'pagesize' bytes +@item -singlestep +Run the emulation in single step mode. @end table @node compilation diff --git a/qemu-options.hx b/qemu-options.hx index 51593a398..4c7012eee 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1209,6 +1209,13 @@ Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. ETEXI +DEF("singlestep", 0, QEMU_OPTION_singlestep, \ + "-singlestep always run in singlestep mode\n") +STEXI +@item -singlestep +Run the emulation in single step mode. +ETEXI + DEF("S", 0, QEMU_OPTION_S, \ "-S freeze CPU at startup (use 'c' to start execution)\n") STEXI diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 6156fb5d0..1e1da542d 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2412,11 +2412,11 @@ static always_inline void gen_intermediate_code_internal (CPUState *env, if (env->singlestep_enabled) { gen_excp(&ctx, EXCP_DEBUG, 0); break; - } + } -#if defined (DO_SINGLE_STEP) - break; -#endif + if (singlestep) { + break; + } } if (ret != 1 && ret != 3) { tcg_gen_movi_i64(cpu_pc, ctx.pc); diff --git a/target-arm/translate.c b/target-arm/translate.c index f7f2a8d6f..9aff6197c 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8791,6 +8791,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, 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); diff --git a/target-cris/translate.c b/target-cris/translate.c index d5fcb9e63..d9256ca42 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3272,6 +3272,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, break; } while (!dc->is_jmp && !dc->cpustate_changed && gen_opc_ptr < gen_opc_end + && !singlestep && (dc->pc < next_page_start) && num_insns < max_insns); diff --git a/target-i386/translate.c b/target-i386/translate.c index cd2e3263e..8df3ea439 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7733,6 +7733,11 @@ static inline void gen_intermediate_code_internal(CPUState *env, gen_eob(dc); break; } + if (singlestep) { + gen_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 4e3cf4aa2..f9b36c963 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3031,6 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, num_insns++; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && + !singlestep && (pc_offset) < (TARGET_PAGE_SIZE - 32) && num_insns < max_insns); diff --git a/target-mips/translate.c b/target-mips/translate.c index 8adc89cff..47a3062f8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -38,7 +38,6 @@ //#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_SIGN_EXTENSIONS -//#define MIPS_SINGLE_STEP /* MIPS major opcodes */ #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) @@ -8140,9 +8139,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (num_insns >= max_insns) break; -#if defined (MIPS_SINGLE_STEP) - break; -#endif + + if (singlestep) + break; } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 870aec5ec..9ba493749 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -39,7 +39,6 @@ #define GDBSTUB_SINGLE_STEP 0x4 /* Include definitions for instructions classes and implementations flags */ -//#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS //#define DO_PPC_STATISTICS @@ -8288,15 +8287,13 @@ static always_inline void gen_intermediate_code_internal (CPUState *env, gen_exception(ctxp, POWERPC_EXCP_TRACE); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (env->singlestep_enabled) || + singlestep || num_insns >= max_insns)) { /* if we reach a page boundary or are single stepping, stop * generation */ break; } -#if defined (DO_SINGLE_STEP) - break; -#endif } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 4ced176b3..aa3b9d439 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1967,9 +1967,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, break; if (num_insns >= max_insns) break; -#ifdef SH4_SINGLE_STEP - break; -#endif + if (singlestep) + break; } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d059408ba..86319a704 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -4838,7 +4838,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, break; /* if single step mode, we generate only one instruction and generate an exception */ - if (env->singlestep_enabled) { + if (env->singlestep_enabled || singlestep) { tcg_gen_movi_tl(cpu_pc, dc->pc); tcg_gen_exit_tb(0); break; diff --git a/vl.c b/vl.c index b294380a4..4bd173f68 100644 --- a/vl.c +++ b/vl.c @@ -236,6 +236,7 @@ int win2k_install_hack = 0; int rtc_td_hack = 0; #endif int usb_enabled = 0; +int singlestep = 0; int smp_cpus = 1; const char *vnc_display; int acpi_enabled = 1; @@ -4660,6 +4661,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_bios: bios_name = optarg; break; + case QEMU_OPTION_singlestep: + singlestep = 1; + break; case QEMU_OPTION_S: autostart = 0; break; -- cgit v1.2.3 From c20d7afb366e5d969858fcdcd4b5d5250fa3be91 Mon Sep 17 00:00:00 2001 From: aliguori Date: Mon, 6 Apr 2009 00:35:08 +0000 Subject: Remove WIN32 guard around -k Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7006 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-options.hx | 2 -- 1 file changed, 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 4c7012eee..c40ea1efc 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -228,10 +228,8 @@ a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or gigabytes respectively. ETEXI -#ifndef _WIN32 DEF("k", HAS_ARG, QEMU_OPTION_k, "-k language use keyboard layout (for example 'fr' for French)\n") -#endif STEXI @item -k @var{language} -- cgit v1.2.3