diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/boot.c | 71 | ||||
-rw-r--r-- | hw/arm/virt.c | 76 | ||||
-rw-r--r-- | hw/block/pflash_cfi01.c | 18 | ||||
-rw-r--r-- | hw/core/loader.c | 21 | ||||
-rw-r--r-- | hw/display/qxl-render.c | 7 | ||||
-rw-r--r-- | hw/display/vga.c | 12 | ||||
-rw-r--r-- | hw/display/vmware_vga.c | 6 | ||||
-rw-r--r-- | hw/display/xenfb.c | 8 | ||||
-rw-r--r-- | hw/gpio/pl061.c | 59 | ||||
-rw-r--r-- | hw/ide/core.c | 111 | ||||
-rw-r--r-- | hw/misc/macio/cuda.c | 23 | ||||
-rw-r--r-- | hw/misc/macio/macio.c | 19 | ||||
-rw-r--r-- | hw/net/spapr_llan.c | 13 | ||||
-rw-r--r-- | hw/nvram/mac_nvram.c | 70 | ||||
-rw-r--r-- | hw/pci-host/apb.c | 15 | ||||
-rw-r--r-- | hw/ppc/mac.h | 4 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 32 | ||||
-rw-r--r-- | hw/ppc/mac_oldworld.c | 20 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 188 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 22 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 61 | ||||
-rw-r--r-- | hw/ppc/spapr_rtas.c | 15 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 6 |
23 files changed, 665 insertions, 212 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index e32f2f4158..c8dc34f086 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -312,7 +312,26 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } } -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) +/** + * load_dtb() - load a device tree binary image into memory + * @addr: the address to load the image at + * @binfo: struct describing the boot environment + * @addr_limit: upper limit of the available memory area at @addr + * + * Load a device tree supplied by the machine or by the user with the + * '-dtb' command line option, and put it at offset @addr in target + * memory. + * + * If @addr_limit contains a meaningful value (i.e., it is strictly greater + * than @addr), the device tree is only loaded if its size does not exceed + * the limit. + * + * Returns: the size of the device tree image on success, + * 0 if the image size exceeds the limit, + * -1 on errors. + */ +static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, + hwaddr addr_limit) { void *fdt = NULL; int size, rc; @@ -341,6 +360,15 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) } } + if (addr_limit > addr && size > (addr_limit - addr)) { + /* Installing the device tree blob at addr would exceed addr_limit. + * Whether this constitutes failure is up to the caller to decide, + * so just return 0 as size, i.e., no error. + */ + g_free(fdt); + return 0; + } + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); if (acells == 0 || scells == 0) { @@ -396,11 +424,14 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) qemu_fdt_dumpdtb(fdt, size); - cpu_physical_memory_write(addr, fdt, size); + /* Put the DTB into the memory map as a ROM image: this will ensure + * the DTB is copied again upon reset, even if addr points into RAM. + */ + rom_add_blob_fixed("dtb", fdt, size, addr); g_free(fdt); - return 0; + return size; fail: g_free(fdt); @@ -451,7 +482,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) int kernel_size; int initrd_size; int is_linux = 0; - uint64_t elf_entry; + uint64_t elf_entry, elf_low_addr, elf_high_addr; int elf_machine; hwaddr entry, kernel_load_offset; int big_endian; @@ -459,6 +490,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) /* Load the kernel. */ if (!info->kernel_filename) { + + if (have_dtb(info)) { + /* If we have a device tree blob, but no kernel to supply it to, + * copy it to the base of RAM for a bootloader to pick up. + */ + if (load_dtb(info->loader_start, info, 0) < 0) { + exit(1); + } + } + /* If no kernel specified, do nothing; we will start from address 0 * (typically a boot ROM image) in the same way as hardware. */ @@ -508,7 +549,25 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, big_endian, elf_machine, 1); + &elf_low_addr, &elf_high_addr, big_endian, + elf_machine, 1); + if (kernel_size > 0 && have_dtb(info)) { + /* If there is still some room left at the base of RAM, try and put + * the DTB there like we do for images loaded with -bios or -pflash. + */ + if (elf_low_addr > info->loader_start + || elf_high_addr < info->loader_start) { + /* Pass elf_low_addr as address limit to load_dtb if it may be + * pointing into RAM, otherwise pass '0' (no limit) + */ + if (elf_low_addr < info->loader_start) { + elf_low_addr = 0; + } + if (load_dtb(info->loader_start, info, elf_low_addr) < 0) { + exit(1); + } + } + } entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uimage(info->kernel_filename, &entry, NULL, @@ -569,7 +628,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) */ hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, 4096); - if (load_dtb(dtb_start, info)) { + if (load_dtb(dtb_start, info, 0) < 0) { exit(1); } fixupcontext[FIXUP_ARGPTR] = dtb_start; diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 89b4ed5281..8c6b171414 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -37,6 +37,7 @@ #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/boards.h" +#include "hw/loader.h" #include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" @@ -371,11 +372,13 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) 2, base, 2, size); qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + GIC_FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks", vbi->clock_phandle, vbi->clock_phandle); qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); + + qemu_fdt_setprop_string(vbi->fdt, "/chosen", "linux,stdout-path", nodename); g_free(nodename); } @@ -396,7 +399,7 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic) 2, base, 2, size); qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + GIC_FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); g_free(nodename); @@ -437,6 +440,73 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) } } +static void create_one_flash(const char *name, hwaddr flashbase, + hwaddr flashsize) +{ + /* Create and map a single flash device. We use the same + * parameters as the flash devices on the Versatile Express board. + */ + DriveInfo *dinfo = drive_get_next(IF_PFLASH); + DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); + const uint64_t sectorlength = 256 * 1024; + + if (dinfo && qdev_prop_set_drive(dev, "drive", dinfo->bdrv)) { + abort(); + } + + qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength); + qdev_prop_set_uint64(dev, "sector-length", sectorlength); + qdev_prop_set_uint8(dev, "width", 4); + qdev_prop_set_uint8(dev, "device-width", 2); + qdev_prop_set_uint8(dev, "big-endian", 0); + qdev_prop_set_uint16(dev, "id0", 0x89); + qdev_prop_set_uint16(dev, "id1", 0x18); + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", name); + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, flashbase); +} + +static void create_flash(const VirtBoardInfo *vbi) +{ + /* Create two flash devices to fill the VIRT_FLASH space in the memmap. + * Any file passed via -bios goes in the first of these. + */ + hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; + char *nodename; + + if (bios_name) { + const char *fn; + + if (drive_get(IF_PFLASH, 0, 0)) { + error_report("The contents of the first flash device may be " + "specified with -bios or with -drive if=pflash... " + "but you cannot use both options at once"); + exit(1); + } + fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!fn || load_image_targphys(fn, flashbase, flashsize) < 0) { + error_report("Could not load ROM image '%s'", bios_name); + exit(1); + } + } + + create_one_flash("virt.flash0", flashbase, flashsize); + create_one_flash("virt.flash1", flashbase + flashsize, flashsize); + + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, flashbase, 2, flashsize, + 2, flashbase + flashsize, 2, flashsize); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + g_free(nodename); +} + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; @@ -515,6 +585,8 @@ static void machvirt_init(MachineState *machine) vmstate_register_ram_global(ram); memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); + create_flash(vbi); + create_gic(vbi, pic); create_uart(vbi, pic); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index e2e0462963..1346541c80 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -94,10 +94,13 @@ struct pflash_t { void *storage; }; +static int pflash_post_load(void *opaque, int version_id); + static const VMStateDescription vmstate_pflash = { .name = "pflash_cfi01", .version_id = 1, .minimum_version_id = 1, + .post_load = pflash_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(wcycle, pflash_t), VMSTATE_UINT8(cmd, pflash_t), @@ -209,11 +212,11 @@ static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset) switch (boff & 0xFF) { case 0: resp = pfl->ident0; - DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret); + DPRINTF("%s: Manufacturer Code %04x\n", __func__, resp); break; case 1: resp = pfl->ident1; - DPRINTF("%s: Device ID Code %04x\n", __func__, ret); + DPRINTF("%s: Device ID Code %04x\n", __func__, resp); break; default: DPRINTF("%s: Read Device Information offset=%x\n", __func__, @@ -988,3 +991,14 @@ MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl) { return &fl->mem; } + +static int pflash_post_load(void *opaque, int version_id) +{ + pflash_t *pfl = opaque; + + if (!pfl->ro) { + DPRINTF("%s: updating bdrv for %s\n", __func__, pfl->name); + pflash_update(pfl, 0, pfl->sector_len * pfl->nb_blocs); + } + return 0; +} diff --git a/hw/core/loader.c b/hw/core/loader.c index 87287b6510..5f3a8598c5 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -89,6 +89,27 @@ int load_image(const char *filename, uint8_t *addr) return size; } +/* return the size or -1 if error */ +ssize_t load_image_size(const char *filename, void *addr, size_t size) +{ + int fd; + ssize_t actsize; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + return -1; + } + + actsize = read(fd, addr, size); + if (actsize < 0) { + close(fd); + return -1; + } + close(fd); + + return actsize; +} + /* read()-like version */ ssize_t read_targphys(const char *name, int fd, hwaddr dst_addr, size_t nbytes) diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index bcc5c3701a..e812ddd6e7 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -116,13 +116,14 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp); if (qxl->guest_primary.qxl_stride > 0) { + pixman_format_code_t format = + qemu_default_pixman_format(qxl->guest_primary.bits_pp, true); surface = qemu_create_displaysurface_from (qxl->guest_primary.surface.width, qxl->guest_primary.surface.height, - qxl->guest_primary.bits_pp, + format, qxl->guest_primary.abs_stride, - qxl->guest_primary.data, - false); + qxl->guest_primary.data); } else { surface = qemu_create_displaysurface (qxl->guest_primary.surface.width, diff --git a/hw/display/vga.c b/hw/display/vga.c index d5f5a013c7..df0c010823 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1725,9 +1725,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) height != s->last_height || s->last_depth != depth) { if (depth == 32 || (depth == 16 && !byteswap)) { + pixman_format_code_t format = + qemu_default_pixman_format(depth, !byteswap); surface = qemu_create_displaysurface_from(disp_width, - height, depth, s->line_offset, - s->vram_ptr + (s->start_addr * 4), byteswap); + height, format, s->line_offset, + s->vram_ptr + (s->start_addr * 4)); dpy_gfx_replace_surface(s->con, surface); } else { qemu_console_resize(s->con, disp_width, height); @@ -1743,9 +1745,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } else if (is_buffer_shared(surface) && (full_update || surface_data(surface) != s->vram_ptr + (s->start_addr * 4))) { + pixman_format_code_t format = + qemu_default_pixman_format(depth, !byteswap); surface = qemu_create_displaysurface_from(disp_width, - height, depth, s->line_offset, - s->vram_ptr + (s->start_addr * 4), byteswap); + height, format, s->line_offset, + s->vram_ptr + (s->start_addr * 4)); dpy_gfx_replace_surface(s->con, surface); } diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 32026e4127..0c36c7204f 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1052,10 +1052,12 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s) s->new_height != surface_height(surface) || s->new_depth != surface_bits_per_pixel(surface)) { int stride = (s->new_depth * s->new_width) / 8; + pixman_format_code_t format = + qemu_default_pixman_format(s->new_depth, true); trace_vmware_setmode(s->new_width, s->new_height, s->new_depth); surface = qemu_create_displaysurface_from(s->new_width, s->new_height, - s->new_depth, stride, - s->vga.vram_ptr, false); + format, stride, + s->vga.vram_ptr); dpy_gfx_replace_surface(s->vga.con, surface); s->invalidated = 1; } diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 07ddc9deba..8a61e959a6 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -713,15 +713,17 @@ static void xenfb_update(void *opaque) /* resize if needed */ if (xenfb->do_resize) { + pixman_format_code_t format; + xenfb->do_resize = 0; switch (xenfb->depth) { case 16: case 32: /* console.c supported depth -> buffer can be used directly */ + format = qemu_default_pixman_format(xenfb->depth, true); surface = qemu_create_displaysurface_from - (xenfb->width, xenfb->height, xenfb->depth, - xenfb->row_stride, xenfb->pixels + xenfb->offset, - false); + (xenfb->width, xenfb->height, format, + xenfb->row_stride, xenfb->pixels + xenfb->offset); break; default: /* we must convert stuff */ diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index dd4ea293e2..bd03e99975 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -37,7 +37,8 @@ typedef struct PL061State { MemoryRegion iomem; uint32_t locked; uint32_t data; - uint32_t old_data; + uint32_t old_out_data; + uint32_t old_in_data; uint32_t dir; uint32_t isense; uint32_t ibe; @@ -63,12 +64,13 @@ typedef struct PL061State { static const VMStateDescription vmstate_pl061 = { .name = "pl061", - .version_id = 2, - .minimum_version_id = 1, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT32(locked, PL061State), VMSTATE_UINT32(data, PL061State), - VMSTATE_UINT32(old_data, PL061State), + VMSTATE_UINT32(old_out_data, PL061State), + VMSTATE_UINT32(old_in_data, PL061State), VMSTATE_UINT32(dir, PL061State), VMSTATE_UINT32(isense, PL061State), VMSTATE_UINT32(ibe, PL061State), @@ -98,23 +100,52 @@ static void pl061_update(PL061State *s) uint8_t out; int i; + DPRINTF("dir = %d, data = %d\n", s->dir, s->data); + /* Outputs float high. */ /* FIXME: This is board dependent. */ out = (s->data & s->dir) | ~s->dir; - changed = s->old_data ^ out; - if (!changed) - return; + changed = s->old_out_data ^ out; + if (changed) { + s->old_out_data = out; + for (i = 0; i < 8; i++) { + mask = 1 << i; + if (changed & mask) { + DPRINTF("Set output %d = %d\n", i, (out & mask) != 0); + qemu_set_irq(s->out[i], (out & mask) != 0); + } + } + } - s->old_data = out; - for (i = 0; i < 8; i++) { - mask = 1 << i; - if (changed & mask) { - DPRINTF("Set output %d = %d\n", i, (out & mask) != 0); - qemu_set_irq(s->out[i], (out & mask) != 0); + /* Inputs */ + changed = (s->old_in_data ^ s->data) & ~s->dir; + if (changed) { + s->old_in_data = s->data; + for (i = 0; i < 8; i++) { + mask = 1 << i; + if (changed & mask) { + DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0); + + if (!(s->isense & mask)) { + /* Edge interrupt */ + if (s->ibe & mask) { + /* Any edge triggers the interrupt */ + s->istate |= mask; + } else { + /* Edge is selected by IEV */ + s->istate |= ~(s->data ^ s->iev) & mask; + } + } + } } } - /* FIXME: Implement input interrupts. */ + /* Level interrupt */ + s->istate |= ~(s->data ^ s->iev) & s->isense; + + DPRINTF("istate = %02X\n", s->istate); + + qemu_set_irq(s->irq, (s->istate & s->im) != 0); } static uint64_t pl061_read(void *opaque, hwaddr offset, diff --git a/hw/ide/core.c b/hw/ide/core.c index b48127f921..191f89321e 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -75,19 +75,29 @@ static void put_le16(uint16_t *p, unsigned int v) *p = cpu_to_le16(v); } +static void ide_identify_size(IDEState *s) +{ + uint16_t *p = (uint16_t *)s->identify_data; + put_le16(p + 60, s->nb_sectors); + put_le16(p + 61, s->nb_sectors >> 16); + put_le16(p + 100, s->nb_sectors); + put_le16(p + 101, s->nb_sectors >> 16); + put_le16(p + 102, s->nb_sectors >> 32); + put_le16(p + 103, s->nb_sectors >> 48); +} + static void ide_identify(IDEState *s) { uint16_t *p; unsigned int oldsize; IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master; + p = (uint16_t *)s->identify_data; if (s->identify_set) { - memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); - return; + goto fill_buffer; } + memset(p, 0, sizeof(s->identify_data)); - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; put_le16(p + 0, 0x0040); put_le16(p + 1, s->cylinders); put_le16(p + 3, s->heads); @@ -116,8 +126,8 @@ static void ide_identify(IDEState *s) put_le16(p + 58, oldsize >> 16); if (s->mult_sectors) put_le16(p + 59, 0x100 | s->mult_sectors); - put_le16(p + 60, s->nb_sectors); - put_le16(p + 61, s->nb_sectors >> 16); + /* *(p + 60) := nb_sectors -- see ide_identify_size */ + /* *(p + 61) := nb_sectors >> 16 -- see ide_identify_size */ put_le16(p + 62, 0x07); /* single word dma0-2 supported */ put_le16(p + 63, 0x07); /* mdma0-2 supported */ put_le16(p + 64, 0x03); /* pio3-4 supported */ @@ -162,10 +172,10 @@ static void ide_identify(IDEState *s) } put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ put_le16(p + 93, 1 | (1 << 14) | 0x2000); - put_le16(p + 100, s->nb_sectors); - put_le16(p + 101, s->nb_sectors >> 16); - put_le16(p + 102, s->nb_sectors >> 32); - put_le16(p + 103, s->nb_sectors >> 48); + /* *(p + 100) := nb_sectors -- see ide_identify_size */ + /* *(p + 101) := nb_sectors >> 16 -- see ide_identify_size */ + /* *(p + 102) := nb_sectors >> 32 -- see ide_identify_size */ + /* *(p + 103) := nb_sectors >> 48 -- see ide_identify_size */ if (dev && dev->conf.physical_block_size) put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf)); @@ -180,21 +190,23 @@ static void ide_identify(IDEState *s) put_le16(p + 169, 1); /* TRIM support */ } - memcpy(s->identify_data, p, sizeof(s->identify_data)); + ide_identify_size(s); s->identify_set = 1; + +fill_buffer: + memcpy(s->io_buffer, p, sizeof(s->identify_data)); } static void ide_atapi_identify(IDEState *s) { uint16_t *p; + p = (uint16_t *)s->identify_data; if (s->identify_set) { - memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); - return; + goto fill_buffer; } + memset(p, 0, sizeof(s->identify_data)); - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ @@ -230,11 +242,36 @@ static void ide_atapi_identify(IDEState *s) } put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ + if (s->wwn) { + put_le16(p + 84, (1 << 8)); /* supports WWN for words 108-111 */ + put_le16(p + 87, (1 << 8)); /* WWN enabled */ + } + #ifdef USE_DMA_CDROM put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ #endif - memcpy(s->identify_data, p, sizeof(s->identify_data)); + + if (s->wwn) { + /* LE 16-bit words 111-108 contain 64-bit World Wide Name */ + put_le16(p + 108, s->wwn >> 48); + put_le16(p + 109, s->wwn >> 32); + put_le16(p + 110, s->wwn >> 16); + put_le16(p + 111, s->wwn); + } + s->identify_set = 1; + +fill_buffer: + memcpy(s->io_buffer, p, sizeof(s->identify_data)); +} + +static void ide_cfata_identify_size(IDEState *s) +{ + uint16_t *p = (uint16_t *)s->identify_data; + put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ + put_le16(p + 8, s->nb_sectors); /* Sectors per card */ + put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */ + put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */ } static void ide_cfata_identify(IDEState *s) @@ -242,10 +279,10 @@ static void ide_cfata_identify(IDEState *s) uint16_t *p; uint32_t cur_sec; - p = (uint16_t *) s->identify_data; - if (s->identify_set) + p = (uint16_t *)s->identify_data; + if (s->identify_set) { goto fill_buffer; - + } memset(p, 0, sizeof(s->identify_data)); cur_sec = s->cylinders * s->heads * s->sectors; @@ -254,8 +291,8 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 1, s->cylinders); /* Default cylinders */ put_le16(p + 3, s->heads); /* Default heads */ put_le16(p + 6, s->sectors); /* Default sectors per track */ - put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ - put_le16(p + 8, s->nb_sectors); /* Sectors per card */ + /* *(p + 7) := nb_sectors >> 16 -- see ide_cfata_identify_size */ + /* *(p + 8) := nb_sectors -- see ide_cfata_identify_size */ padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ put_le16(p + 22, 0x0004); /* ECC bytes */ padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */ @@ -276,8 +313,8 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 58, cur_sec >> 16); /* Current capacity */ if (s->mult_sectors) /* Multiple sector setting */ put_le16(p + 59, 0x100 | s->mult_sectors); - put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */ - put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */ + /* *(p + 60) := nb_sectors -- see ide_cfata_identify_size */ + /* *(p + 61) := nb_sectors >> 16 -- see ide_cfata_identify_size */ put_le16(p + 63, 0x0203); /* Multiword DMA capability */ put_le16(p + 64, 0x0001); /* Flow Control PIO support */ put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */ @@ -297,6 +334,7 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 160, 0x8100); /* Power requirement */ put_le16(p + 161, 0x8001); /* CF command set */ + ide_cfata_identify_size(s); s->identify_set = 1; fill_buffer: @@ -2115,6 +2153,28 @@ static bool ide_cd_is_medium_locked(void *opaque) return ((IDEState *)opaque)->tray_locked; } +static void ide_resize_cb(void *opaque) +{ + IDEState *s = opaque; + uint64_t nb_sectors; + + if (!s->identify_set) { + return; + } + + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; + + /* Update the identify data buffer. */ + if (s->drive_kind == IDE_CFATA) { + ide_cfata_identify_size(s); + } else { + /* IDE_CD uses a different set of callbacks entirely. */ + assert(s->drive_kind != IDE_CD); + ide_identify_size(s); + } +} + static const BlockDevOps ide_cd_block_ops = { .change_media_cb = ide_cd_change_cb, .eject_request_cb = ide_cd_eject_request_cb, @@ -2122,6 +2182,10 @@ static const BlockDevOps ide_cd_block_ops = { .is_medium_locked = ide_cd_is_medium_locked, }; +static const BlockDevOps ide_hd_block_ops = { + .resize_cb = ide_resize_cb, +}; + int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, const char *version, const char *serial, const char *model, uint64_t wwn, @@ -2158,6 +2222,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, error_report("Can't use a read-only drive"); return -1; } + bdrv_set_dev_ops(bs, &ide_hd_block_ops, s); } if (serial) { pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), serial); diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index ff6051defe..b4273aa171 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -123,13 +123,22 @@ static void cuda_update_irq(CUDAState *s) } } +static uint64_t get_tb(uint64_t freq) +{ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + freq, get_ticks_per_sec()); +} + static unsigned int get_counter(CUDATimer *s) { int64_t d; unsigned int counter; + uint64_t tb_diff; + + /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */ + tb_diff = get_tb(s->frequency) - s->load_time; + d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24); - d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->load_time, - CUDA_TIMER_FREQ, get_ticks_per_sec()); if (s->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { @@ -147,7 +156,7 @@ static unsigned int get_counter(CUDATimer *s) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); - ti->load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ti->load_time = get_tb(s->frequency); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time); } @@ -688,6 +697,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp) struct tm tm; s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s); + s->timers[0].frequency = s->frequency; + s->timers[1].frequency = s->frequency; qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; @@ -713,6 +724,11 @@ static void cuda_initfn(Object *obj) DEVICE(obj), "adb.0"); } +static Property cuda_properties[] = { + DEFINE_PROP_UINT64("frequency", CUDAState, frequency, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void cuda_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -720,6 +736,7 @@ static void cuda_class_init(ObjectClass *oc, void *data) dc->realize = cuda_realizefn; dc->reset = cuda_reset; dc->vmsd = &vmstate_cuda; + dc->props = cuda_properties; } static const TypeInfo cuda_type_info = { diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 47f45f5d2c..e0f1e88f54 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -42,6 +42,7 @@ typedef struct MacIOState void *dbdma; MemoryRegion *pic_mem; MemoryRegion *escc_mem; + uint64_t frequency; } MacIOState; #define OLDWORLD_MACIO(obj) \ @@ -243,13 +244,18 @@ static void timer_write(void *opaque, hwaddr addr, uint64_t value, static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) { uint32_t value = 0; + uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint64_t kltime; + + kltime = muldiv64(systime, 4194300, get_ticks_per_sec() * 4); + kltime = muldiv64(kltime, 18432000, 1048575); switch (addr) { case 0x38: - value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + value = kltime; break; case 0x3c: - value = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 32; + value = kltime >> 32; break; } @@ -346,12 +352,19 @@ static void macio_newworld_class_init(ObjectClass *oc, void *data) pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; } +static Property macio_properties[] = { + DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void macio_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->vendor_id = PCI_VENDOR_ID_APPLE; k->class_id = PCI_CLASS_OTHERS << 8; + dc->props = macio_properties; } static const TypeInfo macio_oldworld_type_info = { @@ -398,6 +411,8 @@ void macio_init(PCIDevice *d, macio_state->escc_mem = escc_mem; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ + qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency", + macio_state->frequency); qdev_init_nofail(DEVICE(d)); } diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 2d47df6930..23c47d397c 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -72,7 +72,14 @@ typedef uint64_t vlan_bd_t; #define VLAN_RXQ_BD_OFF 0 #define VLAN_FILTER_BD_OFF 8 #define VLAN_RX_BDS_OFF 16 -#define VLAN_MAX_BUFS ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8) +/* + * The final 8 bytes of the buffer list is a counter of frames dropped + * because there was not a buffer in the buffer list capable of holding + * the frame. We must avoid it, or the operating system will report garbage + * for this statistic. + */ +#define VLAN_RX_BDS_LEN (SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF - 8) +#define VLAN_MAX_BUFS (VLAN_RX_BDS_LEN / 8) #define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan" #define VIO_SPAPR_VLAN_DEVICE(obj) \ @@ -119,7 +126,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, do { buf_ptr += 8; - if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) { + if (buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) { buf_ptr = VLAN_RX_BDS_OFF; } @@ -397,7 +404,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, do { dev->add_buf_ptr += 8; - if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) { + if (dev->add_buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) { dev->add_buf_ptr = VLAN_RX_BDS_OFF; } diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 170b10b766..d35f8a3121 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -26,6 +26,7 @@ #include "hw/nvram/openbios_firmware_abi.h" #include "sysemu/sysemu.h" #include "hw/ppc/mac.h" +#include <zlib.h> /* debug NVR */ //#define DEBUG_NVR @@ -39,29 +40,6 @@ #define DEF_SYSTEM_SIZE 0xc10 -/* Direct access to NVRAM */ -uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr) -{ - uint32_t ret; - - if (addr < s->size) { - ret = s->data[addr]; - } else { - ret = -1; - } - NVR_DPRINTF("read addr %04" PRIx32 " val %" PRIx8 "\n", addr, ret); - - return ret; -} - -void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val) -{ - NVR_DPRINTF("write addr %04" PRIx32 " val %" PRIx8 "\n", addr, val); - if (addr < s->size) { - s->data[addr] = val; - } -} - /* macio style NVRAM device */ static void macio_nvram_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned size) @@ -89,6 +67,10 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, static const MemoryRegionOps macio_nvram_ops = { .read = macio_nvram_readb, .write = macio_nvram_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, .endianness = DEVICE_BIG_ENDIAN, }; @@ -156,15 +138,16 @@ static void macio_nvram_register_types(void) } /* Set up a system OpenBIOS NVRAM partition */ -void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len) +static void pmac_format_nvram_partition_of(MacIONVRAMState *nvr, int off, + int len) { unsigned int i; - uint32_t start = 0, end; + uint32_t start = off, end; struct OpenBIOS_nvpart_v1 *part_header; // OpenBIOS nvram variables // Variable partition - part_header = (struct OpenBIOS_nvpart_v1 *)nvr->data; + part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start]; part_header->signature = OPENBIOS_PART_SYSTEM; pstrcpy(part_header->name, sizeof(part_header->name), "system"); @@ -192,4 +175,39 @@ void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len) OpenBIOS_finish_partition(part_header, end - start); } +#define OSX_NVRAM_SIGNATURE (0x5A) + +/* Set up a Mac OS X NVRAM partition */ +static void pmac_format_nvram_partition_osx(MacIONVRAMState *nvr, int off, + int len) +{ + uint32_t start = off; + struct OpenBIOS_nvpart_v1 *part_header; + unsigned char *data = &nvr->data[start]; + + /* empty partition */ + part_header = (struct OpenBIOS_nvpart_v1 *)data; + part_header->signature = OSX_NVRAM_SIGNATURE; + pstrcpy(part_header->name, sizeof(part_header->name), "wwwwwwwwwwww"); + + OpenBIOS_finish_partition(part_header, len); + + /* Generation */ + stl_be_p(&data[20], 2); + + /* Adler32 checksum */ + stl_be_p(&data[16], adler32(0, &data[20], len - 20)); +} + +/* Set up NVRAM with OF and OSX partitions */ +void pmac_format_nvram_partition(MacIONVRAMState *nvr, int len) +{ + /* + * Mac OS X expects side "B" of the flash at the second half of NVRAM, + * so we use half of the chip for OF and the other half for a free OSX + * partition. + */ + pmac_format_nvram_partition_of(nvr, 0, len / 2); + pmac_format_nvram_partition_osx(nvr, len / 2, len / 2); +} type_init(macio_nvram_register_types) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 762ebdd8fe..f573875baf 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -142,6 +142,7 @@ typedef struct APBState { IOMMUState iommu; uint32_t pci_control[16]; uint32_t pci_irq_map[8]; + uint32_t pci_err_irq_map[4]; uint32_t obio_irq_map[32]; qemu_irq *pbm_irqs; qemu_irq *ivec_irqs; @@ -437,7 +438,7 @@ static void apb_config_writel (void *opaque, hwaddr addr, pbm_check_irqs(s); } break; - case 0x1000 ... 0x1080: /* OBIO interrupt control */ + case 0x1000 ... 0x107f: /* OBIO interrupt control */ if (addr & 4) { unsigned int ino = ((addr & 0xff) >> 3); s->obio_irq_map[ino] &= PBM_PCI_IMR_MASK; @@ -515,13 +516,20 @@ static uint64_t apb_config_readl (void *opaque, val = 0; } break; - case 0x1000 ... 0x1080: /* OBIO interrupt control */ + case 0x1000 ... 0x107f: /* OBIO interrupt control */ if (addr & 4) { val = s->obio_irq_map[(addr & 0xff) >> 3]; } else { val = 0; } break; + case 0x1080 ... 0x108f: /* PCI bus error */ + if (addr & 4) { + val = s->pci_err_irq_map[(addr & 0xf) >> 3]; + } else { + val = 0; + } + break; case 0x2000 ... 0x202f: /* PCI control */ val = s->pci_control[(addr & 0x3f) >> 2]; break; @@ -753,6 +761,9 @@ static int pci_pbm_init_device(SysBusDevice *dev) for (i = 0; i < 8; i++) { s->pci_irq_map[i] = (0x1f << 6) | (i << 2); } + for (i = 0; i < 2; i++) { + s->pci_err_irq_map[i] = (0x1f << 6) | 0x30; + } for (i = 0; i < 32; i++) { s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i; } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index c1faf9ce27..aff2b9a566 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -57,6 +57,7 @@ typedef struct CUDATimer { uint16_t counter_value; int64_t load_time; int64_t next_irq_time; + uint64_t frequency; QEMUTimer *timer; } CUDATimer; @@ -97,6 +98,7 @@ typedef struct CUDAState { CUDATimer timers[2]; uint32_t tick_offset; + uint64_t frequency; uint8_t last_b; uint8_t last_acr; @@ -178,6 +180,4 @@ typedef struct MacIONVRAMState { } MacIONVRAMState; void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); -uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr); -void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val); #endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 7148629a0f..1626db44ef 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -176,6 +176,8 @@ static void ppc_core99_init(MachineState *machine) SysBusDevice *s; DeviceState *dev; int *token = g_new(int, 1); + hwaddr nvram_addr = 0xFFF04000; + uint64_t tbfreq; linux_boot = (kernel_filename != NULL); @@ -373,6 +375,14 @@ static void ppc_core99_init(MachineState *machine) pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io()); machine_arch = ARCH_MAC99; } + + /* Timebase Frequency */ + if (kvm_enabled()) { + tbfreq = kvmppc_get_tbfreq(); + } else { + tbfreq = TBFREQ; + } + /* init basic PC hardware */ escc_mem = escc_init(0, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); @@ -386,6 +396,7 @@ static void ppc_core99_init(MachineState *machine) qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ + qdev_prop_set_uint64(dev, "frequency", tbfreq); macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ @@ -427,11 +438,18 @@ static void ppc_core99_init(MachineState *machine) } /* The NewWorld NVRAM is not located in the MacIO device */ +#ifdef CONFIG_KVM + if (kvm_enabled() && getpagesize() > 4096) { + /* We can't combine read-write and read-only in a single page, so + move the NVRAM out of ROM again for KVM */ + nvram_addr = 0xFFE00000; + } +#endif dev = qdev_create(NULL, TYPE_MACIO_NVRAM); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 1); qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xFFF04000); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, nvram_addr); nvr = MACIO_NVRAM(dev); pmac_format_nvram_partition(nvr, 0x2000); /* No PCI init: the BIOS will do it */ @@ -462,28 +480,34 @@ static void ppc_core99_init(MachineState *machine) #ifdef CONFIG_KVM uint8_t *hypercall; - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); hypercall = g_malloc(16); kvmppc_get_hypercall(env, hypercall, 16); fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq); /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_NVRAM_ADDR, nvram_addr); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } +static int core99_kvm_type(const char *arg) +{ + /* Always force PR KVM */ + return 2; +} + static QEMUMachine core99_machine = { .name = "mac99", .desc = "Mac99 based PowerMAC", .init = ppc_core99_init, .max_cpus = MAX_CPUS, .default_boot_order = "cd", + .kvm_type = core99_kvm_type, }; static void core99_machine_init(void) diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 1c5d9f45ef..be9a194038 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -103,6 +103,7 @@ static void ppc_heathrow_init(MachineState *machine) uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; + uint64_t tbfreq; linux_boot = (kernel_filename != NULL); @@ -251,6 +252,13 @@ static void ppc_heathrow_init(MachineState *machine) } } + /* Timebase Frequency */ + if (kvm_enabled()) { + tbfreq = kvmppc_get_tbfreq(); + } else { + tbfreq = TBFREQ; + } + /* init basic PC hardware */ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { hw_error("Only 6xx bus is supported on heathrow machine\n"); @@ -279,6 +287,7 @@ static void ppc_heathrow_init(MachineState *machine) qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */ qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */ + qdev_prop_set_uint64(dev, "frequency", tbfreq); macio_init(macio, pic_mem, escc_bar); macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), @@ -331,15 +340,13 @@ static void ppc_heathrow_init(MachineState *machine) #ifdef CONFIG_KVM uint8_t *hypercall; - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); hypercall = g_malloc(16); kvmppc_get_hypercall(env, hypercall, 16); fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq); /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); @@ -347,6 +354,12 @@ static void ppc_heathrow_init(MachineState *machine) qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } +static int heathrow_kvm_type(const char *arg) +{ + /* Always force PR KVM */ + return 2; +} + static QEMUMachine heathrow_machine = { .name = "g3beige", .desc = "Heathrow based PowerMAC", @@ -356,6 +369,7 @@ static QEMUMachine heathrow_machine = { .is_default = 1, #endif .default_boot_order = "cd", /* TOFIX "cad" when Mac floppy is implemented */ + .kvm_type = heathrow_kvm_type, }; static void heathrow_machine_init(void) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5cb452f234..2ab4460f04 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -71,6 +71,7 @@ */ #define FDT_MAX_SIZE 0x40000 #define RTAS_MAX_SIZE 0x10000 +#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" #define FW_OVERHEAD 0x2800000 @@ -80,7 +81,7 @@ #define TIMEBASE_FREQ 512000000ULL -#define MAX_CPUS 256 +#define MAX_CPUS 255 #define PHANDLE_XICP 0x00001111 @@ -283,6 +284,19 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, return (p - prop) * sizeof(uint32_t); } +static hwaddr spapr_node0_size(void) +{ + if (nb_numa_nodes) { + int i; + for (i = 0; i < nb_numa_nodes; ++i) { + if (numa_info[i].node_mem) { + return MIN(pow2floor(numa_info[i].node_mem), ram_size); + } + } + } + return ram_size; +} + #define _FDT(exp) \ do { \ int ret = (exp); \ @@ -319,6 +333,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, QemuOpts *opts = qemu_opts_find(qemu_find_opts("smp-opts"), NULL); unsigned sockets = opts ? qemu_opt_get_number(opts, "sockets", 0) : 0; uint32_t cpus_per_socket = sockets ? (smp_cpus / sockets) : 1; + char *buf; add_str(hypertas, "hcall-pft"); add_str(hypertas, "hcall-term"); @@ -348,6 +363,29 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries"))); + /* + * Add info to guest to indentify which host is it being run on + * and what is the uuid of the guest + */ + if (kvmppc_get_host_model(&buf)) { + _FDT((fdt_property_string(fdt, "host-model", buf))); + g_free(buf); + } + if (kvmppc_get_host_serial(&buf)) { + _FDT((fdt_property_string(fdt, "host-serial", buf))); + g_free(buf); + } + + buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], + qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], + qemu_uuid[14], qemu_uuid[15]); + + _FDT((fdt_property_string(fdt, "vm,uuid", buf))); + g_free(buf); + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); @@ -502,6 +540,15 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); + /* + * According to PAPR, rtas ibm,os-term, does not gaurantee a return + * back to the guest cpu. + * + * While an additional ibm,extended-os-term property indicates that + * rtas call return will always occur. Set this property. + */ + _FDT((fdt_property(fdt, "ibm,extended-os-term", NULL, 0))); + _FDT((fdt_end_node(fdt))); /* interrupt controller */ @@ -597,72 +644,75 @@ int spapr_h_cas_compose_response(target_ulong addr, target_ulong size) return 0; } -static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +static void spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start, + hwaddr size) { - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; + uint32_t associativity[] = { + cpu_to_be32(0x4), /* length */ + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(nodeid) + }; char mem_name[32]; - hwaddr node0_size, mem_start, node_size; uint64_t mem_reg_property[2]; - int i, off; + int off; - /* memory node(s) */ - if (nb_numa_nodes > 1 && numa_info[0].node_mem < ram_size) { - node0_size = numa_info[0].node_mem; - } else { - node0_size = ram_size; - } + mem_reg_property[0] = cpu_to_be64(start); + mem_reg_property[1] = cpu_to_be64(size); - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(spapr->rma_size); - off = fdt_add_subnode(fdt, 0, "memory@0"); + sprintf(mem_name, "memory@" TARGET_FMT_lx, start); + off = fdt_add_subnode(fdt, 0, mem_name); _FDT(off); _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, sizeof(mem_reg_property)))); _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, sizeof(associativity)))); +} + +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + hwaddr mem_start, node_size; + int i, nb_nodes = nb_numa_nodes; + NodeInfo *nodes = numa_info; + NodeInfo ramnode; + + /* No NUMA nodes, assume there is just one node with whole RAM */ + if (!nb_numa_nodes) { + nb_nodes = 1; + ramnode.node_mem = ram_size; + nodes = &ramnode; + } - /* RAM: Node 0 */ - if (node0_size > spapr->rma_size) { - mem_reg_property[0] = cpu_to_be64(spapr->rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); - off = fdt_add_subnode(fdt, 0, mem_name); - _FDT(off); - _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); - _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, - sizeof(associativity)))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); + for (i = 0, mem_start = 0; i < nb_nodes; ++i) { + if (!nodes[i].node_mem) { + continue; + } if (mem_start >= ram_size) { node_size = 0; } else { - node_size = numa_info[i].node_mem; + node_size = nodes[i].node_mem; if (node_size > ram_size - mem_start) { node_size = ram_size - mem_start; } } - mem_reg_property[1] = cpu_to_be64(node_size); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - off = fdt_add_subnode(fdt, 0, mem_name); - _FDT(off); - _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); - _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, - sizeof(associativity)))); - mem_start += node_size; + if (!mem_start) { + /* ppc_spapr_init() checks for rma_size <= node0_size already */ + spapr_populate_memory_node(fdt, i, 0, spapr->rma_size); + mem_start += spapr->rma_size; + node_size -= spapr->rma_size; + } + for ( ; node_size; ) { + hwaddr sizetmp = pow2floor(node_size); + + /* mem_start != 0 here */ + if (ctzl(mem_start) < ctzl(sizetmp)) { + sizetmp = 1ULL << ctzl(mem_start); + } + + spapr_populate_memory_node(fdt, i, mem_start, sizetmp); + node_size -= sizetmp; + mem_start += sizetmp; + } } return 0; @@ -746,6 +796,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); + g_free(bootlist); g_free(fdt); } @@ -792,25 +843,38 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* Update the RMA size if necessary */ if (spapr->vrma_adjust) { - hwaddr node0_size = (nb_numa_nodes > 1) ? - numa_info[0].node_mem : ram_size; - spapr->rma_size = kvmppc_rma_size(node0_size, spapr->htab_shift); + spapr->rma_size = kvmppc_rma_size(spapr_node0_size(), + spapr->htab_shift); } } static void ppc_spapr_reset(void) { PowerPCCPU *first_ppc_cpu; + uint32_t rtas_limit; /* Reset the hash table & recalc the RMA */ spapr_reset_htab(spapr); qemu_devices_reset(); + /* + * We place the device tree and RTAS just below either the top of the RMA, + * or just below 2GB, whichever is lowere, so that it can be + * processed with 32-bit real mode code if necessary + */ + rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR); + spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; + spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; + /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, spapr->rtas_size); + /* Copy RTAS over */ + cpu_physical_memory_write(spapr->rtas_addr, spapr->rtas_blob, + spapr->rtas_size); + /* Set up the entry state */ first_ppc_cpu = POWERPC_CPU(first_cpu); first_ppc_cpu->env.gpr[3] = spapr->fdt_addr; @@ -1227,10 +1291,10 @@ static void ppc_spapr_init(MachineState *machine) MemoryRegion *rma_region; void *rma = NULL; hwaddr rma_alloc_size; - hwaddr node0_size = (nb_numa_nodes > 1) ? numa_info[0].node_mem : ram_size; + hwaddr node0_size = spapr_node0_size(); uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; - long load_limit, rtas_limit, fw_size; + long load_limit, fw_size; bool kernel_le = false; char *filename; @@ -1275,13 +1339,8 @@ static void ppc_spapr_init(MachineState *machine) exit(1); } - /* We place the device tree and RTAS just below either the top of the RMA, - * or just below 2GB, whichever is lowere, so that it can be - * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(spapr->rma_size, 0x80000000); - spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; - spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; - load_limit = spapr->fdt_addr - FW_OVERHEAD; + /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */ + load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; /* We aim for a hash table of size 1/128 the size of RAM. The * normal rule of thumb is 1/64 the size of RAM, but that's much @@ -1349,14 +1408,14 @@ static void ppc_spapr_init(MachineState *machine) } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); - spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, - rtas_limit - spapr->rtas_addr); - if (spapr->rtas_size < 0) { + spapr->rtas_size = get_image_size(filename); + spapr->rtas_blob = g_malloc(spapr->rtas_size); + if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) { hw_error("qemu: could not load LPAR rtas '%s'\n", filename); exit(1); } if (spapr->rtas_size > RTAS_MAX_SIZE) { - hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n", + hw_error("RTAS too big ! 0x%zx bytes (max is 0x%x)\n", spapr->rtas_size, RTAS_MAX_SIZE); exit(1); } @@ -1378,7 +1437,6 @@ static void ppc_spapr_init(MachineState *machine) spapr_create_nvram(spapr); /* Set up PCI */ - spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW); spapr_pci_rtas_init(); phb = spapr_create_phb(spapr, 0); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 467858ce05..86514472fe 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -712,10 +712,10 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } -static target_ulong h_set_mode_resouce_le(PowerPCCPU *cpu, - target_ulong mflags, - target_ulong value1, - target_ulong value2) +static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu, + target_ulong mflags, + target_ulong value1, + target_ulong value2) { CPUState *cs; @@ -743,10 +743,10 @@ static target_ulong h_set_mode_resouce_le(PowerPCCPU *cpu, return H_UNSUPPORTED_FLAG; } -static target_ulong h_set_mode_resouce_addr_trans_mode(PowerPCCPU *cpu, - target_ulong mflags, - target_ulong value1, - target_ulong value2) +static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, + target_ulong mflags, + target_ulong value1, + target_ulong value2) { CPUState *cs; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); @@ -794,11 +794,11 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr, switch (resource) { case H_SET_MODE_RESOURCE_LE: - ret = h_set_mode_resouce_le(cpu, args[0], args[2], args[3]); + ret = h_set_mode_resource_le(cpu, args[0], args[2], args[3]); break; case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE: - ret = h_set_mode_resouce_addr_trans_mode(cpu, args[0], - args[2], args[3]); + ret = h_set_mode_resource_addr_trans_mode(cpu, args[0], + args[2], args[3]); break; } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 9ed39a93b7..ad0da7fdc4 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -262,7 +262,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, unsigned int irq, max_irqs = 0, num = 0; sPAPRPHBState *phb = NULL; PCIDevice *pdev = NULL; - bool msix = false; spapr_pci_msi *msi; int *config_addr_key; @@ -300,7 +299,12 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, } xics_free(spapr->icp, msi->first_irq, msi->num); - spapr_msi_setmsg(pdev, 0, msix, 0, num); + if (msi_present(pdev)) { + spapr_msi_setmsg(pdev, 0, false, 0, num); + } + if (msix_present(pdev)) { + spapr_msi_setmsg(pdev, 0, true, 0, num); + } g_hash_table_remove(phb->msi, &config_addr); trace_spapr_pci_msi("Released MSIs", config_addr); @@ -341,7 +345,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, } /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */ - spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX, + spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX, irq, req_num); /* Add MSI device to cache */ @@ -465,34 +469,6 @@ static const MemoryRegionOps spapr_msi_ops = { .endianness = DEVICE_LITTLE_ENDIAN }; -void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr) -{ - uint64_t window_size = 4096; - - /* - * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors, - * we need to allocate some memory to catch those writes coming - * from msi_notify()/msix_notify(). - * As MSIMessage:addr is going to be the same and MSIMessage:data - * is going to be a VIRQ number, 4 bytes of the MSI MR will only - * be used. - * - * For KVM we want to ensure that this memory is a full page so that - * our memory slot is of page size granularity. - */ -#ifdef CONFIG_KVM - if (kvm_enabled()) { - window_size = getpagesize(); - } -#endif - - spapr->msi_win_addr = addr; - memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr, - "msi", window_size); - memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr, - &spapr->msiwindow); -} - /* * PHB PCI device */ @@ -512,6 +488,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) char *namebuf; int i; PCIBus *bus; + uint64_t msi_window_size = 4096; if (sphb->index != -1) { hwaddr windows_base; @@ -604,6 +581,28 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) address_space_init(&sphb->iommu_as, &sphb->iommu_root, sphb->dtbusname); + /* + * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors, + * we need to allocate some memory to catch those writes coming + * from msi_notify()/msix_notify(). + * As MSIMessage:addr is going to be the same and MSIMessage:data + * is going to be a VIRQ number, 4 bytes of the MSI MR will only + * be used. + * + * For KVM we want to ensure that this memory is a full page so that + * our memory slot is of page size granularity. + */ +#ifdef CONFIG_KVM + if (kvm_enabled()) { + msi_window_size = getpagesize(); + } +#endif + + memory_region_init_io(&sphb->msiwindow, NULL, &spapr_msi_ops, spapr, + "msi", msi_window_size); + memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW, + &sphb->msiwindow); + pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb); pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 9ba1ba69f9..2ec2a8e4d1 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -277,6 +277,19 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu, rtas_st(rets, 0, ret); } +static void rtas_ibm_os_term(PowerPCCPU *cpu, + sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong ret = 0; + + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); + + rtas_st(rets, 0, ret); +} + static struct rtas_call { const char *name; spapr_rtas_fn fn; @@ -404,6 +417,8 @@ static void core_rtas_register_types(void) spapr_rtas_register(RTAS_IBM_SET_SYSTEM_PARAMETER, "ibm,set-system-parameter", rtas_ibm_set_system_parameter); + spapr_rtas_register(RTAS_IBM_OS_TERM, "ibm,os-term", + rtas_ibm_os_term); } type_init(core_rtas_register_types) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index bbe4c5fb85..73ced1f5f8 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -499,6 +499,7 @@ enum xhci_flags { XHCI_FLAG_USE_MSI = 1, XHCI_FLAG_USE_MSI_X, XHCI_FLAG_SS_FIRST, + XHCI_FLAG_FORCE_PCIE_ENDCAP, }; static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, @@ -3626,7 +3627,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev) PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, &xhci->mem); - if (pci_bus_is_express(dev->bus)) { + if (pci_bus_is_express(dev->bus) || + xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) { ret = pcie_endpoint_cap_init(dev, 0xa0); assert(ret >= 0); } @@ -3855,6 +3857,8 @@ static Property xhci_properties[] = { DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), DEFINE_PROP_BIT("superspeed-ports-first", XHCIState, flags, XHCI_FLAG_SS_FIRST, true), + DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags, + XHCI_FLAG_FORCE_PCIE_ENDCAP, false), DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS), DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS), DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), |