summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-01-15 15:49:43 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-01-15 15:49:43 +0000
commit5a57acb66f19ee52723aa05b8afbbc41c3e9ec99 (patch)
tree8401eae5b86ae112ee3504e0dbb35d3951217868
parentf02ccf53693758b65843264e077f90cf295e7d98 (diff)
parent67736a25f86595c8ae174a21d965af5a027884c9 (diff)
downloadqemu-5a57acb66f19ee52723aa05b8afbbc41c3e9ec99.tar.gz
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160115' into staging
target-arm queue: * use the right MMU index when handling unaligned accesses * xlnx-zynqmp: Add support for high DDR memory regions * target-arm: support QMP dump-guest-memory * ARM: virt: Don't generate RTC ACPI device when using UEFI # gpg: Signature made Fri 15 Jan 2016 15:16:19 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160115: ARM: virt: Don't generate RTC ACPI device when using UEFI target-arm: dump-guest-memory: add vfp notes for arm elf: add arm note types target-arm: dump-guest-memory: add prfpreg notes for aarch64 target-arm: support QMP dump-guest-memory dump: allow target to set the physical base dump: allow target to set the page size dump: qemunotes aren't commonly needed qapi-schema: dump-guest-memory: Improve text xlnx-zynqmp: Add support for high DDR memory regions target-arm: Use the right MMU index in arm_regime_using_lpae_format Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--dump.c131
-rw-r--r--hw/arm/virt-acpi-build.c24
-rw-r--r--hw/arm/xlnx-ep108.c40
-rw-r--r--hw/arm/xlnx-zynqmp.c37
-rw-r--r--include/elf.h5
-rw-r--r--include/hw/arm/xlnx-zynqmp.h12
-rw-r--r--include/sysemu/dump-arch.h9
-rw-r--r--include/sysemu/dump.h11
-rw-r--r--qapi-schema.json4
-rw-r--r--qom/cpu.c4
-rw-r--r--target-arm/Makefile.objs3
-rw-r--r--target-arm/arch_dump.c336
-rw-r--r--target-arm/cpu-qom.h5
-rw-r--r--target-arm/cpu.c2
-rw-r--r--target-arm/helper.c12
-rw-r--r--target-arm/internals.h5
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-ppc/arch_dump.c6
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/translate_init.c1
-rw-r--r--target-s390x/arch_dump.c6
-rw-r--r--target-s390x/cpu-qom.h2
-rw-r--r--target-s390x/cpu.c1
23 files changed, 528 insertions, 132 deletions
diff --git a/dump.c b/dump.c
index 78b7d843ce..2d4892bec2 100644
--- a/dump.c
+++ b/dump.c
@@ -347,18 +347,18 @@ static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
int64_t i;
Error *local_err = NULL;
- for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
- write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
- TARGET_PAGE_SIZE, &local_err);
+ for (i = 0; i < size / s->dump_info.page_size; i++) {
+ write_data(s, block->host_addr + start + i * s->dump_info.page_size,
+ s->dump_info.page_size, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
- if ((size % TARGET_PAGE_SIZE) != 0) {
- write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
- size % TARGET_PAGE_SIZE, &local_err);
+ if ((size % s->dump_info.page_size) != 0) {
+ write_data(s, block->host_addr + start + i * s->dump_info.page_size,
+ size % s->dump_info.page_size, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -737,7 +737,7 @@ static void create_header32(DumpState *s, Error **errp)
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
dh->header_version = cpu_to_dump32(s, 6);
- block_size = TARGET_PAGE_SIZE;
+ block_size = s->dump_info.page_size;
dh->block_size = cpu_to_dump32(s, block_size);
sub_hdr_size = sizeof(struct KdumpSubHeader32) + s->note_size;
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
@@ -775,7 +775,7 @@ static void create_header32(DumpState *s, Error **errp)
/* 64bit max_mapnr_64 */
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
- kh->phys_base = cpu_to_dump32(s, PHYS_BASE);
+ kh->phys_base = cpu_to_dump32(s, s->dump_info.phys_base);
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
@@ -837,7 +837,7 @@ static void create_header64(DumpState *s, Error **errp)
strncpy(dh->signature, KDUMP_SIGNATURE, strlen(KDUMP_SIGNATURE));
dh->header_version = cpu_to_dump32(s, 6);
- block_size = TARGET_PAGE_SIZE;
+ block_size = s->dump_info.page_size;
dh->block_size = cpu_to_dump32(s, block_size);
sub_hdr_size = sizeof(struct KdumpSubHeader64) + s->note_size;
sub_hdr_size = DIV_ROUND_UP(sub_hdr_size, block_size);
@@ -875,7 +875,7 @@ static void create_header64(DumpState *s, Error **errp)
/* 64bit max_mapnr_64 */
kh->max_mapnr_64 = cpu_to_dump64(s, s->max_mapnr);
- kh->phys_base = cpu_to_dump64(s, PHYS_BASE);
+ kh->phys_base = cpu_to_dump64(s, s->dump_info.phys_base);
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
@@ -933,6 +933,11 @@ static void write_dump_header(DumpState *s, Error **errp)
}
}
+static size_t dump_bitmap_get_bufsize(DumpState *s)
+{
+ return s->dump_info.page_size;
+}
+
/*
* set dump_bitmap sequencely. the bit before last_pfn is not allowed to be
* rewritten, so if need to set the first bit, set last_pfn and pfn to 0.
@@ -946,6 +951,8 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
off_t old_offset, new_offset;
off_t offset_bitmap1, offset_bitmap2;
uint32_t byte, bit;
+ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
+ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
/* should not set the previous place */
assert(last_pfn <= pfn);
@@ -956,14 +963,14 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
* making new_offset be bigger than old_offset can also sync remained data
* into vmcore.
*/
- old_offset = BUFSIZE_BITMAP * (last_pfn / PFN_BUFBITMAP);
- new_offset = BUFSIZE_BITMAP * (pfn / PFN_BUFBITMAP);
+ old_offset = bitmap_bufsize * (last_pfn / bits_per_buf);
+ new_offset = bitmap_bufsize * (pfn / bits_per_buf);
while (old_offset < new_offset) {
/* calculate the offset and write dump_bitmap */
offset_bitmap1 = s->offset_dump_bitmap + old_offset;
if (write_buffer(s->fd, offset_bitmap1, buf,
- BUFSIZE_BITMAP) < 0) {
+ bitmap_bufsize) < 0) {
return -1;
}
@@ -971,17 +978,17 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
offset_bitmap2 = s->offset_dump_bitmap + s->len_dump_bitmap +
old_offset;
if (write_buffer(s->fd, offset_bitmap2, buf,
- BUFSIZE_BITMAP) < 0) {
+ bitmap_bufsize) < 0) {
return -1;
}
- memset(buf, 0, BUFSIZE_BITMAP);
- old_offset += BUFSIZE_BITMAP;
+ memset(buf, 0, bitmap_bufsize);
+ old_offset += bitmap_bufsize;
}
/* get the exact place of the bit in the buf, and set it */
- byte = (pfn % PFN_BUFBITMAP) / CHAR_BIT;
- bit = (pfn % PFN_BUFBITMAP) % CHAR_BIT;
+ byte = (pfn % bits_per_buf) / CHAR_BIT;
+ bit = (pfn % bits_per_buf) % CHAR_BIT;
if (value) {
buf[byte] |= 1u << bit;
} else {
@@ -991,6 +998,20 @@ static int set_dump_bitmap(uint64_t last_pfn, uint64_t pfn, bool value,
return 0;
}
+static uint64_t dump_paddr_to_pfn(DumpState *s, uint64_t addr)
+{
+ int target_page_shift = ctz32(s->dump_info.page_size);
+
+ return (addr >> target_page_shift) - ARCH_PFN_OFFSET;
+}
+
+static uint64_t dump_pfn_to_paddr(DumpState *s, uint64_t pfn)
+{
+ int target_page_shift = ctz32(s->dump_info.page_size);
+
+ return (pfn + ARCH_PFN_OFFSET) << target_page_shift;
+}
+
/*
* exam every page and return the page frame number and the address of the page.
* bufptr can be NULL. note: the blocks here is supposed to reflect guest-phys
@@ -1001,16 +1022,16 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
uint8_t **bufptr, DumpState *s)
{
GuestPhysBlock *block = *blockptr;
- hwaddr addr;
+ hwaddr addr, target_page_mask = ~((hwaddr)s->dump_info.page_size - 1);
uint8_t *buf;
/* block == NULL means the start of the iteration */
if (!block) {
block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
*blockptr = block;
- assert((block->target_start & ~TARGET_PAGE_MASK) == 0);
- assert((block->target_end & ~TARGET_PAGE_MASK) == 0);
- *pfnptr = paddr_to_pfn(block->target_start);
+ assert((block->target_start & ~target_page_mask) == 0);
+ assert((block->target_end & ~target_page_mask) == 0);
+ *pfnptr = dump_paddr_to_pfn(s, block->target_start);
if (bufptr) {
*bufptr = block->host_addr;
}
@@ -1018,10 +1039,10 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
}
*pfnptr = *pfnptr + 1;
- addr = pfn_to_paddr(*pfnptr);
+ addr = dump_pfn_to_paddr(s, *pfnptr);
if ((addr >= block->target_start) &&
- (addr + TARGET_PAGE_SIZE <= block->target_end)) {
+ (addr + s->dump_info.page_size <= block->target_end)) {
buf = block->host_addr + (addr - block->target_start);
} else {
/* the next page is in the next block */
@@ -1030,9 +1051,9 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
if (!block) {
return false;
}
- assert((block->target_start & ~TARGET_PAGE_MASK) == 0);
- assert((block->target_end & ~TARGET_PAGE_MASK) == 0);
- *pfnptr = paddr_to_pfn(block->target_start);
+ assert((block->target_start & ~target_page_mask) == 0);
+ assert((block->target_end & ~target_page_mask) == 0);
+ *pfnptr = dump_paddr_to_pfn(s, block->target_start);
buf = block->host_addr;
}
@@ -1050,9 +1071,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
void *dump_bitmap_buf;
size_t num_dumpable;
GuestPhysBlock *block_iter = NULL;
+ size_t bitmap_bufsize = dump_bitmap_get_bufsize(s);
+ size_t bits_per_buf = bitmap_bufsize * CHAR_BIT;
/* dump_bitmap_buf is used to store dump_bitmap temporarily */
- dump_bitmap_buf = g_malloc0(BUFSIZE_BITMAP);
+ dump_bitmap_buf = g_malloc0(bitmap_bufsize);
num_dumpable = 0;
last_pfn = 0;
@@ -1074,11 +1097,11 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
/*
* set_dump_bitmap will always leave the recently set bit un-sync. Here we
- * set last_pfn + PFN_BUFBITMAP to 0 and those set but un-sync bit will be
- * synchronized into vmcore.
+ * set the remaining bits from last_pfn to the end of the bitmap buffer to
+ * 0. With those set, the un-sync bit will be synchronized into the vmcore.
*/
if (num_dumpable > 0) {
- ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
+ ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
dump_bitmap_buf, s);
if (ret < 0) {
dump_error(s, "dump: failed to sync dump_bitmap", errp);
@@ -1098,8 +1121,8 @@ static void prepare_data_cache(DataCache *data_cache, DumpState *s,
{
data_cache->fd = s->fd;
data_cache->data_size = 0;
- data_cache->buf_size = BUFSIZE_DATA_CACHE;
- data_cache->buf = g_malloc0(BUFSIZE_DATA_CACHE);
+ data_cache->buf_size = 4 * dump_bitmap_get_bufsize(s);
+ data_cache->buf = g_malloc0(data_cache->buf_size);
data_cache->offset = offset;
}
@@ -1193,7 +1216,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
prepare_data_cache(&page_data, s, offset_data);
/* prepare buffer to store compressed data */
- len_buf_out = get_len_buf_out(TARGET_PAGE_SIZE, s->flag_compress);
+ len_buf_out = get_len_buf_out(s->dump_info.page_size, s->flag_compress);
assert(len_buf_out != 0);
#ifdef CONFIG_LZO
@@ -1206,19 +1229,19 @@ static void write_dump_pages(DumpState *s, Error **errp)
* init zero page's page_desc and page_data, because every zero page
* uses the same page_data
*/
- pd_zero.size = cpu_to_dump32(s, TARGET_PAGE_SIZE);
+ pd_zero.size = cpu_to_dump32(s, s->dump_info.page_size);
pd_zero.flags = cpu_to_dump32(s, 0);
pd_zero.offset = cpu_to_dump64(s, offset_data);
pd_zero.page_flags = cpu_to_dump64(s, 0);
- buf = g_malloc0(TARGET_PAGE_SIZE);
- ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
+ buf = g_malloc0(s->dump_info.page_size);
+ ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
g_free(buf);
if (ret < 0) {
dump_error(s, "dump: failed to write page data (zero page)", errp);
goto out;
}
- offset_data += TARGET_PAGE_SIZE;
+ offset_data += s->dump_info.page_size;
/*
* dump memory to vmcore page by page. zero page will all be resided in the
@@ -1226,7 +1249,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
*/
while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
/* check zero page */
- if (is_zero_page(buf, TARGET_PAGE_SIZE)) {
+ if (is_zero_page(buf, s->dump_info.page_size)) {
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
false);
if (ret < 0) {
@@ -1248,8 +1271,8 @@ static void write_dump_pages(DumpState *s, Error **errp)
size_out = len_buf_out;
if ((s->flag_compress & DUMP_DH_COMPRESSED_ZLIB) &&
(compress2(buf_out, (uLongf *)&size_out, buf,
- TARGET_PAGE_SIZE, Z_BEST_SPEED) == Z_OK) &&
- (size_out < TARGET_PAGE_SIZE)) {
+ s->dump_info.page_size, Z_BEST_SPEED) == Z_OK) &&
+ (size_out < s->dump_info.page_size)) {
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_ZLIB);
pd.size = cpu_to_dump32(s, size_out);
@@ -1260,9 +1283,9 @@ static void write_dump_pages(DumpState *s, Error **errp)
}
#ifdef CONFIG_LZO
} else if ((s->flag_compress & DUMP_DH_COMPRESSED_LZO) &&
- (lzo1x_1_compress(buf, TARGET_PAGE_SIZE, buf_out,
+ (lzo1x_1_compress(buf, s->dump_info.page_size, buf_out,
(lzo_uint *)&size_out, wrkmem) == LZO_E_OK) &&
- (size_out < TARGET_PAGE_SIZE)) {
+ (size_out < s->dump_info.page_size)) {
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_LZO);
pd.size = cpu_to_dump32(s, size_out);
@@ -1274,9 +1297,9 @@ static void write_dump_pages(DumpState *s, Error **errp)
#endif
#ifdef CONFIG_SNAPPY
} else if ((s->flag_compress & DUMP_DH_COMPRESSED_SNAPPY) &&
- (snappy_compress((char *)buf, TARGET_PAGE_SIZE,
+ (snappy_compress((char *)buf, s->dump_info.page_size,
(char *)buf_out, &size_out) == SNAPPY_OK) &&
- (size_out < TARGET_PAGE_SIZE)) {
+ (size_out < s->dump_info.page_size)) {
pd.flags = cpu_to_dump32(s, DUMP_DH_COMPRESSED_SNAPPY);
pd.size = cpu_to_dump32(s, size_out);
@@ -1289,13 +1312,14 @@ static void write_dump_pages(DumpState *s, Error **errp)
} else {
/*
* fall back to save in plaintext, size_out should be
- * assigned TARGET_PAGE_SIZE
+ * assigned the target's page size
*/
pd.flags = cpu_to_dump32(s, 0);
- size_out = TARGET_PAGE_SIZE;
+ size_out = s->dump_info.page_size;
pd.size = cpu_to_dump32(s, size_out);
- ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
+ ret = write_cache(&page_data, buf,
+ s->dump_info.page_size, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data", errp);
goto out;
@@ -1430,7 +1454,7 @@ static void get_max_mapnr(DumpState *s)
GuestPhysBlock *last_block;
last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead);
- s->max_mapnr = paddr_to_pfn(last_block->target_end);
+ s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
}
static void dump_init(DumpState *s, int fd, bool has_format,
@@ -1489,6 +1513,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
goto cleanup;
}
+ if (!s->dump_info.page_size) {
+ s->dump_info.page_size = TARGET_PAGE_SIZE;
+ }
+
s->note_size = cpu_get_note_size(s->dump_info.d_class,
s->dump_info.d_machine, nr_cpus);
if (s->note_size < 0) {
@@ -1512,8 +1540,9 @@ static void dump_init(DumpState *s, int fd, bool has_format,
get_max_mapnr(s);
uint64_t tmp;
- tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT), TARGET_PAGE_SIZE);
- s->len_dump_bitmap = tmp * TARGET_PAGE_SIZE;
+ tmp = DIV_ROUND_UP(DIV_ROUND_UP(s->max_mapnr, CHAR_BIT),
+ s->dump_info.page_size);
+ s->len_dump_bitmap = tmp * s->dump_info.page_size;
/* init for kdump-compressed format */
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0caf5ced69..0d5c635cc8 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -94,23 +94,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
aml_append(scope, dev);
}
-static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
- uint32_t rtc_irq)
-{
- Aml *dev = aml_device("RTC0");
- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
-
- Aml *crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(rtc_memmap->base,
- rtc_memmap->size, AML_READ_WRITE));
- aml_append(crs,
- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, &rtc_irq, 1));
- aml_append(dev, aml_name_decl("_CRS", crs));
- aml_append(scope, dev);
-}
-
static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
{
Aml *dev, *crs;
@@ -571,12 +554,15 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
/* Reserve space for header */
acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
+ /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
+ * While UEFI can use libfdt to disable the RTC device node in the DTB that
+ * it passes to the OS, it cannot modify AML. Therefore, we won't generate
+ * the RTC ACPI device at all when using UEFI.
+ */
scope = aml_scope("\\_SB");
acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
- acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
- (irqmap[VIRT_RTC] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c
index 73e60876e8..9099025a79 100644
--- a/hw/arm/xlnx-ep108.c
+++ b/hw/arm/xlnx-ep108.c
@@ -25,42 +25,44 @@ typedef struct XlnxEP108 {
MemoryRegion ddr_ram;
} XlnxEP108;
-/* Max 2GB RAM */
-#define EP108_MAX_RAM_SIZE 0x80000000ull
-
static struct arm_boot_info xlnx_ep108_binfo;
static void xlnx_ep108_init(MachineState *machine)
{
XlnxEP108 *s = g_new0(XlnxEP108, 1);
Error *err = NULL;
+ uint64_t ram_size = machine->ram_size;
+
+ /* Create the memory region to pass to the SoC */
+ if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) {
+ error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of "
+ "0x%llx", ram_size,
+ XLNX_ZYNQMP_MAX_RAM_SIZE);
+ exit(1);
+ }
+
+ if (ram_size < 0x08000000) {
+ qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for EP108",
+ ram_size);
+ }
+
+ memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
+ ram_size);
object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP);
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
&error_abort);
+ object_property_set_link(OBJECT(&s->soc), OBJECT(&s->ddr_ram),
+ "ddr-ram", &error_abort);
+
object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
if (err) {
error_report_err(err);
exit(1);
}
- if (machine->ram_size > EP108_MAX_RAM_SIZE) {
- error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
- "reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE);
- machine->ram_size = EP108_MAX_RAM_SIZE;
- }
-
- if (machine->ram_size < 0x08000000) {
- qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108",
- machine->ram_size);
- }
-
- memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram",
- machine->ram_size);
- memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram);
-
- xlnx_ep108_binfo.ram_size = machine->ram_size;
+ xlnx_ep108_binfo.ram_size = ram_size;
xlnx_ep108_binfo.kernel_filename = machine->kernel_filename;
xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
xlnx_ep108_binfo.initrd_filename = machine->initrd_filename;
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 20a3b2b093..f26efd802a 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -90,6 +90,11 @@ static void xlnx_zynqmp_init(Object *obj)
&error_abort);
}
+ object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION,
+ (Object **)&s->ddr_ram,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
+
object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
@@ -119,10 +124,42 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
XlnxZynqMPState *s = XLNX_ZYNQMP(dev);
MemoryRegion *system_memory = get_system_memory();
uint8_t i;
+ uint64_t ram_size;
const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
+ ram_addr_t ddr_low_size, ddr_high_size;
qemu_irq gic_spi[GIC_NUM_SPI_INTR];
Error *err = NULL;
+ ram_size = memory_region_size(s->ddr_ram);
+
+ /* Create the DDR Memory Regions. User friendly checks should happen at
+ * the board level
+ */
+ if (ram_size > XLNX_ZYNQMP_MAX_LOW_RAM_SIZE) {
+ /* The RAM size is above the maximum available for the low DDR.
+ * Create the high DDR memory region as well.
+ */
+ assert(ram_size <= XLNX_ZYNQMP_MAX_RAM_SIZE);
+ ddr_low_size = XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
+ ddr_high_size = ram_size - XLNX_ZYNQMP_MAX_LOW_RAM_SIZE;
+
+ memory_region_init_alias(&s->ddr_ram_high, NULL,
+ "ddr-ram-high", s->ddr_ram,
+ ddr_low_size, ddr_high_size);
+ memory_region_add_subregion(get_system_memory(),
+ XLNX_ZYNQMP_HIGH_RAM_START,
+ &s->ddr_ram_high);
+ } else {
+ /* RAM must be non-zero */
+ assert(ram_size);
+ ddr_low_size = ram_size;
+ }
+
+ memory_region_init_alias(&s->ddr_ram_low, NULL,
+ "ddr-ram-low", s->ddr_ram,
+ 0, ddr_low_size);
+ memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram_low);
+
/* Create the four OCM banks */
for (i = 0; i < XLNX_ZYNQMP_NUM_OCM_BANKS; i++) {
char *ocm_name = g_strdup_printf("zynqmp.ocm_ram_bank_%d", i);
diff --git a/include/elf.h b/include/elf.h
index 66add810df..1098d217ec 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1471,6 +1471,11 @@ typedef struct elf64_shdr {
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
+#define NT_ARM_TLS 0x401 /* ARM TLS register */
+#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
/* Note header in a PT_NOTE section */
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index d1160920cc..1eba937964 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -51,6 +51,14 @@
#define XLNX_ZYNQMP_GIC_REGION_SIZE 0x1000
#define XLNX_ZYNQMP_GIC_ALIASES (0x10000 / XLNX_ZYNQMP_GIC_REGION_SIZE - 1)
+#define XLNX_ZYNQMP_MAX_LOW_RAM_SIZE 0x80000000ull
+
+#define XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE 0x800000000ull
+#define XLNX_ZYNQMP_HIGH_RAM_START 0x800000000ull
+
+#define XLNX_ZYNQMP_MAX_RAM_SIZE (XLNX_ZYNQMP_MAX_LOW_RAM_SIZE + \
+ XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE)
+
typedef struct XlnxZynqMPState {
/*< private >*/
DeviceState parent_obj;
@@ -60,8 +68,12 @@ typedef struct XlnxZynqMPState {
ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
GICState gic;
MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
+
MemoryRegion ocm_ram[XLNX_ZYNQMP_NUM_OCM_BANKS];
+ MemoryRegion *ddr_ram;
+ MemoryRegion ddr_ram_low, ddr_ram_high;
+
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
SysbusAHCIState sata;
diff --git a/include/sysemu/dump-arch.h b/include/sysemu/dump-arch.h
index 9c95cede3d..e25b02e990 100644
--- a/include/sysemu/dump-arch.h
+++ b/include/sysemu/dump-arch.h
@@ -15,9 +15,12 @@
#define DUMP_ARCH_H
typedef struct ArchDumpInfo {
- int d_machine; /* Architecture */
- int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
- int d_class; /* ELFCLASS32 or ELFCLASS64 */
+ int d_machine; /* Architecture */
+ int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
+ int d_class; /* ELFCLASS32 or ELFCLASS64 */
+ uint32_t page_size; /* The target's page size. If it's variable and
+ * unknown, then this should be the maximum. */
+ uint64_t phys_base; /* The target's physmem base. */
} ArchDumpInfo;
struct GuestPhysBlockList; /* memory_mapping.h */
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
index 7e4ec5c7d9..2f04b247be 100644
--- a/include/sysemu/dump.h
+++ b/include/sysemu/dump.h
@@ -20,12 +20,9 @@
#define VERSION_FLAT_HEADER (1) /* version of flattened format */
#define END_FLAG_FLAT_HEADER (-1)
+#ifndef ARCH_PFN_OFFSET
#define ARCH_PFN_OFFSET (0)
-
-#define paddr_to_pfn(X) \
- (((unsigned long long)(X) >> TARGET_PAGE_BITS) - ARCH_PFN_OFFSET)
-#define pfn_to_paddr(X) \
- (((unsigned long long)(X) + ARCH_PFN_OFFSET) << TARGET_PAGE_BITS)
+#endif
/*
* flag for compressed format
@@ -36,12 +33,8 @@
#define KDUMP_SIGNATURE "KDUMP "
#define SIG_LEN (sizeof(KDUMP_SIGNATURE) - 1)
-#define PHYS_BASE (0)
#define DUMP_LEVEL (1)
#define DISKDUMP_HEADER_BLOCKS (1)
-#define BUFSIZE_BITMAP (TARGET_PAGE_SIZE)
-#define PFN_BUFBITMAP (CHAR_BIT * BUFSIZE_BITMAP)
-#define BUFSIZE_DATA_CACHE (TARGET_PAGE_SIZE * 4)
#include "sysemu/dump-arch.h"
#include "sysemu/memory_mapping.h"
diff --git a/qapi-schema.json b/qapi-schema.json
index 2e31733b21..0c75465031 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2169,8 +2169,7 @@
# @dump-guest-memory
#
# Dump guest's memory to vmcore. It is a synchronous operation that can take
-# very long depending on the amount of guest memory. This command is only
-# supported on i386 and x86_64.
+# very long depending on the amount of guest memory.
#
# @paging: if true, do paging to get guest's memory mapping. This allows
# using gdb to process the core file.
@@ -2186,6 +2185,7 @@
# 2. The guest can be in real-mode even if paging is enabled. For
# example, the guest uses ACPI to sleep, and ACPI sleep state
# goes in real-mode
+# 3. Currently only supported on i386 and x86_64.
#
# @protocol: the filename or file descriptor of the vmcore. The supported
# protocols are:
diff --git a/qom/cpu.c b/qom/cpu.c
index fb80d13a3f..8f537a470f 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -130,7 +130,7 @@ int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque)
{
- return -1;
+ return 0;
}
int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
@@ -159,7 +159,7 @@ int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque)
{
- return -1;
+ return 0;
}
int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index 9460b409a5..a80eb39743 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -1,5 +1,5 @@
obj-y += arm-semi.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o
obj-$(CONFIG_KVM) += kvm.o
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
@@ -7,6 +7,5 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o
obj-y += gdbstub.o
-obj-$(CONFIG_SOFTMMU) += psci.o
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
obj-y += crypto_helper.o
diff --git a/target-arm/arch_dump.c b/target-arm/arch_dump.c
new file mode 100644
index 0000000000..f45125ffe6
--- /dev/null
+++ b/target-arm/arch_dump.c
@@ -0,0 +1,336 @@
+/* Support for writing ELF notes for ARM architectures
+ *
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * Author: Andrew Jones <drjones@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "elf.h"
+#include "sysemu/dump.h"
+
+/* struct user_pt_regs from arch/arm64/include/uapi/asm/ptrace.h */
+struct aarch64_user_regs {
+ uint64_t regs[31];
+ uint64_t sp;
+ uint64_t pc;
+ uint64_t pstate;
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_regs) != 272);
+
+/* struct elf_prstatus from include/uapi/linux/elfcore.h */
+struct aarch64_elf_prstatus {
+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pr_pid;
+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
+ struct aarch64_user_regs pr_reg;
+ uint32_t pr_fpvalid;
+ char pad3[4];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct aarch64_elf_prstatus) != 392);
+
+/* struct user_fpsimd_state from arch/arm64/include/uapi/asm/ptrace.h
+ *
+ * While the vregs member of user_fpsimd_state is of type __uint128_t,
+ * QEMU uses an array of uint64_t, where the high half of the 128-bit
+ * value is always in the 2n+1'th index. Thus we also break the 128-
+ * bit values into two halves in this reproduction of user_fpsimd_state.
+ */
+struct aarch64_user_vfp_state {
+ uint64_t vregs[64];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ char pad[8];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct aarch64_user_vfp_state) != 528);
+
+struct aarch64_note {
+ Elf64_Nhdr hdr;
+ char name[8]; /* align_up(sizeof("CORE"), 4) */
+ union {
+ struct aarch64_elf_prstatus prstatus;
+ struct aarch64_user_vfp_state vfp;
+ };
+} QEMU_PACKED;
+
+#define AARCH64_NOTE_HEADER_SIZE offsetof(struct aarch64_note, prstatus)
+#define AARCH64_PRSTATUS_NOTE_SIZE \
+ (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_elf_prstatus))
+#define AARCH64_PRFPREG_NOTE_SIZE \
+ (AARCH64_NOTE_HEADER_SIZE + sizeof(struct aarch64_user_vfp_state))
+
+static void aarch64_note_init(struct aarch64_note *note, DumpState *s,
+ const char *name, Elf64_Word namesz,
+ Elf64_Word type, Elf64_Word descsz)
+{
+ memset(note, 0, sizeof(*note));
+
+ note->hdr.n_namesz = cpu_to_dump32(s, namesz);
+ note->hdr.n_descsz = cpu_to_dump32(s, descsz);
+ note->hdr.n_type = cpu_to_dump32(s, type);
+
+ memcpy(note->name, name, namesz);
+}
+
+static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f,
+ CPUARMState *env, int cpuid,
+ DumpState *s)
+{
+ struct aarch64_note note;
+ int ret, i;
+
+ aarch64_note_init(&note, s, "CORE", 5, NT_PRFPREG, sizeof(note.vfp));
+
+ for (i = 0; i < 64; ++i) {
+ note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
+ }
+
+ if (s->dump_info.d_endian == ELFDATA2MSB) {
+ /* For AArch64 we must always swap the vfp.regs's 2n and 2n+1
+ * entries when generating BE notes, because even big endian
+ * hosts use 2n+1 for the high half.
+ */
+ for (i = 0; i < 32; ++i) {
+ uint64_t tmp = note.vfp.vregs[2*i];
+ note.vfp.vregs[2*i] = note.vfp.vregs[2*i+1];
+ note.vfp.vregs[2*i+1] = tmp;
+ }
+ }
+
+ note.vfp.fpsr = cpu_to_dump32(s, vfp_get_fpsr(env));
+ note.vfp.fpcr = cpu_to_dump32(s, vfp_get_fpcr(env));
+
+ ret = f(&note, AARCH64_PRFPREG_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque)
+{
+ struct aarch64_note note;
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ DumpState *s = opaque;
+ uint64_t pstate, sp;
+ int ret, i;
+
+ aarch64_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
+
+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1);
+
+ if (!is_a64(env)) {
+ aarch64_sync_32_to_64(env);
+ pstate = cpsr_read(env);
+ sp = 0;
+ } else {
+ pstate = pstate_read(env);
+ sp = env->xregs[31];
+ }
+
+ for (i = 0; i < 31; ++i) {
+ note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->xregs[i]);
+ }
+ note.prstatus.pr_reg.sp = cpu_to_dump64(s, sp);
+ note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
+ note.prstatus.pr_reg.pstate = cpu_to_dump64(s, pstate);
+
+ ret = f(&note, AARCH64_PRSTATUS_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return aarch64_write_elf64_prfpreg(f, env, cpuid, s);
+}
+
+/* struct pt_regs from arch/arm/include/asm/ptrace.h */
+struct arm_user_regs {
+ uint32_t regs[17];
+ char pad[4];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct arm_user_regs) != 72);
+
+/* struct elf_prstatus from include/uapi/linux/elfcore.h */
+struct arm_elf_prstatus {
+ char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pr_pid;
+ char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
+ struct arm_user_regs pr_reg;
+ uint32_t pr_fpvalid;
+} QEMU_PACKED arm_elf_prstatus;
+
+QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus) != 148);
+
+/* struct user_vfp from arch/arm/include/asm/user.h */
+struct arm_user_vfp_state {
+ uint64_t vregs[32];
+ uint32_t fpscr;
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state) != 260);
+
+struct arm_note {
+ Elf32_Nhdr hdr;
+ char name[8]; /* align_up(sizeof("LINUX"), 4) */
+ union {
+ struct arm_elf_prstatus prstatus;
+ struct arm_user_vfp_state vfp;
+ };
+} QEMU_PACKED;
+
+#define ARM_NOTE_HEADER_SIZE offsetof(struct arm_note, prstatus)
+#define ARM_PRSTATUS_NOTE_SIZE \
+ (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_elf_prstatus))
+#define ARM_VFP_NOTE_SIZE \
+ (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_user_vfp_state))
+
+static void arm_note_init(struct arm_note *note, DumpState *s,
+ const char *name, Elf32_Word namesz,
+ Elf32_Word type, Elf32_Word descsz)
+{
+ memset(note, 0, sizeof(*note));
+
+ note->hdr.n_namesz = cpu_to_dump32(s, namesz);
+ note->hdr.n_descsz = cpu_to_dump32(s, descsz);
+ note->hdr.n_type = cpu_to_dump32(s, type);
+
+ memcpy(note->name, name, namesz);
+}
+
+static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env,
+ int cpuid, DumpState *s)
+{
+ struct arm_note note;
+ int ret, i;
+
+ arm_note_init(&note, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp));
+
+ for (i = 0; i < 32; ++i) {
+ note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
+ }
+
+ note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env));
+
+ ret = f(&note, ARM_VFP_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque)
+{
+ struct arm_note note;
+ CPUARMState *env = &ARM_CPU(cs)->env;
+ DumpState *s = opaque;
+ int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP);
+
+ arm_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
+
+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, fpvalid);
+
+ for (i = 0; i < 16; ++i) {
+ note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->regs[i]);
+ }
+ note.prstatus.pr_reg.regs[16] = cpu_to_dump32(s, cpsr_read(env));
+
+ ret = f(&note, ARM_PRSTATUS_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ } else if (fpvalid) {
+ return arm_write_elf32_vfp(f, env, cpuid, s);
+ }
+
+ return 0;
+}
+
+int cpu_get_dump_info(ArchDumpInfo *info,
+ const GuestPhysBlockList *guest_phys_blocks)
+{
+ ARMCPU *cpu = ARM_CPU(first_cpu);
+ CPUARMState *env = &cpu->env;
+ GuestPhysBlock *block;
+ hwaddr lowest_addr = ULLONG_MAX;
+
+ /* Take a best guess at the phys_base. If we get it wrong then crash
+ * will need '--machdep phys_offset=<phys-offset>' added to its command
+ * line, which isn't any worse than assuming we can use zero, but being
+ * wrong. This is the same algorithm the crash utility uses when
+ * attempting to guess as it loads non-dumpfile formatted files.
+ */
+ QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
+ if (block->target_start < lowest_addr) {
+ lowest_addr = block->target_start;
+ }
+ }
+
+ if (arm_feature(env, ARM_FEATURE_AARCH64)) {
+ info->d_machine = EM_AARCH64;
+ info->d_class = ELFCLASS64;
+ info->page_size = (1 << 16); /* aarch64 max pagesize */
+ if (lowest_addr != ULLONG_MAX) {
+ info->phys_base = lowest_addr;
+ }
+ } else {
+ info->d_machine = EM_ARM;
+ info->d_class = ELFCLASS32;
+ info->page_size = (1 << 12);
+ if (lowest_addr < UINT_MAX) {
+ info->phys_base = lowest_addr;
+ }
+ }
+
+ /* We assume the relevant endianness is that of EL1; this is right
+ * for kernels, but might give the wrong answer if you're trying to
+ * dump a hypervisor that happens to be running an opposite-endian
+ * kernel.
+ */
+ info->d_endian = (env->cp15.sctlr_el[1] & SCTLR_EE) != 0
+ ? ELFDATA2MSB : ELFDATA2LSB;
+
+ return 0;
+}
+
+ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
+{
+ ARMCPU *cpu = ARM_CPU(first_cpu);
+ CPUARMState *env = &cpu->env;
+ size_t note_size;
+
+ if (class == ELFCLASS64) {
+ note_size = AARCH64_PRSTATUS_NOTE_SIZE;
+ note_size += AARCH64_PRFPREG_NOTE_SIZE;
+ } else {
+ note_size = ARM_PRSTATUS_NOTE_SIZE;
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ note_size += ARM_VFP_NOTE_SIZE;
+ }
+ }
+
+ return note_size * nr_cpus;
+}
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 25fb1ce0f3..5bd9b7bb9f 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -221,6 +221,11 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque);
+int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, void *opaque);
+
/* Callback functions for the generic timer's timers. */
void arm_gt_ptimer_cb(void *opaque);
void arm_gt_vtimer_cb(void *opaque);
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 775e0a46bd..450ef78a3d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1421,6 +1421,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_arm_cpu;
cc->virtio_is_big_endian = arm_cpu_is_big_endian;
+ cc->write_elf64_note = arm_cpu_write_elf64_note;
+ cc->write_elf32_note = arm_cpu_write_elf32_note;
#endif
cc->gdb_num_core_regs = 26;
cc->gdb_core_xml_file = "arm-core.xml";
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 59d5a41b58..faeaaa806a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5996,11 +5996,15 @@ static inline bool regime_using_lpae_format(CPUARMState *env,
return false;
}
-/* Returns true if the translation regime is using LPAE format page tables.
- * Used when raising alignment exceptions, whose FSR changes depending on
- * whether the long or short descriptor format is in use. */
-bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
+/* Returns true if the stage 1 translation regime is using LPAE format page
+ * tables. Used when raising alignment exceptions, whose FSR changes depending
+ * on whether the long or short descriptor format is in use. */
+bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
{
+ if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
+ mmu_idx += ARMMMUIdx_S1NSE0;
+ }
+
return regime_using_lpae_format(env, mmu_idx);
}
diff --git a/target-arm/internals.h b/target-arm/internals.h
index b925aaaa45..d226bbe857 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -441,8 +441,9 @@ struct ARMMMUFaultInfo {
bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx,
uint32_t *fsr, ARMMMUFaultInfo *fi);
-/* Return true if the translation regime is using LPAE format page tables */
-bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
+/* Return true if the stage 1 translation regime is using LPAE format page
+ * tables */
+bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
/* Raise a data fault alignment exception for the specified virtual address */
void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index e42d287d9c..951fc5ae51 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -149,7 +149,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
/* the DFSR for an alignment fault depends on whether we're using
* the LPAE long descriptor format, or the short descriptor format
*/
- if (arm_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
+ if (arm_s1_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
env->exception.fsr = 0x21;
} else {
env->exception.fsr = 0x1;
diff --git a/target-ppc/arch_dump.c b/target-ppc/arch_dump.c
index 5acafc68a4..816dbc2134 100644
--- a/target-ppc/arch_dump.c
+++ b/target-ppc/arch_dump.c
@@ -278,9 +278,3 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
PowerPCCPU *cpu = POWERPC_CPU(cs);
return ppc64_write_all_elf64_notes("CORE", f, cpu, cpuid, opaque);
}
-
-int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
- CPUState *cpu, void *opaque)
-{
- return 0;
-}
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index bc20504b3d..7d5e2b36a9 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -125,8 +125,6 @@ int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
-int ppc64_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
- CPUState *cpu, void *opaque);
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
#ifndef CONFIG_USER_ONLY
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index e88dc7fc7a..4ab2d927b0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9712,7 +9712,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->vmsd = &vmstate_ppc_cpu;
#if defined(TARGET_PPC64)
cc->write_elf64_note = ppc64_cpu_write_elf64_note;
- cc->write_elf64_qemunote = ppc64_cpu_write_elf64_qemunote;
#endif
#endif
cc->cpu_exec_enter = ppc_cpu_exec_enter;
diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c
index dab63eb44f..549a99b357 100644
--- a/target-s390x/arch_dump.c
+++ b/target-s390x/arch_dump.c
@@ -246,9 +246,3 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
return (elf_note_size) * nr_cpus;
}
-
-int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
- CPUState *cpu, void *opaque)
-{
- return 0;
-}
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index 491c1b8769..029a44af24 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -91,8 +91,6 @@ void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
-int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
- CPUState *cpu, void *opaque);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 189a2afc0f..e5a3f65029 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -353,7 +353,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_s390_cpu;
cc->write_elf64_note = s390_cpu_write_elf64_note;
- cc->write_elf64_qemunote = s390_cpu_write_elf64_qemunote;
cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
#endif