diff options
author | Blue Swirl <blauwirbel@gmail.com> | 2013-03-09 11:02:07 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2013-03-09 11:02:07 +0000 |
commit | 62e1aeaee4d0450222a0ea43c713b59526e3e0fe (patch) | |
tree | 9aeb9e95add5e5cb89b97bdeae93347bf44fb26d /hw | |
parent | d6258c93a7133bb2bf2ab4e91476bc0b631ba7f1 (diff) | |
parent | d63919c93e6fb0587632adafba82c21e55ea4396 (diff) |
Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu
* 'ppc-for-upstream' of git://github.com/agraf/qemu: (66 commits)
pseries: Add compatible property to root of device tree
target-ppc: Move CPU aliases out of translate_init.c
target-ppc: Report CPU aliases for QMP
target-ppc: List alias names alongside CPU models
target-ppc: Make host CPU a subclass of the host's CPU model
PPC: xnu kernel expects FLUSH to be cleared on STOP
PPC: Fix dma interrupt
target-ppc: Fix PPC_DUMP_SPR_ACCESS build
target-ppc: Synchronize FPU state with KVM
target-ppc: Add mechanism for synchronizing SPRs with KVM
Save memory allocation in the elf loader
pseries: Implement h_read hcall
target-ppc: Change "POWER7" CPU alias
target-ppc: Fix remaining microcontroller typos among models
target-ppc: Split model definitions out of translate_init.c
target-ppc: Update Coding Style for CPU models
target-ppc: Turn descriptive CPU model comments into device descriptions
target-ppc: Turn descriptive CPU family comments into device descriptions
target-ppc: Set remaining fields on CPU family classes
target-ppc: Register all types for TARGET_PPCEMB
...
Diffstat (limited to 'hw')
-rw-r--r-- | hw/elf_ops.h | 19 | ||||
-rw-r--r-- | hw/loader.c | 75 | ||||
-rw-r--r-- | hw/loader.h | 2 | ||||
-rw-r--r-- | hw/mac_dbdma.c | 4 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 2 | ||||
-rw-r--r-- | hw/spapr.c | 1 | ||||
-rw-r--r-- | hw/spapr_hcall.c | 31 | ||||
-rw-r--r-- | hw/spapr_llan.c | 8 |
8 files changed, 120 insertions, 22 deletions
diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 531a42553b..acc701e3a4 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -197,7 +197,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; - elf_word mem_size; + elf_word mem_size, file_size; uint64_t addr, low = (uint64_t)-1, high = 0; uint8_t *data = NULL; char label[128]; @@ -252,14 +252,16 @@ static int glue(load_elf, SZ)(const char *name, int fd, for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; if (ph->p_type == PT_LOAD) { - mem_size = ph->p_memsz; - /* XXX: avoid allocating */ - data = g_malloc0(mem_size); + mem_size = ph->p_memsz; /* Size of the ROM */ + file_size = ph->p_filesz; /* Size of the allocated data */ + data = g_malloc0(file_size); if (ph->p_filesz > 0) { - if (lseek(fd, ph->p_offset, SEEK_SET) < 0) + if (lseek(fd, ph->p_offset, SEEK_SET) < 0) { goto fail; - if (read(fd, data, ph->p_filesz) != ph->p_filesz) + } + if (read(fd, data, file_size) != file_size) { goto fail; + } } /* address_offset is hack for kernel images that are linked at the wrong physical address. */ @@ -281,7 +283,9 @@ static int glue(load_elf, SZ)(const char *name, int fd, } snprintf(label, sizeof(label), "phdr #%d: %s", i, name); - rom_add_blob_fixed(label, data, mem_size, addr); + + /* rom_add_elf_program() seize the ownership of 'data' */ + rom_add_elf_program(label, data, file_size, mem_size, addr); total_size += mem_size; if (addr < low) @@ -289,7 +293,6 @@ static int glue(load_elf, SZ)(const char *name, int fd, if ((addr + mem_size) > high) high = addr + mem_size; - g_free(data); data = NULL; } } diff --git a/hw/loader.c b/hw/loader.c index 995edc3f98..bd2b52d14e 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -533,7 +533,14 @@ typedef struct Rom Rom; struct Rom { char *name; char *path; + + /* datasize is the amount of memory allocated in "data". If datasize is less + * than romsize, it means that the area from datasize to romsize is filled + * with zeros. + */ size_t romsize; + size_t datasize; + uint8_t *data; int isrom; char *fw_dir; @@ -589,14 +596,15 @@ int rom_add_file(const char *file, const char *fw_dir, rom->fw_dir = g_strdup(fw_dir); rom->fw_file = g_strdup(file); } - rom->addr = addr; - rom->romsize = lseek(fd, 0, SEEK_END); - rom->data = g_malloc0(rom->romsize); + rom->addr = addr; + rom->romsize = lseek(fd, 0, SEEK_END); + rom->datasize = rom->romsize; + rom->data = g_malloc0(rom->datasize); lseek(fd, 0, SEEK_SET); - rc = read(fd, rom->data, rom->romsize); - if (rc != rom->romsize) { + rc = read(fd, rom->data, rom->datasize); + if (rc != rom->datasize) { fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", - rom->name, rc, rom->romsize); + rom->name, rc, rom->datasize); goto err; } close(fd); @@ -637,16 +645,37 @@ int rom_add_blob(const char *name, const void *blob, size_t len, { Rom *rom; - rom = g_malloc0(sizeof(*rom)); - rom->name = g_strdup(name); - rom->addr = addr; - rom->romsize = len; - rom->data = g_malloc0(rom->romsize); + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->romsize = len; + rom->datasize = len; + rom->data = g_malloc0(rom->datasize); memcpy(rom->data, blob, len); rom_insert(rom); return 0; } +/* This function is specific for elf program because we don't need to allocate + * all the rom. We just allocate the first part and the rest is just zeros. This + * is why romsize and datasize are different. Also, this function seize the + * memory ownership of "data", so we don't have to allocate and copy the buffer. + */ +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr) +{ + Rom *rom; + + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->datasize = datasize; + rom->romsize = romsize; + rom->data = data; + rom_insert(rom); + return 0; +} + int rom_add_vga(const char *file) { return rom_add_file(file, "vgaroms", 0, -1); @@ -668,7 +697,7 @@ static void rom_reset(void *unused) if (rom->data == NULL) { continue; } - cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize); + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); if (rom->isrom) { /* rom needs to be written only once */ g_free(rom->data); @@ -756,13 +785,33 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) d = dest + (rom->addr - addr); s = rom->data; - l = rom->romsize; + l = rom->datasize; if ((d + l) > (dest + size)) { l = dest - d; } memcpy(d, s, l); + + if (rom->romsize > rom->datasize) { + /* If datasize is less than romsize, it means that we didn't + * allocate all the ROM because the trailing data are only zeros. + */ + + d += l; + l = rom->romsize - rom->datasize; + + if ((d + l) > (dest + size)) { + /* Rom size doesn't fit in the destination area. Adjust to avoid + * overflow. + */ + l = dest - d; + } + + if (l > 0) { + memset(d, 0x0, l); + } + } } return (d + l) - dest; diff --git a/hw/loader.h b/hw/loader.h index 5e61c95b84..0958f06934 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -27,6 +27,8 @@ int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex); int rom_add_blob(const char *name, const void *blob, size_t len, hwaddr addr); +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr); int rom_load_all(void); void rom_set_fw(void *f); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index b894ab21aa..73d74c2c59 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -688,6 +688,10 @@ dbdma_control_write(DBDMA_channel *ch) if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { /* RUN is cleared */ status &= ~(ACTIVE|DEAD); + if ((status & FLUSH) && ch->flush) { + ch->flush(&ch->io); + status &= ~FLUSH; + } } DBDMA_DPRINTF(" status 0x%08x\n", status); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 065ea871b3..a08a6b2086 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -370,7 +370,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ - qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ diff --git a/hw/spapr.c b/hw/spapr.c index e88a27aa71..fadf70f952 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -260,6 +260,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_begin_node(fdt, ""))); _FDT((fdt_property_string(fdt, "device_type", "chrp"))); _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); + _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries"))); _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 7b8959488e..77c052fcb1 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -323,6 +323,36 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + uint8_t *hpte; + int i, ridx, n_entries = 1; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + if (flags & H_READ_4) { + /* Clear the two low order bits */ + pte_index &= ~(3ULL); + n_entries = 4; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + + for (i = 0, ridx = 0; i < n_entries; i++) { + args[ridx++] = ldq_p(hpte); + args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + hpte += HASH_PTE_SIZE_64; + } + + return H_SUCCESS; +} + static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -710,6 +740,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_ENTER, h_enter); spapr_register_hypercall(H_REMOVE, h_remove); spapr_register_hypercall(H_PROTECT, h_protect); + spapr_register_hypercall(H_READ, h_read); /* hcall-bulk */ spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 6ef29362f5..0ace2eb1f3 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -175,11 +175,19 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, return size; } +static void spapr_vlan_cleanup(NetClientState *nc) +{ + VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc); + + dev->nic = NULL; +} + static NetClientInfo net_spapr_vlan_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = spapr_vlan_can_receive, .receive = spapr_vlan_receive, + .cleanup = spapr_vlan_cleanup, }; static void spapr_vlan_reset(VIOsPAPRDevice *sdev) |